Fakultas Ilmu Komputer UI

Commit adc44145 authored by Jahns's avatar Jahns
Browse files

Merge branch 'jahns/forget-and-change-pass' into 'pbi-11-lupa-password'

Jahns/forget and change pass

See merge request !3
parents e398fd65 62304374
Pipeline #77402 passed with stage
in 16 minutes and 19 seconds
......@@ -3,7 +3,7 @@
buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 16
minSdkVersion = 21
compileSdkVersion = 28
targetSdkVersion = 28
}
......
File mode changed from 100755 to 100644
This diff is collapsed.
......@@ -18,10 +18,11 @@
"@types/crypto-js": "^3.1.44",
"@types/react-navigation": "^3.4.0",
"@types/styled-components": "^5.0.0",
"axios": "^0.19.2",
"axios": "^0.21.1",
"crypto-js": "^3.1.9-1",
"fbjs": "^3.0.0",
"react": "16.9.0",
"react-native": "^0.62.1",
"react-native": "^0.64.1",
"react-native-dotenv": "^0.2.0",
"react-native-gesture-handler": "^1.6.0",
"react-native-reanimated": "^1.7.0",
......@@ -41,13 +42,13 @@
"@types/react-test-renderer": "16.9.1",
"@typescript-eslint/eslint-plugin": "^2.12.0",
"@typescript-eslint/parser": "^2.12.0",
"babel-jest": "^25.2.6",
"babel-jest": "^25.5.1",
"babel-plugin-module-resolver": "^4.0.0",
"eslint": "^6.5.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^25.1.0",
"jest": "^25.5.4",
"metro-react-native-babel-preset": "^0.56.0",
"react-test-renderer": "16.9.0",
"react-test-renderer": "^17.0.2",
"typescript": "^3.7.3"
},
"jest": {
......@@ -66,6 +67,9 @@
},
"setupFiles": [
"./node_modules/react-native-gesture-handler/jestSetup.js"
],
"transformIgnorePatterns": [
"node_modules/(?!react-native|react-navigation)/"
]
},
"rnpm": {
......
......@@ -8,6 +8,7 @@ import App from '.';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
jest.useFakeTimers();
it('renders correctly', () => {
renderer.create(<App />);
......
......@@ -28,6 +28,7 @@ import initialCacheState, {
} from 'contexts/AppContext/cache';
import { useMainService } from 'services'
import { Box, Text, Button, Gap } from 'components';
import ForgetPasswordPage from 'scenes/ForgetPasswordPage';
const StyledApp = styled.SafeAreaView`
height: 100%;
......@@ -284,6 +285,7 @@ const App = () => {
}}>
<Stack.Screen name="splash" component={Splash} />
<Stack.Screen name="login" component={LoginPage} />
<Stack.Screen name="forget-password" component={ForgetPasswordPage} />
<Stack.Screen name="home" component={Home} />
<Stack.Screen
name="contact-investigation-form/1"
......
......@@ -163,7 +163,7 @@ exports[`DatePicker tests renders correctly 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......
declare module '*.jpg';
declare module '*.jpeg';
declare module '*.png';
\ No newline at end of file
......@@ -30,6 +30,7 @@ const testProps = {
setCache: jest.fn()
};
jest.mock('axios');
jest.useFakeTimers();
const mockedAxios = axios as jest.Mocked<typeof axios>;
describe('Contact investigation form step 1', () => {
......
......@@ -42,6 +42,7 @@ const testProps = {
}
jest.mock('axios');
jest.useFakeTimers();
const mockedAxios = axios as jest.Mocked<typeof axios>;
mockedAxios.request.mockImplementation(
() => new Promise(resolve => {
......
import 'react-native';
import axios from 'axios';
import React from 'react';
import { useMainService, LocalStorage } from 'services';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import ReactTestRenderer, { act } from 'react-test-renderer';
import ForgetPasswordPage from '.';
import { AppContext } from 'contexts';
const Stack = createStackNavigator();
const testProps = {
services: {
main: useMainService('dummyToken'),
},
alert: {
illustration: "",
message: "",
},
setAlert: (alert: string) => testProps.alert = alert,
shouldLoading: false,
setShouldLoading: (shouldLoading: boolean) => testProps.shouldLoading = shouldLoading,
cache: {},
}
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
it('renders correctly', () => {
const instance = ReactTestRenderer.create(
<NavigationContainer>
<Stack.Navigator
screenOptions={{
header: () => <></>,
}}>
<Stack.Screen name="forget-password" component={ForgetPasswordPage} />
</Stack.Navigator>
</NavigationContainer>,
);
expect(instance.toJSON()).toMatchSnapshot();
});
it('insert email correctly', async () => {
LocalStorage.setSecretKey("sssttt");
const instance = ReactTestRenderer.create(
<AppContext.Provider value={testProps}>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
header: () => <></>,
}}>
<Stack.Screen name="forget-password" component={ForgetPasswordPage} />
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>,
);
expect(instance.toJSON()).toMatchSnapshot();
const emailField = instance.root.find(elem => elem.props.id === "email");
act(() => {
if (emailField) {
emailField.props.updateValue("email@email.com");
}
})
expect(instance).toBeTruthy();
mockedAxios.request.mockImplementationOnce(
() => new Promise(resolve => {
resolve({
status: 200,
data: [
"Password successfully changed"
],
});
})
);
const submit = instance.root.find(elem => elem.props.id === "submit");
await act(async () => {
submit.props.onPress();
})
expect(testProps.alert.message).toBe("Password berhasil diubah, silakan cek email anda.");
});
it('insert invalid email', async () => {
LocalStorage.setSecretKey("sssttt");
const instance = ReactTestRenderer.create(
<AppContext.Provider value={testProps}>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
header: () => <></>,
}}>
<Stack.Screen name="forget-password" component={ForgetPasswordPage} />
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>,
);
expect(instance.toJSON()).toMatchSnapshot();
const emailField = instance.root.find(elem => elem.props.id === "email");
act(() => {
if (emailField) {
emailField.props.updateValue("beneranemail.com");
}
})
expect(instance).toBeTruthy();
const submit = instance.root.find(elem => elem.props.id === "submit");
await act(async () => {
submit.props.onPress();
})
expect(emailField.props.information).toBe("Masukkan email yang valid.");
});
it('insert email that does\'t exists in database', async () => {
LocalStorage.setSecretKey("sssttt");
const instance = ReactTestRenderer.create(
<AppContext.Provider value={testProps}>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
header: () => <></>,
}}>
<Stack.Screen name="forget-password" component={ForgetPasswordPage} />
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>,
);
expect(instance.toJSON()).toMatchSnapshot();
const emailField = instance.root.find(elem => elem.props.id === "email");
act(() => {
if (emailField) {
emailField.props.updateValue("email@email.com");
}
})
expect(instance).toBeTruthy();
mockedAxios.request.mockImplementationOnce(
() => new Promise(resolve => {
resolve({
status: 400,
data: {
"error": "Account matching query does not exist."
},
});
})
);
const submit = instance.root.find(elem => elem.props.id === "submit");
await act(async () => {
submit.props.onPress();
})
expect(testProps.alert.message).toBe("Terjadi kesalahan, periksa kembali email anda.");
});
\ No newline at end of file
import { Box, Button, Cloud, Field, Gap, Text } from "components";
import styled from 'styled-components/native';
import React, { useContext, useState } from "react";
import { Image } from "react-native";
import WaveBackground from 'assets/arts/background-wave.png';
import WonderingIllustration from 'assets/illustrations/wondering.png';
import DoctorTeamIllustration from 'assets/illustrations/doctor-team.png';
import { useFormState } from "helpers";
import { AppContext } from "contexts";
enum ForgetPasswordResponse {
Success = 'Password berhasil diubah, silakan cek email anda.',
BadRequest = 'Terjadi kesalahan, periksa kembali email anda.',
UnknownServerError = 'Terjadi kesalahan pada server.',
NoInternetConn = 'Cek Konektivitas Internet',
}
const ForgetPasswordPage = () => {
const [isFirstTime, setIsFirstTime] = useState(true);
const { services, setAlert, shouldLoading, setShouldLoading } = useContext(AppContext);
const [form, setField] = useFormState({
email: {
type: 'EMAIL'
}
})
return (
<Box
axis={Box.Axis.Vertical}
height="100%"
width="100%"
background="transparent"
>
<Cloud
top="0px"
left="0px"
height="100%"
width="100%"
>
<Image
style={{
height: "100%",
width: "100%",
}}
source={WaveBackground}
/>
</Cloud>
<Container>
<FieldControl>
<Text isBold={true} fontSize='48px'>Lupa Password</Text>
</FieldControl>
<Gap gap={24} axis={Gap.Axis.Vertical} />
<FieldControl>
<Field
id="email"
name="Email"
placeholder="Masukkan email Anda."
information={
isFirstTime || form.fields.email.isValid
? ''
: 'Masukkan email yang valid.'
}
updateValue={val => setField('email', val)}>
</Field>
</FieldControl>
</Container>
<Action>
<Box>
<Button
id="submit"
type={Button.Type.Filled}
clickable={!shouldLoading}
onPress={async () => {
if (isFirstTime) {
setIsFirstTime(false);
}
if (form.isValid) {
setShouldLoading(true)
const forgetPassRes = await services.main.forgetPassword({
email: form.fields.email.value,
})
setShouldLoading(false)
if (forgetPassRes === undefined) {
setAlert({
illustration: WonderingIllustration,
message: ForgetPasswordResponse.NoInternetConn,
})
} else {
if (forgetPassRes.status === 200) {
setAlert({
illustration: DoctorTeamIllustration,
message: ForgetPasswordResponse.Success,
})
} else if (forgetPassRes.status === 400) {
setAlert({
illustration: WonderingIllustration,
message: ForgetPasswordResponse.BadRequest,
})
} else {
setAlert({
illustration: WonderingIllustration,
message: ForgetPasswordResponse.UnknownServerError,
})
}
}
}
}}
>Kirim Email Verifikasi</Button>
</Box>
</Action>
</Box>
)
}
const Container = styled.View`
width: 100%;
height: 55%;
padding: 0 32px;
justify-content: flex-end;
`;
const FieldControl = styled.View`
margin-bottom: 5%;
`;
const Action = styled.View`
position: relative;
display: flex;
flex-flow: column nowrap;
width: 100%;
padding: 0 32px;
flex-grow: 1;
`;
export default ForgetPasswordPage;
\ No newline at end of file
......@@ -11,6 +11,7 @@ import Log from '.';
import ReactTestRenderer, {act} from 'react-test-renderer';
jest.mock('axios');
jest.useFakeTimers();
const Stack = createStackNavigator();
const testProps = {
services: {
......
......@@ -20,6 +20,7 @@ const testProps = {
},
cache: {},
};
jest.useFakeTimers();
it('renders correctly', () => {
const instance = ReactTestRenderer.create(
......
import React, {useContext, useState} from 'react';
import {AppContext} from 'contexts';
import React, { useContext, useState } from 'react';
import { AppContext } from 'contexts';
import styled from 'styled-components/native';
import {Image} from 'react-native';
import { Image } from 'react-native';
import {Box, Button, Text, Field, Cloud, Gap} from 'components';
import {useFormState} from 'helpers';
import {LocalStorage} from 'services';
import {useNavigation} from '@react-navigation/native';
import { Box, Button, Text, Field, Cloud, Gap } from 'components';
import { useFormState } from 'helpers';
import { LocalStorage } from 'services';
import { useNavigation } from '@react-navigation/native';
import WaveBackground from 'assets/arts/background-wave.png';
import WonderingIllustration from 'assets/illustrations/wondering.png';
......@@ -20,7 +20,7 @@ enum LoginResponse {
const LoginPage = () => {
const navigation = useNavigation();
const [isFirstTime, setIsFirstTime] = useState(true);
const {setToken, services, setAlert, shouldLoading, setShouldLoading} = useContext(AppContext);
const { setToken, services, setAlert, shouldLoading, setShouldLoading } = useContext(AppContext);
const [form, setField] = useFormState({
username: {
type: 'text',
......@@ -96,15 +96,15 @@ const LoginPage = () => {
setIsFirstTime(false);
}
if (form.isValid) {
setShouldLoading(true)
const loginRes = await services.main.login({
username: form.fields.username.value,
password: form.fields.password.value,
});
setShouldLoading(false)
if (loginRes === undefined) {
......@@ -133,6 +133,16 @@ const LoginPage = () => {
Masuk
</Button>
</Box>
<Gap axis={Gap.Axis.Vertical} gap={14}></Gap>
<Box>
<Button
id="forgetpass"
clickable={!shouldLoading}
type={Button.Type.Outline}
onPress={() => navigation.navigate('forget-password')}>
Lupa Password
</Button>
</Box>
<Line />
<Box>
<Button
......
......@@ -909,7 +909,7 @@ exports[`can press previous button 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -2365,7 +2365,7 @@ exports[`renders correctly 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -3821,7 +3821,7 @@ exports[`renders form with correct fields 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -5277,7 +5277,7 @@ exports[`submit data succesfully 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......
......@@ -663,7 +663,7 @@ exports[`can press previous button 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -881,7 +881,7 @@ exports[`can press previous button 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -2070,7 +2070,7 @@ exports[`renders correctly 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -2288,7 +2288,7 @@ exports[`renders correctly 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -3477,7 +3477,7 @@ exports[`renders form with correct fields 1`] = `
]
}
>
6/4/2020
17/5/2021
</Text>
</View>
<View
......@@ -3695,7 +3695,7 @@ exports[`renders form with correct fields 1`] = `
]