diff --git a/README.md b/README.md
index c59df34..5640ada 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
-# testing-app
+# Testing App
+
Demo for react native testing library
+
+Please don't judge me for coding practices using this code base. I am better than this; might be.
diff --git a/app/screens/LoginScreen/EmailPasswordForm/tests/index.test.tsx b/app/screens/LoginScreen/EmailPasswordForm/tests/index.test.tsx
index 9406619..bcb9020 100644
--- a/app/screens/LoginScreen/EmailPasswordForm/tests/index.test.tsx
+++ b/app/screens/LoginScreen/EmailPasswordForm/tests/index.test.tsx
@@ -12,35 +12,53 @@ import {
describe('', () => {
it('Expect to show password required', async () => {
+ // Dummy email value
const email = 'email@email.com';
+ // Grabbing our parent component
const { getByTestId } = render(
null}
onForgotPasswordPress={() => null}
/>,
);
+
+ // Grabbing our input & button components
const emailInput = getByTestId(TEST_ID_EMAIL_INPUT);
const button = getByTestId(TEST_ID_SUBMIT_BUTTON);
+ /**
+ * We are changing text in inputs here; that requires a state change
+ * Since setState is async in react we have to execute this tests
+ * in async way. RNTL give waitFor API for this.
+ */
await waitFor(() => {
fireEvent.changeText(emailInput, email);
+ // Just making sure that value is updated in input
expect(emailInput.props.value).toBe(email);
fireEvent.press(button);
+
+ // We have passwordInput_ERROR component that only renders when error is there
expect(getByTestId('passwordInput_ERROR')).toBeDefined();
});
});
it('Expect to call handle submit with email & password', async () => {
+ // Dummy inputs
const email = 'email@email.com';
const password = 'qwerty1234';
+
+ // Expected output
const expectedOutput = {
email,
password,
};
let output = {};
+
+ // Mock onSubmit method that we are expecting will be executed
const onSubmit = jest.fn((data) => (output = data));
+ // Rendering our component & grabbing required nodes.
const { getByTestId } = render(
', () => {
const emailInput = getByTestId(TEST_ID_EMAIL_INPUT);
const passwordInput = getByTestId(TEST_ID_PASSWORD_INPUT);
+ // Testing behaviors
await waitFor(() => {
fireEvent.changeText(emailInput, email);
expect(emailInput.props.value).toBe(email);
@@ -58,6 +77,10 @@ describe('', () => {
fireEvent.changeText(passwordInput, password);
expect(passwordInput.props.value).toBe(password);
+ /**
+ * Here we are asserting that onSubmit is not just called
+ * but it is called with expected output.
+ */
fireEvent.press(button);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(output).toEqual(expectedOutput);
diff --git a/app/screens/LoginScreen/tests/index.test.tsx b/app/screens/LoginScreen/tests/index.test.tsx
index 6b535b4..6222501 100644
--- a/app/screens/LoginScreen/tests/index.test.tsx
+++ b/app/screens/LoginScreen/tests/index.test.tsx
@@ -20,28 +20,32 @@ import {
} from '../constants';
describe('Login Screen', () => {
- afterEach(() => {
- fetchMock.reset();
- fetchMock.restore();
- });
-
- it('Expect to save token in AsyncStorage & navigate to home screen on successful login', async () => {
+ // Setting up fetch mock before execution of any test
+ beforeAll(() => {
const endPoint = `${API_URL}${LOGIN_ENDPOINT}`;
fetchMock.post(endPoint, {
status: 200,
body: JSON.stringify(LOGIN_EXPECTED_RESPONSE),
});
+ });
+ // Testing complete flow
+ it('Expect to save token in AsyncStorage & navigate to home screen on successful login', async () => {
+ // Mocking navigate method
const navigate = jest.fn();
+ const endPoint = `${API_URL}${LOGIN_ENDPOINT}`;
+ // Dummy data to supply to form
const email = 'email@email.com';
const password = 'password';
+ // Getting element
const screen = render();
const emailInput = screen.getByTestId(TEST_ID_EMAIL_INPUT);
const passwordInput = screen.getByTestId(TEST_ID_PASSWORD_INPUT);
const button = screen.getByTestId(TEST_ID_SUBMIT_BUTTON);
+ // Formik requires all state changes to be wrapper in async method.
await waitFor(() => {
fireEvent.changeText(emailInput, email);
fireEvent.changeText(passwordInput, password);
@@ -51,16 +55,27 @@ describe('Login Screen', () => {
fireEvent.press(button);
});
+ // Asserting that API has been called
expect(fetchMock).toHaveBeenCalledWith(endPoint, {
body: `{"email":"${email}","password":"${password}"}`,
headers: { 'Content-Type': 'application/json' },
method: 'POST',
});
+
+ // Asserting screen navigation
expect(navigate).toHaveBeenCalledTimes(1);
expect(navigate).toHaveBeenCalledWith(HOME, {});
+
+ // Asserting token storage in local storage.
expect(AsyncStorage.setItem).toHaveBeenCalledWith(
AUTH_TOKEN_KEY,
LOGIN_EXPECTED_RESPONSE.data.tokens.jwtToken,
);
});
+
+ // Cleaning up fetch mock
+ afterEach(() => {
+ fetchMock.reset();
+ fetchMock.restore();
+ });
});
diff --git a/app/theme/Button/index.tsx b/app/theme/Button/index.tsx
index bac0ddd..460f407 100644
--- a/app/theme/Button/index.tsx
+++ b/app/theme/Button/index.tsx
@@ -7,7 +7,7 @@ import React, { useEffect, useRef } from 'react';
import { Animated } from 'react-native';
import Text from 'theme/Text';
-import TouchFeedback from 'theme/TouchFeedback';
+import TouchFeedback, { TouchFeedbackProps } from 'theme/TouchFeedback';
import style from './style';
@@ -22,7 +22,7 @@ const typeForeground = {
tertiary: style.tertiaryForeground,
};
-interface ButtonProps {
+interface ButtonProps extends TouchFeedbackProps {
onPress: (...args: any[]) => any;
label: string | React.ReactNode;
mini?: boolean;
diff --git a/app/theme/Button/tests/index.test.tsx b/app/theme/Button/tests/index.test.tsx
index c805f6d..ff3f443 100644
--- a/app/theme/Button/tests/index.test.tsx
+++ b/app/theme/Button/tests/index.test.tsx
@@ -5,15 +5,31 @@ import { fireEvent } from '@testing-library/react-native';
import { render } from 'utils/testWrapper';
import Button from '../index';
+// Describing a test suite
describe('', () => {
+ // Describing our test
it('Calls onPress', async () => {
+ // Mocking onPress method so we can check if its called or not
const onPress = jest.fn();
+
+ // test id to be applied on our button component
const testID = 'button';
+
+ // Rendering Button component using react-native-test-renderer.
const { getByTestId } = await render(
,
);
+
+ // Grabbing our button component to perform actions on it.
const button = getByTestId(testID);
+
+ /**
+ * RNTL gives us API to fire events on node
+ * Here we are firing on press event
+ */
fireEvent.press(button);
+
+ // Asserting if given mock method is called or not.
expect(onPress).toHaveBeenCalledTimes(1);
});
});
diff --git a/app/theme/TouchFeedback/index.tsx b/app/theme/TouchFeedback/index.tsx
index be1c91a..8c3a598 100644
--- a/app/theme/TouchFeedback/index.tsx
+++ b/app/theme/TouchFeedback/index.tsx
@@ -13,13 +13,13 @@ const AnimatedNative = Animated.createAnimatedComponent(
);
const RIPPLE = Platform.OS === 'android' && Platform.Version >= 21;
-type TouchFeedbackProps = {
+export interface TouchFeedbackProps {
style?: number | any[];
ripple?: boolean;
animated?: boolean;
onPress: (...args: any[]) => any;
testID?: string;
-};
+}
const TouchFeedback: React.SFC = ({
children,
diff --git a/app/utils/delay.ts b/app/utils/delay.ts
deleted file mode 100644
index c4e4209..0000000
--- a/app/utils/delay.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export default function delay(time: number): Promise {
- return new Promise(function (resolve) {
- setTimeout(() => resolve(), time);
- });
-}
diff --git a/jest.report.html b/jest.report.html
index cf09f90..8bce4ee 100644
--- a/jest.report.html
+++ b/jest.report.html
@@ -1,5 +1,5 @@
Report