From dcca881f1bae7234427d7e0f72886dd4c61eb1c3 Mon Sep 17 00:00:00 2001
From: Liam Stevens <8955671+liamstevens111@users.noreply.github.com>
Date: Wed, 22 Feb 2023 12:05:36 +0700
Subject: [PATCH] [#21] Use nock for mocking API response WIP
---
package-lock.json | 43 +++++++++
package.json | 1 +
src/routes/index.tsx | 2 +-
src/screens/Login/index.test.tsx | 91 +++++++++++++++++++
.../{Home/login.tsx => Login/index.tsx} | 4 +-
5 files changed, 138 insertions(+), 3 deletions(-)
create mode 100644 src/screens/Login/index.test.tsx
rename src/screens/{Home/login.tsx => Login/index.tsx} (96%)
diff --git a/package-lock.json b/package-lock.json
index 3ed68f9..62bc580 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,6 +38,7 @@
"danger": "10.9.0",
"danger-plugin-istanbul-coverage": "1.6.2",
"eslint": "8.11.0",
+ "nock": "^13.3.0",
"postcss": "8.4.21",
"postcss-import": "14.1.0",
"prettier": "2.6.0",
@@ -16753,6 +16754,21 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/nock": {
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz",
+ "integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.0",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.17.21",
+ "propagate": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13"
+ }
+ },
"node_modules/node-cleanup": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
@@ -19339,6 +19355,15 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/propagate": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
+ "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -36708,6 +36733,18 @@
"tslib": "^2.0.3"
}
},
+ "nock": {
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz",
+ "integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "json-stringify-safe": "^5.0.1",
+ "lodash": "^4.17.21",
+ "propagate": "^2.0.0"
+ }
+ },
"node-cleanup": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
@@ -38374,6 +38411,12 @@
}
}
},
+ "propagate": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
+ "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
+ "dev": true
+ },
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
diff --git a/package.json b/package.json
index d32cd1c..5b9e18a 100644
--- a/package.json
+++ b/package.json
@@ -65,6 +65,7 @@
"danger": "10.9.0",
"danger-plugin-istanbul-coverage": "1.6.2",
"eslint": "8.11.0",
+ "nock": "13.3.0",
"postcss": "8.4.21",
"postcss-import": "14.1.0",
"prettier": "2.6.0",
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index ec00d40..2d93c7f 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import { RouteObject } from 'react-router-dom';
import HomeScreen from 'screens/Home';
-import LoginScreen from 'screens/Home/login';
+import LoginScreen from 'screens/Login';
const routes: RouteObject[] = [
{
diff --git a/src/screens/Login/index.test.tsx b/src/screens/Login/index.test.tsx
new file mode 100644
index 0000000..8692fd5
--- /dev/null
+++ b/src/screens/Login/index.test.tsx
@@ -0,0 +1,91 @@
+import { BrowserRouter } from 'react-router-dom';
+
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import nock from 'nock';
+
+import LoginScreen from '.';
+
+afterAll(() => {
+ nock.cleanAll();
+ nock.restore();
+});
+
+describe('LoginScreen', () => {
+ test('submit an an empty email and password and receive errors', async () => {
+ render(, { wrapper: BrowserRouter });
+
+ const submitButton = screen.getByRole('button', { name: 'login.sign-in' });
+
+ await userEvent.click(submitButton);
+
+ expect(screen.getByText('login.invalid-email')).toBeInTheDocument();
+ expect(screen.getByText('login.invalid-password')).toBeInTheDocument();
+ });
+
+ test('submit incorrect details', async () => {
+ render(, { wrapper: BrowserRouter });
+
+ const formData = {
+ email: 'testemail@gmail.com',
+ password: 'password123',
+ };
+
+ nock(`${process.env.REACT_APP_API_ENDPOINT}`)
+ .defaultReplyHeaders({
+ 'access-control-allow-origin': '*',
+ 'access-control-allow-credentials': 'true',
+ })
+ .post('/oauth/token', {
+ email: formData.email,
+ password: formData.password,
+ grant_type: 'password',
+ client_id: process.env.REACT_APP_API_CLIENT_ID,
+ client_secret: process.env.REACT_APP_API_CLIENT_SECRET,
+ })
+ .reply(400, {
+ errors: [
+ {
+ detail: 'Your email or password is incorrect. Please try again.',
+ code: 'invalid_email_or_password',
+ },
+ ],
+ });
+
+ const emailField = screen.getByLabelText('login.email');
+ const passwordField = screen.getByLabelText('login.password');
+ const submitButton = screen.getByRole('button', { name: 'login.sign-in' });
+
+ await userEvent.type(emailField, formData.email);
+ await userEvent.type(passwordField, formData.password);
+
+ await userEvent.click(submitButton);
+ await waitFor(() => {
+ expect(screen.getByText('Your email or password is incorrect. Please try again.')).toBeInTheDocument();
+ });
+ });
+
+ // test('Allows form submission of email and password', async () => {
+ // const requestData = {
+ // email: 'testemail@gmail.com',
+ // password: 'password123',
+ // };
+
+ // render(, { wrapper: BrowserRouter });
+
+ // const emailField = screen.getByLabelText('login.email');
+ // const passwordField = screen.getByLabelText('login.password');
+ // const submitButton = screen.getByRole('button', { name: 'login.sign-in' });
+
+ // await userEvent.type(emailField, 'testemail@gmail.com');
+ // await userEvent.type(passwordField, 'password123');
+
+ // const requestSpy = jest.spyOn(axios, 'request').mockImplementation(() => Promise.resolve({}));
+
+ // await userEvent.click(submitButton);
+
+ // expect(axios.request).toHaveBeenCalledWith(requestData);
+
+ // requestSpy.mockRestore();
+ // });
+});
diff --git a/src/screens/Home/login.tsx b/src/screens/Login/index.tsx
similarity index 96%
rename from src/screens/Home/login.tsx
rename to src/screens/Login/index.tsx
index 8a7dc73..1b1be89 100644
--- a/src/screens/Home/login.tsx
+++ b/src/screens/Login/index.tsx
@@ -41,10 +41,10 @@ function LoginScreen() {
setToken({ accessToken: accessToken, refreshToken: refreshToken });
navigate('/');
} catch (error) {
- let errorMessage = '';
+ let errorMessage = 'There was a problem receiving a response from the server';
if (error instanceof Error) {
- errorMessage = (error as AxiosError).response?.data?.errors[0]?.detail || error.message || 'Internal error';
+ errorMessage = (error as AxiosError).response?.data?.errors[0]?.detail || error.cause || errorMessage;
}
setErrors([errorMessage]);
} finally {