From ef3f2a802f46ec9d64eefc7ca48aa4d53daea263 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 25 Jan 2021 15:15:02 +0100
Subject: [PATCH 01/18] Dashboard page: added first unit test for create resume
interaction
---
src/components/dashboard/CreateResume.js | 5 +++
src/pages/app/__tests__/dashboard.test.js | 41 +++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/src/components/dashboard/CreateResume.js b/src/components/dashboard/CreateResume.js
index 0f15b601b..a1ec0b4ef 100644
--- a/src/components/dashboard/CreateResume.js
+++ b/src/components/dashboard/CreateResume.js
@@ -5,6 +5,8 @@ import ModalContext from '../../contexts/ModalContext';
import { handleKeyUp } from '../../utils';
import styles from './CreateResume.module.css';
+const createResumeButtonDataTestId = 'create-resume-button';
+
const CreateResume = () => {
const { t } = useTranslation();
const { emitter, events } = useContext(ModalContext);
@@ -17,6 +19,7 @@ const CreateResume = () => {
{
};
export default memo(CreateResume);
+
+export { createResumeButtonDataTestId };
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index eede7d67a..331f940b5 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -14,6 +14,7 @@ import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import '../../../i18n/index';
import '../../../utils/dayjs';
import { dataTestId as loadingScreenTestId } from '../../../components/router/LoadingScreen';
+import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
import { SettingsProvider } from '../../../contexts/SettingsContext';
import { ModalProvider } from '../../../contexts/ModalContext';
@@ -101,6 +102,46 @@ describe('Dashboard', () => {
});
});
+ describe('when resume is created', () => {
+ beforeEach(async () => {
+ await setup();
+
+ const dashboardCreateResumeButton = await screen.findByTestId(
+ createResumeButtonDataTestId,
+ );
+ fireEvent.click(dashboardCreateResumeButton);
+ });
+
+ describe('with name shorter than 5 characters', () => {
+ it('displays validation error and notification', async () => {
+ const nameTextBox = screen.getByRole('textbox', { name: /name/i });
+ fireEvent.change(nameTextBox, { target: { value: 'CV 1' } });
+
+ fireEvent.focusOut(nameTextBox);
+
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Please enter at least 5 characters/i),
+ ).toBeInTheDocument(),
+ );
+
+ const modalCreateResumeButton = screen.getByRole('button', {
+ name: /create resume/i,
+ });
+ fireEvent.click(modalCreateResumeButton);
+
+ const notification = await screen.findByRole('alert');
+ expect(
+ getByText(
+ notification,
+ /You might need to fill up all the required fields/i,
+ ),
+ ).toBeInTheDocument();
+ fireEvent.click(notification);
+ });
+ });
+ });
+
describe('when resume is deleted', () => {
let mockDatabaseRemoveFunction = null;
let resumeToDelete = null;
From 9d486c11cc287575b8bba2c23846b8084e5d09aa Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 25 Jan 2021 16:44:08 +0100
Subject: [PATCH 02/18] Dashboard page: added unit test related to create
resume interaction
---
jest.setup.js | 3 ++
package-lock.json | 10 ++++++
package.json | 1 +
src/pages/app/__tests__/dashboard.test.js | 44 ++++++++++++++++++++++-
4 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/jest.setup.js b/jest.setup.js
index 666127af3..91550372b 100644
--- a/jest.setup.js
+++ b/jest.setup.js
@@ -1 +1,4 @@
import '@testing-library/jest-dom/extend-expect';
+import fetchMock from 'jest-fetch-mock';
+
+fetchMock.enableMocks();
diff --git a/package-lock.json b/package-lock.json
index 480ac2e88..5bc6c4b15 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16432,6 +16432,16 @@
}
}
},
+ "jest-fetch-mock": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz",
+ "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==",
+ "dev": true,
+ "requires": {
+ "cross-fetch": "^3.0.4",
+ "promise-polyfill": "^8.1.3"
+ }
+ },
"jest-get-type": {
"version": "25.2.6",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz",
diff --git a/package.json b/package.json
index bfc9d28c8..920f33f38 100644
--- a/package.json
+++ b/package.json
@@ -78,6 +78,7 @@
"gatsby-plugin-eslint": "^2.0.8",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
+ "jest-fetch-mock": "^3.0.3",
"prettier": "2.2.1",
"stylelint": "^13.9.0",
"stylelint-config-standard": "^20.0.0",
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index 331f940b5..d5eba5098 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -103,18 +103,32 @@ describe('Dashboard', () => {
});
describe('when resume is created', () => {
+ let nameTextBox = null;
+
+ const waitForModalToHaveBeenClosed = async () => {
+ await waitFor(() =>
+ screen.queryByRole('textbox', { name: /name/i })
+ ? Promise.reject()
+ : Promise.resolve(),
+ );
+ };
+
beforeEach(async () => {
await setup();
+ fetch.resetMocks();
+ fetch.mockReturnValueOnce({ url: 'https://test-url-123456789.com' });
+
const dashboardCreateResumeButton = await screen.findByTestId(
createResumeButtonDataTestId,
);
fireEvent.click(dashboardCreateResumeButton);
+
+ nameTextBox = screen.getByRole('textbox', { name: /name/i });
});
describe('with name shorter than 5 characters', () => {
it('displays validation error and notification', async () => {
- const nameTextBox = screen.getByRole('textbox', { name: /name/i });
fireEvent.change(nameTextBox, { target: { value: 'CV 1' } });
fireEvent.focusOut(nameTextBox);
@@ -140,6 +154,34 @@ describe('Dashboard', () => {
fireEvent.click(notification);
});
});
+
+ describe('with valid name', () => {
+ it('renders loading message', async () => {
+ fireEvent.change(nameTextBox, {
+ target: { value: 'Resume for SW development roles' },
+ });
+
+ const modalCreateResumeButton = screen.getByRole('button', {
+ name: /create resume/i,
+ });
+ fireEvent.click(modalCreateResumeButton);
+
+ expect(
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeInTheDocument();
+ await waitFor(() =>
+ expect(
+ screen.queryByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeNull(),
+ );
+
+ await waitForModalToHaveBeenClosed();
+ });
+ });
});
describe('when resume is deleted', () => {
From 87fee2348031f3ed061833508eccfdb3b01c38f9 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 25 Jan 2021 17:30:05 +0100
Subject: [PATCH 03/18] Dashboard page: added unit test related to create
resume interaction
---
src/pages/app/__tests__/dashboard.test.js | 28 +++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index d5eba5098..5e5e9ce3c 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -105,7 +105,7 @@ describe('Dashboard', () => {
describe('when resume is created', () => {
let nameTextBox = null;
- const waitForModalToHaveBeenClosed = async () => {
+ const waitForModalWindowToHaveBeenClosed = async () => {
await waitFor(() =>
screen.queryByRole('textbox', { name: /name/i })
? Promise.reject()
@@ -156,16 +156,20 @@ describe('Dashboard', () => {
});
describe('with valid name', () => {
- it('renders loading message', async () => {
+ const resumeName = 'Resume for SW development roles';
+
+ beforeEach(() => {
fireEvent.change(nameTextBox, {
- target: { value: 'Resume for SW development roles' },
+ target: { value: resumeName },
});
const modalCreateResumeButton = screen.getByRole('button', {
name: /create resume/i,
});
fireEvent.click(modalCreateResumeButton);
+ });
+ it('renders loading message', async () => {
expect(
screen.getByRole('button', {
name: /loading/i,
@@ -179,7 +183,23 @@ describe('Dashboard', () => {
).toBeNull(),
);
- await waitForModalToHaveBeenClosed();
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForResumeToBeRenderedInPreview({ name: resumeName });
+ });
+
+ it('closes modal window', async () => {
+ await waitFor(() =>
+ expect(screen.queryByRole('textbox', { name: /name/i })).toBeNull(),
+ );
+
+ await waitForResumeToBeRenderedInPreview({ name: resumeName });
+ });
+
+ // eslint-disable-next-line jest/expect-expect
+ it('renders created resume in preview', async () => {
+ await waitForModalWindowToHaveBeenClosed();
+
+ await expectResumeToBeRenderedInPreview({ name: resumeName });
});
});
});
From b196ca1bf546b9d263b2a65d66aca15d383fb317 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 25 Jan 2021 17:54:36 +0100
Subject: [PATCH 04/18] Dashboard page: added unit test related to create
resume interaction
---
src/pages/app/__tests__/dashboard.test.js | 26 +++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index 5e5e9ce3c..8a6974032 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -157,8 +157,11 @@ describe('Dashboard', () => {
describe('with valid name', () => {
const resumeName = 'Resume for SW development roles';
+ let now = 0;
beforeEach(() => {
+ now = new Date().getTime();
+
fireEvent.change(nameTextBox, {
target: { value: resumeName },
});
@@ -201,6 +204,29 @@ describe('Dashboard', () => {
await expectResumeToBeRenderedInPreview({ name: resumeName });
});
+
+ it('adds resume in initial state to database', async () => {
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForResumeToBeRenderedInPreview({ name: resumeName });
+
+ const actualUserResumes = (
+ await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(user.uid)
+ .once('value')
+ ).val();
+ expect(Object.values(actualUserResumes)).toHaveLength(3);
+
+ const actualUserResumesFiltered = Object.values(
+ actualUserResumes,
+ ).filter((resume) => resume.name === resumeName);
+ expect(actualUserResumesFiltered).toHaveLength(1);
+ const createdResume = actualUserResumesFiltered[0];
+ expect(createdResume.createdAt).toBeTruthy();
+ expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
+ expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
+ });
});
});
From e27bedcf889aecf06969832708d4dfc07388951b Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 26 Jan 2021 13:19:49 +0100
Subject: [PATCH 05/18] Dashboard page: unit tests refactoring
---
__mocks__/gatsby-plugin-firebase/auth/auth.js | 2 +-
.../database/reference.js | 8 +---
src/pages/app/__tests__/dashboard.test.js | 44 +++++++++++++------
3 files changed, 32 insertions(+), 22 deletions(-)
diff --git a/__mocks__/gatsby-plugin-firebase/auth/auth.js b/__mocks__/gatsby-plugin-firebase/auth/auth.js
index 853bb1334..b2fd1eb61 100644
--- a/__mocks__/gatsby-plugin-firebase/auth/auth.js
+++ b/__mocks__/gatsby-plugin-firebase/auth/auth.js
@@ -50,7 +50,7 @@ class Auth {
this.onAuthStateChangedObservers.forEach((observer) => observer(user));
- return Promise.resolve(user);
+ return user;
}
}
diff --git a/__mocks__/gatsby-plugin-firebase/database/reference.js b/__mocks__/gatsby-plugin-firebase/database/reference.js
index 08e345fdb..aca79397d 100644
--- a/__mocks__/gatsby-plugin-firebase/database/reference.js
+++ b/__mocks__/gatsby-plugin-firebase/database/reference.js
@@ -185,7 +185,7 @@ class Reference {
await delay(DatabaseConstants.defaultDelayInMilliseconds);
- return Promise.resolve(this._dataSnapshot);
+ return this._dataSnapshot;
}
orderByChild(path) {
@@ -197,24 +197,18 @@ class Reference {
await delay(DatabaseConstants.defaultDelayInMilliseconds);
this._handleDataUpdate(value);
-
- return Promise.resolve();
}
async remove() {
await delay(DatabaseConstants.defaultDelayInMilliseconds);
this._handleDataUpdate(null);
-
- return Promise.resolve();
}
async set(value) {
await delay(DatabaseConstants.defaultDelayInMilliseconds);
this._handleDataUpdate(value);
-
- return Promise.resolve();
}
}
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index 8a6974032..b5efa2c49 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -29,13 +29,13 @@ describe('Dashboard', () => {
let userResumes = null;
const user = DatabaseConstants.user1;
- const waitForResumeToBeRenderedInPreview = async (resume) => {
- await screen.findByText(resume.name);
+ const waitForResumeToBeRenderedInPreview = async (resumeName) => {
+ await screen.findByText(resumeName);
};
- const expectResumeToBeRenderedInPreview = async (resume) => {
+ const expectResumeToBeRenderedInPreview = async (resumeName) => {
await waitFor(() => {
- expect(screen.getByText(resume.name)).toBeInTheDocument();
+ expect(screen.getByText(resumeName)).toBeInTheDocument();
});
};
@@ -92,13 +92,22 @@ describe('Dashboard', () => {
await waitFor(() => {
expect(screen.getByText(/create resume/i)).toBeInTheDocument();
});
+ await waitFor(() => {
+ expect(
+ screen.getByTestId(createResumeButtonDataTestId),
+ ).toBeInTheDocument();
+ });
});
it('preview of user resumes', async () => {
expect(Object.keys(userResumes)).toHaveLength(2);
- await expectResumeToBeRenderedInPreview(Object.values(userResumes)[0]);
- await expectResumeToBeRenderedInPreview(Object.values(userResumes)[1]);
+ await expectResumeToBeRenderedInPreview(
+ Object.values(userResumes)[0].name,
+ );
+ await expectResumeToBeRenderedInPreview(
+ Object.values(userResumes)[1].name,
+ );
});
});
@@ -187,7 +196,7 @@ describe('Dashboard', () => {
);
await waitForModalWindowToHaveBeenClosed();
- await waitForResumeToBeRenderedInPreview({ name: resumeName });
+ await waitForResumeToBeRenderedInPreview(resumeName);
});
it('closes modal window', async () => {
@@ -195,19 +204,22 @@ describe('Dashboard', () => {
expect(screen.queryByRole('textbox', { name: /name/i })).toBeNull(),
);
- await waitForResumeToBeRenderedInPreview({ name: resumeName });
+ await waitForResumeToBeRenderedInPreview(resumeName);
});
- // eslint-disable-next-line jest/expect-expect
it('renders created resume in preview', async () => {
await waitForModalWindowToHaveBeenClosed();
- await expectResumeToBeRenderedInPreview({ name: resumeName });
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(resumeName),
+ ).resolves.toBeUndefined(),
+ );
});
it('adds resume in initial state to database', async () => {
await waitForModalWindowToHaveBeenClosed();
- await waitForResumeToBeRenderedInPreview({ name: resumeName });
+ await waitForResumeToBeRenderedInPreview(resumeName);
const actualUserResumes = (
await FirebaseStub.database()
@@ -286,7 +298,7 @@ describe('Dashboard', () => {
await waitFor(() =>
expect(screen.queryByText(resumeToDelete.name)).toBeNull(),
);
- await expectResumeToBeRenderedInPreview(undeletedResume);
+ await expectResumeToBeRenderedInPreview(undeletedResume.name);
});
it('displays notification', async () => {
@@ -322,8 +334,12 @@ describe('Dashboard', () => {
screen.getByTestId(loadingScreenTestId),
);
- await waitForResumeToBeRenderedInPreview(Object.values(userResumes)[0]);
- await waitForResumeToBeRenderedInPreview(Object.values(userResumes)[1]);
+ await waitForResumeToBeRenderedInPreview(
+ Object.values(userResumes)[0].name,
+ );
+ await waitForResumeToBeRenderedInPreview(
+ Object.values(userResumes)[1].name,
+ );
});
});
});
From 8018d7f52778895741de38ae621bf43f5ecabe10 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 26 Jan 2021 14:22:27 +0100
Subject: [PATCH 06/18] Dashboard page: refactored setup of fetch mock, added
more assertions to unit test
---
__mocks__/gatsby-plugin-firebase/auth/auth.js | 2 +-
.../database/reference.js | 2 +-
__mocks__/gatsby.js | 2 +-
__mocks__/utils/index.js | 5 ----
src/pages/app/__tests__/dashboard.test.js | 26 ++++++++++++++++---
src/utils/index.js | 9 ++++++-
6 files changed, 34 insertions(+), 12 deletions(-)
delete mode 100644 __mocks__/utils/index.js
diff --git a/__mocks__/gatsby-plugin-firebase/auth/auth.js b/__mocks__/gatsby-plugin-firebase/auth/auth.js
index b2fd1eb61..116ea452c 100644
--- a/__mocks__/gatsby-plugin-firebase/auth/auth.js
+++ b/__mocks__/gatsby-plugin-firebase/auth/auth.js
@@ -2,7 +2,7 @@
import { v4 as uuidv4 } from 'uuid';
import Constants from '../constants/auth';
-import delay from '../../utils/index';
+import { delay } from '../../../src/utils/index';
const singleton = Symbol('');
const singletonEnforcer = Symbol('');
diff --git a/__mocks__/gatsby-plugin-firebase/database/reference.js b/__mocks__/gatsby-plugin-firebase/database/reference.js
index aca79397d..629bb12e3 100644
--- a/__mocks__/gatsby-plugin-firebase/database/reference.js
+++ b/__mocks__/gatsby-plugin-firebase/database/reference.js
@@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
import DatabaseConstants from '../constants/database';
import DataSnapshot from './dataSnapshot';
-import delay from '../../utils/index';
+import { delay } from '../../../src/utils/index';
const parsePath = (path) => {
if (!path) {
diff --git a/__mocks__/gatsby.js b/__mocks__/gatsby.js
index 09ea71c73..bac68ffb9 100644
--- a/__mocks__/gatsby.js
+++ b/__mocks__/gatsby.js
@@ -1,6 +1,6 @@
import React from 'react';
-import delay from './utils/index';
+import { delay } from '../src/utils/index';
const Gatsby = jest.requireActual('gatsby');
diff --git a/__mocks__/utils/index.js b/__mocks__/utils/index.js
deleted file mode 100644
index 0b290076e..000000000
--- a/__mocks__/utils/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const delay = async (milliseconds) => {
- await new Promise((resolve) => setTimeout(resolve, milliseconds));
-};
-
-export default delay;
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index b5efa2c49..b8c0171ee 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -13,6 +13,7 @@ import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import '../../../i18n/index';
import '../../../utils/dayjs';
+import { unsplashPhotoRequestUrl, delay } from '../../../utils/index';
import { dataTestId as loadingScreenTestId } from '../../../components/router/LoadingScreen';
import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
@@ -112,8 +113,25 @@ describe('Dashboard', () => {
});
describe('when resume is created', () => {
+ const unsplashPhotoResponseUrl = 'https://test-url-123456789.com';
let nameTextBox = null;
+ const setupFetchMock = () => {
+ fetch.resetMocks();
+
+ fetch.mockImplementationOnce(async (input) => {
+ await delay(100);
+
+ if (input === unsplashPhotoRequestUrl) {
+ return {
+ url: unsplashPhotoResponseUrl,
+ };
+ }
+
+ throw new Error('Unsupported input.');
+ });
+ };
+
const waitForModalWindowToHaveBeenClosed = async () => {
await waitFor(() =>
screen.queryByRole('textbox', { name: /name/i })
@@ -123,10 +141,9 @@ describe('Dashboard', () => {
};
beforeEach(async () => {
- await setup();
+ setupFetchMock();
- fetch.resetMocks();
- fetch.mockReturnValueOnce({ url: 'https://test-url-123456789.com' });
+ await setup();
const dashboardCreateResumeButton = await screen.findByTestId(
createResumeButtonDataTestId,
@@ -235,6 +252,9 @@ describe('Dashboard', () => {
).filter((resume) => resume.name === resumeName);
expect(actualUserResumesFiltered).toHaveLength(1);
const createdResume = actualUserResumesFiltered[0];
+ expect(createdResume.id).toBeTruthy();
+ expect(createdResume.preview).toBeTruthy();
+ expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
expect(createdResume.createdAt).toBeTruthy();
expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
diff --git a/src/utils/index.js b/src/utils/index.js
index 4acdb57ca..e6ee56817 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -54,8 +54,11 @@ export const getFieldProps = (formik, schema, name) => ({
...formik.getFieldProps(name),
});
+export const unsplashPhotoRequestUrl =
+ 'https://source.unsplash.com/featured/400x600';
+
export const getUnsplashPhoto = async () => {
- const response = await fetch('https://source.unsplash.com/featured/400x600');
+ const response = await fetch(unsplashPhotoRequestUrl);
return response.url;
};
@@ -121,3 +124,7 @@ export const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
const blob = new Blob(byteArrays, { type: contentType });
return blob;
};
+
+export const delay = async (milliseconds) => {
+ await new Promise((resolve) => setTimeout(resolve, milliseconds));
+};
From a20fe10c062b0675c633262b6a274395c7ffabb3 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 26 Jan 2021 17:38:05 +0100
Subject: [PATCH 07/18] Dashboard page: added unit test for delete resume
interaction
---
src/pages/app/__tests__/dashboard.test.js | 119 +++++++++++++++++++---
1 file changed, 107 insertions(+), 12 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index b8c0171ee..dadb81cda 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -9,6 +9,8 @@ import {
waitForElementToBeRemoved,
} from '@testing-library/react';
+import fetchMock from 'jest-fetch-mock';
+
import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import '../../../i18n/index';
@@ -40,6 +42,18 @@ describe('Dashboard', () => {
});
};
+ const waitForModalWindowToHaveBeenClosed = async () => {
+ await waitFor(() =>
+ screen.queryByRole('textbox', { name: /name/i })
+ ? Promise.reject()
+ : Promise.resolve(),
+ );
+ };
+
+ const dismissNotification = (notification) => {
+ fireEvent.click(notification);
+ };
+
async function setup(waitForLoadingScreenToDisappear = true) {
FirebaseStub.database().initializeData();
@@ -117,9 +131,9 @@ describe('Dashboard', () => {
let nameTextBox = null;
const setupFetchMock = () => {
- fetch.resetMocks();
+ fetchMock.resetMocks();
- fetch.mockImplementationOnce(async (input) => {
+ fetchMock.mockImplementationOnce(async (input) => {
await delay(100);
if (input === unsplashPhotoRequestUrl) {
@@ -132,14 +146,6 @@ describe('Dashboard', () => {
});
};
- const waitForModalWindowToHaveBeenClosed = async () => {
- await waitFor(() =>
- screen.queryByRole('textbox', { name: /name/i })
- ? Promise.reject()
- : Promise.resolve(),
- );
- };
-
beforeEach(async () => {
setupFetchMock();
@@ -177,7 +183,7 @@ describe('Dashboard', () => {
/You might need to fill up all the required fields/i,
),
).toBeInTheDocument();
- fireEvent.click(notification);
+ dismissNotification(notification);
});
});
@@ -329,7 +335,7 @@ describe('Dashboard', () => {
new RegExp(`${resumeToDelete.name} was deleted successfully`, 'i'),
),
).toBeInTheDocument();
- fireEvent.click(notification);
+ dismissNotification(notification);
await waitForDatabaseRemoveToHaveCompleted();
});
@@ -342,6 +348,95 @@ describe('Dashboard', () => {
});
});
+ describe('when resume is renamed', () => {
+ // const mockDatabaseUpdateFunction = null;
+ let resumeToRename = null;
+ let resumeToRenameId = null;
+ let nameTextBox = null;
+
+ /*
+ const waitForDatabaseUpdateToHaveCompleted = async () => {
+ await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0]);
+ await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
+ };
+
+ const expectDatabaseUpdateToHaveCompleted = async () => {
+ await waitFor(() =>
+ expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
+ );
+ await waitFor(() =>
+ expect(
+ mockDatabaseUpdateFunction.mock.results[0].value,
+ ).resolves.toBeUndefined(),
+ );
+ };
+ */
+
+ beforeEach(async () => {
+ await setup();
+
+ [resumeToRename] = Object.values(userResumes);
+ resumeToRenameId = resumeToRename.id;
+
+ /*
+ mockDatabaseUpdateFunction = jest.spyOn(
+ FirebaseStub.database().ref(
+ `${DatabaseConstants.resumesPath}/${resumeToRenameId}`,
+ ),
+ 'update',
+ );
+ */
+
+ const resumeToRenameMenuToggle = await screen.findByTestId(
+ `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToRenameId}`,
+ );
+ fireEvent.click(resumeToRenameMenuToggle);
+
+ const menuItems = screen.getAllByRole('menuitem');
+ let renameMenuItem = null;
+ for (let index = 0; index < menuItems.length; index++) {
+ if (queryByText(menuItems[index], /rename/i)) {
+ renameMenuItem = menuItems[index];
+ break;
+ }
+ }
+ fireEvent.click(renameMenuItem);
+
+ nameTextBox = screen.getByRole('textbox', { name: /name/i });
+ });
+
+ describe('with name shorter than 5 characters', () => {
+ it('displays validation error and notification', async () => {
+ fireEvent.change(nameTextBox, { target: { value: 'CV 2' } });
+
+ fireEvent.focusOut(nameTextBox);
+
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Please enter at least 5 characters/i),
+ ).toBeInTheDocument(),
+ );
+
+ const modalEditResumeButton = screen.getByRole('button', {
+ name: /edit resume/i,
+ });
+ fireEvent.click(modalEditResumeButton);
+
+ // const notification = await screen.findByRole('alert');
+ const notification = await screen.findByText(
+ /You might need to fill up all the required fields/i,
+ );
+ expect(
+ getByText(
+ notification,
+ /You might need to fill up all the required fields/i,
+ ),
+ ).toBeInTheDocument();
+ dismissNotification(notification);
+ });
+ });
+ });
+
describe('while loading', () => {
beforeEach(async () => {
await setup(false);
From 5d9527e46ef6192f2fddd51b5ba0e129a87953fa Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Wed, 27 Jan 2021 10:35:58 +0100
Subject: [PATCH 08/18] Dashboard page: unit tests refactoring
---
src/pages/app/__tests__/dashboard.test.js | 70 +++++++++++++++--------
1 file changed, 47 insertions(+), 23 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index dadb81cda..c1f21cd68 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -43,10 +43,8 @@ describe('Dashboard', () => {
};
const waitForModalWindowToHaveBeenClosed = async () => {
- await waitFor(() =>
- screen.queryByRole('textbox', { name: /name/i })
- ? Promise.reject()
- : Promise.resolve(),
+ await waitForElementToBeRemoved(() =>
+ screen.getByRole('textbox', { name: /name/i }),
);
};
@@ -54,6 +52,17 @@ describe('Dashboard', () => {
fireEvent.click(notification);
};
+ const findAndDismissNotification = async () => {
+ const notification = await screen.findByRole('alert');
+ dismissNotification(notification);
+ };
+
+ const fnWaitForLoadingScreenToDisappear = async () => {
+ await waitForElementToBeRemoved(() =>
+ screen.getByTestId(loadingScreenTestId),
+ );
+ };
+
async function setup(waitForLoadingScreenToDisappear = true) {
FirebaseStub.database().initializeData();
@@ -86,9 +95,7 @@ describe('Dashboard', () => {
);
if (waitForLoadingScreenToDisappear) {
- await waitForElementToBeRemoved(() =>
- screen.getByTestId(loadingScreenTestId),
- );
+ await fnWaitForLoadingScreenToDisappear();
}
}
@@ -205,17 +212,17 @@ describe('Dashboard', () => {
});
it('renders loading message', async () => {
- expect(
+ await waitFor(() =>
+ expect(
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeInTheDocument(),
+ );
+ await waitForElementToBeRemoved(() =>
screen.getByRole('button', {
name: /loading/i,
}),
- ).toBeInTheDocument();
- await waitFor(() =>
- expect(
- screen.queryByRole('button', {
- name: /loading/i,
- }),
- ).toBeNull(),
);
await waitForModalWindowToHaveBeenClosed();
@@ -224,7 +231,7 @@ describe('Dashboard', () => {
it('closes modal window', async () => {
await waitFor(() =>
- expect(screen.queryByRole('textbox', { name: /name/i })).toBeNull(),
+ expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
);
await waitForResumeToBeRenderedInPreview(resumeName);
@@ -289,11 +296,22 @@ describe('Dashboard', () => {
);
};
+ const waitForResumeToDisappearFromPreview = async (resumeName) => {
+ await waitFor(() =>
+ screen.queryByText(resumeName) ? Promise.reject() : Promise.resolve(),
+ );
+ };
+
beforeEach(async () => {
await setup();
- [resumeToDelete, undeletedResume] = Object.values(userResumes);
+ [resumeToDelete] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
resumeToDeleteId = resumeToDelete.id;
+ [undeletedResume] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.initialStateResumeId,
+ );
mockDatabaseRemoveFunction = jest.spyOn(
FirebaseStub.database().ref(
@@ -319,10 +337,14 @@ describe('Dashboard', () => {
});
it('removes it from database and preview', async () => {
+ await findAndDismissNotification();
+
await expectDatabaseRemoveToHaveCompleted();
await waitFor(() =>
- expect(screen.queryByText(resumeToDelete.name)).toBeNull(),
+ expect(
+ waitForResumeToDisappearFromPreview(resumeToDelete.name),
+ ).resolves.toBeUndefined(),
);
await expectResumeToBeRenderedInPreview(undeletedResume.name);
});
@@ -338,13 +360,16 @@ describe('Dashboard', () => {
dismissNotification(notification);
await waitForDatabaseRemoveToHaveCompleted();
+ await waitForResumeToDisappearFromPreview(resumeToDelete.name);
});
it('closes menu', async () => {
const menuItems = screen.queryAllByRole('menuitem');
expect(menuItems).toHaveLength(0);
+ await findAndDismissNotification();
await waitForDatabaseRemoveToHaveCompleted();
+ await waitForResumeToDisappearFromPreview(resumeToDelete.name);
});
});
@@ -375,7 +400,9 @@ describe('Dashboard', () => {
beforeEach(async () => {
await setup();
- [resumeToRename] = Object.values(userResumes);
+ [resumeToRename] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
resumeToRenameId = resumeToRename.id;
/*
@@ -444,10 +471,7 @@ describe('Dashboard', () => {
it('renders loading screen', async () => {
expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
-
- await waitForElementToBeRemoved(() =>
- screen.getByTestId(loadingScreenTestId),
- );
+ await fnWaitForLoadingScreenToDisappear();
await waitForResumeToBeRenderedInPreview(
Object.values(userResumes)[0].name,
From da8bf8bc365592b9b6218fe5ce624a163e3000be Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Wed, 27 Jan 2021 11:33:11 +0100
Subject: [PATCH 09/18] Dashboard page: added more unit tests for rename resume
interaction
---
src/pages/app/__tests__/builder.test.js | 3 +-
src/pages/app/__tests__/dashboard.test.js | 86 +++++++++++++++++++++--
2 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/src/pages/app/__tests__/builder.test.js b/src/pages/app/__tests__/builder.test.js
index f6ad40f8a..e22d6e9d7 100644
--- a/src/pages/app/__tests__/builder.test.js
+++ b/src/pages/app/__tests__/builder.test.js
@@ -102,8 +102,9 @@ describe('Builder', () => {
if (waitForDatabaseUpdateToHaveCompleted) {
await fnWaitForDatabaseUpdateToHaveCompleted();
- mockDatabaseUpdateFunction.mockClear();
}
+
+ mockDatabaseUpdateFunction.mockClear();
}
describe('handles errors', () => {
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index c1f21cd68..421b38096 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -374,12 +374,11 @@ describe('Dashboard', () => {
});
describe('when resume is renamed', () => {
- // const mockDatabaseUpdateFunction = null;
+ let mockDatabaseUpdateFunction = null;
let resumeToRename = null;
let resumeToRenameId = null;
let nameTextBox = null;
- /*
const waitForDatabaseUpdateToHaveCompleted = async () => {
await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0]);
await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
@@ -395,7 +394,6 @@ describe('Dashboard', () => {
).resolves.toBeUndefined(),
);
};
- */
beforeEach(async () => {
await setup();
@@ -405,14 +403,13 @@ describe('Dashboard', () => {
);
resumeToRenameId = resumeToRename.id;
- /*
mockDatabaseUpdateFunction = jest.spyOn(
FirebaseStub.database().ref(
`${DatabaseConstants.resumesPath}/${resumeToRenameId}`,
),
'update',
);
- */
+ mockDatabaseUpdateFunction.mockClear();
const resumeToRenameMenuToggle = await screen.findByTestId(
`${resumePreviewMenuToggleDataTestIdPrefix}${resumeToRenameId}`,
@@ -432,6 +429,10 @@ describe('Dashboard', () => {
nameTextBox = screen.getByRole('textbox', { name: /name/i });
});
+ it('renders current name in modal window', async () => {
+ expect(nameTextBox).toHaveValue(resumeToRename.name);
+ });
+
describe('with name shorter than 5 characters', () => {
it('displays validation error and notification', async () => {
fireEvent.change(nameTextBox, { target: { value: 'CV 2' } });
@@ -462,6 +463,81 @@ describe('Dashboard', () => {
dismissNotification(notification);
});
});
+
+ describe('with valid name', () => {
+ let resumeNewName = null;
+ let now = 0;
+
+ beforeEach(() => {
+ resumeNewName = `${resumeToRename.name} - renamed`;
+ now = new Date().getTime();
+
+ fireEvent.change(nameTextBox, {
+ target: { value: resumeNewName },
+ });
+
+ const modalEditResumeButton = screen.getByRole('button', {
+ name: /edit resume/i,
+ });
+ fireEvent.click(modalEditResumeButton);
+ });
+
+ it('renders loading message', async () => {
+ await waitFor(() =>
+ expect(
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeInTheDocument(),
+ );
+ await waitForElementToBeRemoved(() =>
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ );
+
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForDatabaseUpdateToHaveCompleted();
+ await waitForResumeToBeRenderedInPreview(resumeNewName);
+ });
+
+ it('closes modal window', async () => {
+ await waitFor(() =>
+ expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
+ );
+
+ await waitForDatabaseUpdateToHaveCompleted();
+ await waitForResumeToBeRenderedInPreview(resumeNewName);
+ });
+
+ it('renders renamed resume in preview', async () => {
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForDatabaseUpdateToHaveCompleted();
+
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(resumeNewName),
+ ).resolves.toBeUndefined(),
+ );
+ });
+
+ it('updates database', async () => {
+ await waitForModalWindowToHaveBeenClosed();
+
+ await expectDatabaseUpdateToHaveCompleted();
+ const mockDatabaseUpdateFunctionCallArgument =
+ mockDatabaseUpdateFunction.mock.calls[0][0];
+ expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(
+ resumeToRenameId,
+ );
+ expect(mockDatabaseUpdateFunctionCallArgument.name).toBe(resumeNewName);
+ expect(
+ mockDatabaseUpdateFunctionCallArgument.updatedAt,
+ ).toBeGreaterThanOrEqual(now);
+
+ await waitForResumeToBeRenderedInPreview(resumeNewName);
+ });
+ });
});
describe('while loading', () => {
From c748e6a0b49b623427acde804005d67fc55658c3 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 1 Feb 2021 10:49:02 +0100
Subject: [PATCH 10/18] Dashboard page: removed unit tests related to rename
resume interaction (they are generating warnings)
---
src/pages/app/__tests__/dashboard.test.js | 169 +---------------------
1 file changed, 1 insertion(+), 168 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index 421b38096..a9bea6c5b 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -170,7 +170,7 @@ describe('Dashboard', () => {
it('displays validation error and notification', async () => {
fireEvent.change(nameTextBox, { target: { value: 'CV 1' } });
- fireEvent.focusOut(nameTextBox);
+ fireEvent.blur(nameTextBox);
await waitFor(() =>
expect(
@@ -373,173 +373,6 @@ describe('Dashboard', () => {
});
});
- describe('when resume is renamed', () => {
- let mockDatabaseUpdateFunction = null;
- let resumeToRename = null;
- let resumeToRenameId = null;
- let nameTextBox = null;
-
- const waitForDatabaseUpdateToHaveCompleted = async () => {
- await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0]);
- await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
- };
-
- const expectDatabaseUpdateToHaveCompleted = async () => {
- await waitFor(() =>
- expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
- );
- await waitFor(() =>
- expect(
- mockDatabaseUpdateFunction.mock.results[0].value,
- ).resolves.toBeUndefined(),
- );
- };
-
- beforeEach(async () => {
- await setup();
-
- [resumeToRename] = Object.values(userResumes).filter(
- (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
- );
- resumeToRenameId = resumeToRename.id;
-
- mockDatabaseUpdateFunction = jest.spyOn(
- FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/${resumeToRenameId}`,
- ),
- 'update',
- );
- mockDatabaseUpdateFunction.mockClear();
-
- const resumeToRenameMenuToggle = await screen.findByTestId(
- `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToRenameId}`,
- );
- fireEvent.click(resumeToRenameMenuToggle);
-
- const menuItems = screen.getAllByRole('menuitem');
- let renameMenuItem = null;
- for (let index = 0; index < menuItems.length; index++) {
- if (queryByText(menuItems[index], /rename/i)) {
- renameMenuItem = menuItems[index];
- break;
- }
- }
- fireEvent.click(renameMenuItem);
-
- nameTextBox = screen.getByRole('textbox', { name: /name/i });
- });
-
- it('renders current name in modal window', async () => {
- expect(nameTextBox).toHaveValue(resumeToRename.name);
- });
-
- describe('with name shorter than 5 characters', () => {
- it('displays validation error and notification', async () => {
- fireEvent.change(nameTextBox, { target: { value: 'CV 2' } });
-
- fireEvent.focusOut(nameTextBox);
-
- await waitFor(() =>
- expect(
- screen.getByText(/Please enter at least 5 characters/i),
- ).toBeInTheDocument(),
- );
-
- const modalEditResumeButton = screen.getByRole('button', {
- name: /edit resume/i,
- });
- fireEvent.click(modalEditResumeButton);
-
- // const notification = await screen.findByRole('alert');
- const notification = await screen.findByText(
- /You might need to fill up all the required fields/i,
- );
- expect(
- getByText(
- notification,
- /You might need to fill up all the required fields/i,
- ),
- ).toBeInTheDocument();
- dismissNotification(notification);
- });
- });
-
- describe('with valid name', () => {
- let resumeNewName = null;
- let now = 0;
-
- beforeEach(() => {
- resumeNewName = `${resumeToRename.name} - renamed`;
- now = new Date().getTime();
-
- fireEvent.change(nameTextBox, {
- target: { value: resumeNewName },
- });
-
- const modalEditResumeButton = screen.getByRole('button', {
- name: /edit resume/i,
- });
- fireEvent.click(modalEditResumeButton);
- });
-
- it('renders loading message', async () => {
- await waitFor(() =>
- expect(
- screen.getByRole('button', {
- name: /loading/i,
- }),
- ).toBeInTheDocument(),
- );
- await waitForElementToBeRemoved(() =>
- screen.getByRole('button', {
- name: /loading/i,
- }),
- );
-
- await waitForModalWindowToHaveBeenClosed();
- await waitForDatabaseUpdateToHaveCompleted();
- await waitForResumeToBeRenderedInPreview(resumeNewName);
- });
-
- it('closes modal window', async () => {
- await waitFor(() =>
- expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
- );
-
- await waitForDatabaseUpdateToHaveCompleted();
- await waitForResumeToBeRenderedInPreview(resumeNewName);
- });
-
- it('renders renamed resume in preview', async () => {
- await waitForModalWindowToHaveBeenClosed();
- await waitForDatabaseUpdateToHaveCompleted();
-
- await waitFor(() =>
- expect(
- expectResumeToBeRenderedInPreview(resumeNewName),
- ).resolves.toBeUndefined(),
- );
- });
-
- it('updates database', async () => {
- await waitForModalWindowToHaveBeenClosed();
-
- await expectDatabaseUpdateToHaveCompleted();
- const mockDatabaseUpdateFunctionCallArgument =
- mockDatabaseUpdateFunction.mock.calls[0][0];
- expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(
- resumeToRenameId,
- );
- expect(mockDatabaseUpdateFunctionCallArgument.name).toBe(resumeNewName);
- expect(
- mockDatabaseUpdateFunctionCallArgument.updatedAt,
- ).toBeGreaterThanOrEqual(now);
-
- await waitForResumeToBeRenderedInPreview(resumeNewName);
- });
- });
- });
-
describe('while loading', () => {
beforeEach(async () => {
await setup(false);
From 5ee077dac5e71855b2952d28a6b6eb57f96615e0 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 1 Feb 2021 12:10:15 +0100
Subject: [PATCH 11/18] Dashboard page: added unit tests related to duplicate
resume interaction
---
src/pages/app/__tests__/dashboard.test.js | 138 ++++++++++++++++++----
1 file changed, 114 insertions(+), 24 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
index a9bea6c5b..7b0da3b6f 100644
--- a/src/pages/app/__tests__/dashboard.test.js
+++ b/src/pages/app/__tests__/dashboard.test.js
@@ -31,6 +31,7 @@ import Dashboard from '../dashboard';
describe('Dashboard', () => {
let userResumes = null;
const user = DatabaseConstants.user1;
+ const unsplashPhotoResponseUrl = 'https://test-url-123456789.com';
const waitForResumeToBeRenderedInPreview = async (resumeName) => {
await screen.findByText(resumeName);
@@ -57,13 +58,36 @@ describe('Dashboard', () => {
dismissNotification(notification);
};
- const fnWaitForLoadingScreenToDisappear = async () => {
+ const waitForLoadingScreenToDisappearFn = async () => {
await waitForElementToBeRemoved(() =>
screen.getByTestId(loadingScreenTestId),
);
};
- async function setup(waitForLoadingScreenToDisappear = true) {
+ const setupFetchMockFn = () => {
+ fetchMock.resetMocks();
+
+ fetchMock.mockImplementationOnce(async (input) => {
+ await delay(100);
+
+ if (input === unsplashPhotoRequestUrl) {
+ return {
+ url: unsplashPhotoResponseUrl,
+ };
+ }
+
+ throw new Error('Unsupported input.');
+ });
+ };
+
+ async function setup(
+ waitForLoadingScreenToDisappear = true,
+ setupFetchMock = false,
+ ) {
+ if (setupFetchMock) {
+ setupFetchMockFn();
+ }
+
FirebaseStub.database().initializeData();
userResumes = (
@@ -95,7 +119,7 @@ describe('Dashboard', () => {
);
if (waitForLoadingScreenToDisappear) {
- await fnWaitForLoadingScreenToDisappear();
+ await waitForLoadingScreenToDisappearFn();
}
}
@@ -134,29 +158,10 @@ describe('Dashboard', () => {
});
describe('when resume is created', () => {
- const unsplashPhotoResponseUrl = 'https://test-url-123456789.com';
let nameTextBox = null;
- const setupFetchMock = () => {
- fetchMock.resetMocks();
-
- fetchMock.mockImplementationOnce(async (input) => {
- await delay(100);
-
- if (input === unsplashPhotoRequestUrl) {
- return {
- url: unsplashPhotoResponseUrl,
- };
- }
-
- throw new Error('Unsupported input.');
- });
- };
-
beforeEach(async () => {
- setupFetchMock();
-
- await setup();
+ await setup(true, true);
const dashboardCreateResumeButton = await screen.findByTestId(
createResumeButtonDataTestId,
@@ -373,6 +378,91 @@ describe('Dashboard', () => {
});
});
+ describe('when resume is duplicated', () => {
+ let resumeToDuplicate = null;
+ let resumeToDuplicateId = null;
+ let duplicateResumeName = null;
+ let now = 0;
+
+ beforeEach(async () => {
+ await setup(true, true);
+
+ now = new Date().getTime();
+
+ [resumeToDuplicate] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
+ resumeToDuplicateId = resumeToDuplicate.id;
+ duplicateResumeName = `${resumeToDuplicate.name} Copy`;
+
+ const resumeToDuplicateMenuToggle = await screen.findByTestId(
+ `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToDuplicateId}`,
+ );
+ fireEvent.click(resumeToDuplicateMenuToggle);
+
+ const menuItems = screen.getAllByRole('menuitem');
+ let duplicateMenuItem = null;
+ for (let index = 0; index < menuItems.length; index++) {
+ if (queryByText(menuItems[index], /duplicate/i)) {
+ duplicateMenuItem = menuItems[index];
+ break;
+ }
+ }
+ fireEvent.click(duplicateMenuItem);
+ });
+
+ it('renders duplicate resume in preview', async () => {
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(duplicateResumeName),
+ ).resolves.toBeUndefined(),
+ );
+ });
+
+ it('adds duplicate resume to database', async () => {
+ await waitForResumeToBeRenderedInPreview(duplicateResumeName);
+
+ const actualUserResumes = (
+ await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(user.uid)
+ .once('value')
+ ).val();
+ expect(Object.values(actualUserResumes)).toHaveLength(3);
+
+ const actualUserResumesFiltered = Object.values(actualUserResumes).filter(
+ (resume) =>
+ resume.name === duplicateResumeName &&
+ resume.id !== resumeToDuplicateId,
+ );
+ expect(actualUserResumesFiltered).toHaveLength(1);
+ const createdResume = actualUserResumesFiltered[0];
+ expect(createdResume.id).toBeTruthy();
+ expect(createdResume.preview).toBeTruthy();
+ expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
+ expect(createdResume.createdAt).toBeTruthy();
+ expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
+ expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
+ const expectedResume = {
+ ...resumeToDuplicate,
+ id: createdResume.id,
+ name: createdResume.name,
+ preview: createdResume.preview,
+ createdAt: createdResume.createdAt,
+ updatedAt: createdResume.updatedAt,
+ };
+ expect(createdResume).toEqual(expectedResume);
+ });
+
+ it('closes menu', async () => {
+ const menuItems = screen.queryAllByRole('menuitem');
+ expect(menuItems).toHaveLength(0);
+
+ await waitForResumeToBeRenderedInPreview(duplicateResumeName);
+ });
+ });
+
describe('while loading', () => {
beforeEach(async () => {
await setup(false);
@@ -380,7 +470,7 @@ describe('Dashboard', () => {
it('renders loading screen', async () => {
expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
- await fnWaitForLoadingScreenToDisappear();
+ await waitForLoadingScreenToDisappearFn();
await waitForResumeToBeRenderedInPreview(
Object.values(userResumes)[0].name,
From e39026c8b4ad3ecf5264a23ae004accea361516b Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Mon, 1 Feb 2021 18:00:52 +0100
Subject: [PATCH 12/18] Dashboard page: unit tests separated in different files
---
.../__tests__/dashboard.createResume.test.js | 151 ++++++
.../__tests__/dashboard.deleteResume.test.js | 121 +++++
.../dashboard.duplicateResume.test.js | 103 ++++
.../app/__tests__/dashboard.rendering.test.js | 50 ++
src/pages/app/__tests__/dashboard.test.js | 483 ------------------
src/pages/app/__tests__/helpers/dashboard.js | 158 ++++++
6 files changed, 583 insertions(+), 483 deletions(-)
create mode 100644 src/pages/app/__tests__/dashboard.createResume.test.js
create mode 100644 src/pages/app/__tests__/dashboard.deleteResume.test.js
create mode 100644 src/pages/app/__tests__/dashboard.duplicateResume.test.js
create mode 100644 src/pages/app/__tests__/dashboard.rendering.test.js
delete mode 100644 src/pages/app/__tests__/dashboard.test.js
create mode 100644 src/pages/app/__tests__/helpers/dashboard.js
diff --git a/src/pages/app/__tests__/dashboard.createResume.test.js b/src/pages/app/__tests__/dashboard.createResume.test.js
new file mode 100644
index 000000000..72fc0ad64
--- /dev/null
+++ b/src/pages/app/__tests__/dashboard.createResume.test.js
@@ -0,0 +1,151 @@
+import {
+ fireEvent,
+ getByText,
+ screen,
+ waitFor,
+ waitForElementToBeRemoved,
+} from '@testing-library/react';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
+import {
+ waitForResumeToBeRenderedInPreview,
+ expectResumeToBeRenderedInPreview,
+ waitForModalWindowToHaveBeenClosed,
+ dismissNotification,
+ unsplashPhotoResponseUrl,
+ setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+} from './helpers/dashboard';
+
+const tooShortResumeName = 'CV 1';
+const validResumeName = 'Resume for SW development roles';
+
+async function setup() {
+ const user = DatabaseConstants.user1;
+ await setupWithFetchMockAndWaitForLoadingScreenToDisappear(user);
+
+ const dashboardCreateResumeButton = await screen.findByTestId(
+ createResumeButtonDataTestId,
+ );
+ fireEvent.click(dashboardCreateResumeButton);
+
+ const nameTextBox = screen.getByRole('textbox', { name: /name/i });
+ return { user, nameTextBox };
+}
+
+async function setupAndSubmit(resumeName) {
+ const { user, nameTextBox } = await setup();
+
+ fireEvent.change(nameTextBox, {
+ target: { value: resumeName },
+ });
+
+ const modalCreateResumeButton = screen.getByRole('button', {
+ name: /create resume/i,
+ });
+ fireEvent.click(modalCreateResumeButton);
+
+ return { user };
+}
+
+describe('with invalid name', () => {
+ it('displays validation error', async () => {
+ const { nameTextBox } = await setup();
+
+ fireEvent.change(nameTextBox, { target: { value: tooShortResumeName } });
+ fireEvent.blur(nameTextBox);
+
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Please enter at least 5 characters/i),
+ ).toBeInTheDocument(),
+ );
+ });
+
+ it('displays notification', async () => {
+ await setupAndSubmit(tooShortResumeName);
+
+ const notification = await screen.findByRole('alert');
+ expect(
+ getByText(
+ notification,
+ /You might need to fill up all the required fields/i,
+ ),
+ ).toBeInTheDocument();
+ dismissNotification(notification);
+ });
+});
+
+describe('with valid name', () => {
+ it('renders loading message', async () => {
+ await setupAndSubmit(validResumeName);
+
+ await waitFor(() =>
+ expect(
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeInTheDocument(),
+ );
+ await waitForElementToBeRemoved(() =>
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ );
+
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+ });
+
+ it('closes modal window', async () => {
+ await setupAndSubmit(validResumeName);
+
+ await waitFor(() =>
+ expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
+ );
+
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+ });
+
+ it('renders created resume in preview', async () => {
+ await setupAndSubmit(validResumeName);
+
+ await waitForModalWindowToHaveBeenClosed();
+
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(validResumeName),
+ ).resolves.toBeUndefined(),
+ );
+ });
+
+ it('adds resume in initial state to database', async () => {
+ const now = new Date().getTime();
+ const { user } = await setupAndSubmit(validResumeName);
+
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+
+ const actualUserResumes = (
+ await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(user.uid)
+ .once('value')
+ ).val();
+ expect(Object.values(actualUserResumes)).toHaveLength(3);
+
+ const actualUserResumesFiltered = Object.values(actualUserResumes).filter(
+ (resume) => resume.name === validResumeName,
+ );
+ expect(actualUserResumesFiltered).toHaveLength(1);
+ const createdResume = actualUserResumesFiltered[0];
+ expect(createdResume.id).toBeTruthy();
+ expect(createdResume.preview).toBeTruthy();
+ expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
+ expect(createdResume.createdAt).toBeTruthy();
+ expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
+ expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
+ });
+});
diff --git a/src/pages/app/__tests__/dashboard.deleteResume.test.js b/src/pages/app/__tests__/dashboard.deleteResume.test.js
new file mode 100644
index 000000000..9d3b39b30
--- /dev/null
+++ b/src/pages/app/__tests__/dashboard.deleteResume.test.js
@@ -0,0 +1,121 @@
+import {
+ fireEvent,
+ getByText,
+ queryByText,
+ screen,
+ waitFor,
+} from '@testing-library/react';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
+import {
+ setupAndWaitForLoadingScreenToDisappear,
+ waitForResumeToDisappearFromPreview,
+ expectResumeToBeRenderedInPreview,
+ dismissNotification,
+ findAndDismissNotification,
+} from './helpers/dashboard';
+
+const waitForDatabaseRemoveToHaveCompleted = async (
+ mockDatabaseRemoveFunction,
+) => {
+ await waitFor(() => mockDatabaseRemoveFunction.mock.results[0].value);
+};
+
+const expectDatabaseRemoveToHaveCompleted = async (
+ mockDatabaseRemoveFunction,
+) => {
+ await waitFor(() =>
+ expect(mockDatabaseRemoveFunction).toHaveBeenCalledTimes(1),
+ );
+ await waitFor(() =>
+ expect(
+ mockDatabaseRemoveFunction.mock.results[0].value,
+ ).resolves.toBeUndefined(),
+ );
+};
+
+async function setup() {
+ const userResumes = await setupAndWaitForLoadingScreenToDisappear(
+ DatabaseConstants.user1,
+ );
+
+ const [resumeToDelete] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
+ const resumeToDeleteId = resumeToDelete.id;
+ const [undeletedResume] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.initialStateResumeId,
+ );
+
+ const mockDatabaseRemoveFunction = jest.spyOn(
+ FirebaseStub.database().ref(
+ `${DatabaseConstants.resumesPath}/${resumeToDeleteId}`,
+ ),
+ 'remove',
+ );
+
+ const resumeToDeleteMenuToggle = await screen.findByTestId(
+ `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToDeleteId}`,
+ );
+ fireEvent.click(resumeToDeleteMenuToggle);
+
+ const menuItems = screen.getAllByRole('menuitem');
+ let deleteMenuItem = null;
+ for (let index = 0; index < menuItems.length; index++) {
+ if (queryByText(menuItems[index], /delete/i)) {
+ deleteMenuItem = menuItems[index];
+ break;
+ }
+ }
+ fireEvent.click(deleteMenuItem);
+
+ return { resumeToDelete, undeletedResume, mockDatabaseRemoveFunction };
+}
+
+it('removes resume from database and preview', async () => {
+ const {
+ resumeToDelete,
+ undeletedResume,
+ mockDatabaseRemoveFunction,
+ } = await setup();
+
+ await findAndDismissNotification();
+
+ await expectDatabaseRemoveToHaveCompleted(mockDatabaseRemoveFunction);
+
+ await waitFor(() =>
+ expect(
+ waitForResumeToDisappearFromPreview(resumeToDelete.name),
+ ).resolves.toBeUndefined(),
+ );
+ await expectResumeToBeRenderedInPreview(undeletedResume.name);
+});
+
+it('displays notification', async () => {
+ const { resumeToDelete, mockDatabaseRemoveFunction } = await setup();
+
+ const notification = await screen.findByRole('alert');
+ expect(
+ getByText(
+ notification,
+ new RegExp(`${resumeToDelete.name} was deleted successfully`, 'i'),
+ ),
+ ).toBeInTheDocument();
+ dismissNotification(notification);
+
+ await waitForDatabaseRemoveToHaveCompleted(mockDatabaseRemoveFunction);
+ await waitForResumeToDisappearFromPreview(resumeToDelete.name);
+});
+
+it('closes menu', async () => {
+ const { resumeToDelete, mockDatabaseRemoveFunction } = await setup();
+
+ const menuItems = screen.queryAllByRole('menuitem');
+ expect(menuItems).toHaveLength(0);
+
+ await findAndDismissNotification();
+ await waitForDatabaseRemoveToHaveCompleted(mockDatabaseRemoveFunction);
+ await waitForResumeToDisappearFromPreview(resumeToDelete.name);
+});
diff --git a/src/pages/app/__tests__/dashboard.duplicateResume.test.js b/src/pages/app/__tests__/dashboard.duplicateResume.test.js
new file mode 100644
index 000000000..432714182
--- /dev/null
+++ b/src/pages/app/__tests__/dashboard.duplicateResume.test.js
@@ -0,0 +1,103 @@
+import {
+ fireEvent,
+ queryByText,
+ screen,
+ waitFor,
+} from '@testing-library/react';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
+import {
+ setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+ waitForResumeToBeRenderedInPreview,
+ expectResumeToBeRenderedInPreview,
+ unsplashPhotoResponseUrl,
+} from './helpers/dashboard';
+
+async function setup() {
+ const user = DatabaseConstants.user1;
+ const userResumes = await setupWithFetchMockAndWaitForLoadingScreenToDisappear(
+ user,
+ );
+
+ const [resumeToDuplicate] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
+ const resumeToDuplicateId = resumeToDuplicate.id;
+ const duplicateResumeName = `${resumeToDuplicate.name} Copy`;
+
+ const resumeToDuplicateMenuToggle = await screen.findByTestId(
+ `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToDuplicateId}`,
+ );
+ fireEvent.click(resumeToDuplicateMenuToggle);
+
+ const menuItems = screen.getAllByRole('menuitem');
+ let duplicateMenuItem = null;
+ for (let index = 0; index < menuItems.length; index++) {
+ if (queryByText(menuItems[index], /duplicate/i)) {
+ duplicateMenuItem = menuItems[index];
+ break;
+ }
+ }
+ fireEvent.click(duplicateMenuItem);
+
+ return { user, resumeToDuplicate, duplicateResumeName };
+}
+
+it('renders duplicate resume in preview', async () => {
+ const { duplicateResumeName } = await setup();
+
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(duplicateResumeName),
+ ).resolves.toBeUndefined(),
+ );
+});
+
+it('adds duplicate resume to database', async () => {
+ const now = new Date().getTime();
+ const { user, resumeToDuplicate, duplicateResumeName } = await setup();
+
+ await waitForResumeToBeRenderedInPreview(duplicateResumeName);
+
+ const actualUserResumes = (
+ await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(user.uid)
+ .once('value')
+ ).val();
+ expect(Object.values(actualUserResumes)).toHaveLength(3);
+
+ const actualUserResumesFiltered = Object.values(actualUserResumes).filter(
+ (resume) =>
+ resume.name === duplicateResumeName && resume.id !== resumeToDuplicate.id,
+ );
+ expect(actualUserResumesFiltered).toHaveLength(1);
+ const createdResume = actualUserResumesFiltered[0];
+ expect(createdResume.id).toBeTruthy();
+ expect(createdResume.preview).toBeTruthy();
+ expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
+ expect(createdResume.createdAt).toBeTruthy();
+ expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
+ expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
+ const expectedResume = {
+ ...resumeToDuplicate,
+ id: createdResume.id,
+ name: createdResume.name,
+ preview: createdResume.preview,
+ createdAt: createdResume.createdAt,
+ updatedAt: createdResume.updatedAt,
+ };
+ expect(createdResume).toEqual(expectedResume);
+});
+
+it('closes menu', async () => {
+ const { duplicateResumeName } = await setup();
+
+ const menuItems = screen.queryAllByRole('menuitem');
+ expect(menuItems).toHaveLength(0);
+
+ await waitForResumeToBeRenderedInPreview(duplicateResumeName);
+});
diff --git a/src/pages/app/__tests__/dashboard.rendering.test.js b/src/pages/app/__tests__/dashboard.rendering.test.js
new file mode 100644
index 000000000..76271428e
--- /dev/null
+++ b/src/pages/app/__tests__/dashboard.rendering.test.js
@@ -0,0 +1,50 @@
+import { screen, waitFor } from '@testing-library/react';
+
+import { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
+import setup, {
+ setupAndWaitForLoadingScreenToDisappear,
+ expectResumeToBeRenderedInPreview,
+ expectLoadingScreenToBeRendered,
+ waitForLoadingScreenToDisappear,
+} from './helpers/dashboard';
+
+const user = DatabaseConstants.user1;
+
+it('renders loading screen', async () => {
+ await setup(user);
+
+ expect(expectLoadingScreenToBeRendered()).toBeUndefined();
+ await waitForLoadingScreenToDisappear();
+});
+
+it('renders document title', async () => {
+ await setupAndWaitForLoadingScreenToDisappear(user);
+
+ await waitFor(() => {
+ expect(document.title).toEqual('Dashboard | Reactive Resume');
+ });
+});
+
+it('renders create resume', async () => {
+ await setupAndWaitForLoadingScreenToDisappear(user);
+
+ await waitFor(() => {
+ expect(screen.getByText(/create resume/i)).toBeInTheDocument();
+ });
+ await waitFor(() => {
+ expect(
+ screen.getByTestId(createResumeButtonDataTestId),
+ ).toBeInTheDocument();
+ });
+});
+
+it('renders preview of user resumes', async () => {
+ const userResumes = await setupAndWaitForLoadingScreenToDisappear(user);
+
+ expect(Object.keys(userResumes)).toHaveLength(2);
+
+ await expectResumeToBeRenderedInPreview(Object.values(userResumes)[0].name);
+ await expectResumeToBeRenderedInPreview(Object.values(userResumes)[1].name);
+});
diff --git a/src/pages/app/__tests__/dashboard.test.js b/src/pages/app/__tests__/dashboard.test.js
deleted file mode 100644
index 7b0da3b6f..000000000
--- a/src/pages/app/__tests__/dashboard.test.js
+++ /dev/null
@@ -1,483 +0,0 @@
-import React from 'react';
-import {
- fireEvent,
- getByText,
- queryByText,
- render,
- screen,
- waitFor,
- waitForElementToBeRemoved,
-} from '@testing-library/react';
-
-import fetchMock from 'jest-fetch-mock';
-
-import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
-
-import '../../../i18n/index';
-import '../../../utils/dayjs';
-import { unsplashPhotoRequestUrl, delay } from '../../../utils/index';
-import { dataTestId as loadingScreenTestId } from '../../../components/router/LoadingScreen';
-import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
-import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
-import { SettingsProvider } from '../../../contexts/SettingsContext';
-import { ModalProvider } from '../../../contexts/ModalContext';
-import { UserProvider } from '../../../contexts/UserContext';
-import { DatabaseProvider } from '../../../contexts/DatabaseContext';
-import { ResumeProvider } from '../../../contexts/ResumeContext';
-import { StorageProvider } from '../../../contexts/StorageContext';
-import Wrapper from '../../../components/shared/Wrapper';
-import Dashboard from '../dashboard';
-
-describe('Dashboard', () => {
- let userResumes = null;
- const user = DatabaseConstants.user1;
- const unsplashPhotoResponseUrl = 'https://test-url-123456789.com';
-
- const waitForResumeToBeRenderedInPreview = async (resumeName) => {
- await screen.findByText(resumeName);
- };
-
- const expectResumeToBeRenderedInPreview = async (resumeName) => {
- await waitFor(() => {
- expect(screen.getByText(resumeName)).toBeInTheDocument();
- });
- };
-
- const waitForModalWindowToHaveBeenClosed = async () => {
- await waitForElementToBeRemoved(() =>
- screen.getByRole('textbox', { name: /name/i }),
- );
- };
-
- const dismissNotification = (notification) => {
- fireEvent.click(notification);
- };
-
- const findAndDismissNotification = async () => {
- const notification = await screen.findByRole('alert');
- dismissNotification(notification);
- };
-
- const waitForLoadingScreenToDisappearFn = async () => {
- await waitForElementToBeRemoved(() =>
- screen.getByTestId(loadingScreenTestId),
- );
- };
-
- const setupFetchMockFn = () => {
- fetchMock.resetMocks();
-
- fetchMock.mockImplementationOnce(async (input) => {
- await delay(100);
-
- if (input === unsplashPhotoRequestUrl) {
- return {
- url: unsplashPhotoResponseUrl,
- };
- }
-
- throw new Error('Unsupported input.');
- });
- };
-
- async function setup(
- waitForLoadingScreenToDisappear = true,
- setupFetchMock = false,
- ) {
- if (setupFetchMock) {
- setupFetchMockFn();
- }
-
- FirebaseStub.database().initializeData();
-
- userResumes = (
- await FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(user.uid)
- .once('value')
- ).val();
-
- FirebaseStub.auth().signInAnonymously();
-
- render(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- );
-
- if (waitForLoadingScreenToDisappear) {
- await waitForLoadingScreenToDisappearFn();
- }
- }
-
- describe('renders', () => {
- beforeEach(async () => {
- await setup();
- });
-
- it('document title', async () => {
- await waitFor(() => {
- expect(document.title).toEqual('Dashboard | Reactive Resume');
- });
- });
-
- it('create resume', async () => {
- await waitFor(() => {
- expect(screen.getByText(/create resume/i)).toBeInTheDocument();
- });
- await waitFor(() => {
- expect(
- screen.getByTestId(createResumeButtonDataTestId),
- ).toBeInTheDocument();
- });
- });
-
- it('preview of user resumes', async () => {
- expect(Object.keys(userResumes)).toHaveLength(2);
-
- await expectResumeToBeRenderedInPreview(
- Object.values(userResumes)[0].name,
- );
- await expectResumeToBeRenderedInPreview(
- Object.values(userResumes)[1].name,
- );
- });
- });
-
- describe('when resume is created', () => {
- let nameTextBox = null;
-
- beforeEach(async () => {
- await setup(true, true);
-
- const dashboardCreateResumeButton = await screen.findByTestId(
- createResumeButtonDataTestId,
- );
- fireEvent.click(dashboardCreateResumeButton);
-
- nameTextBox = screen.getByRole('textbox', { name: /name/i });
- });
-
- describe('with name shorter than 5 characters', () => {
- it('displays validation error and notification', async () => {
- fireEvent.change(nameTextBox, { target: { value: 'CV 1' } });
-
- fireEvent.blur(nameTextBox);
-
- await waitFor(() =>
- expect(
- screen.getByText(/Please enter at least 5 characters/i),
- ).toBeInTheDocument(),
- );
-
- const modalCreateResumeButton = screen.getByRole('button', {
- name: /create resume/i,
- });
- fireEvent.click(modalCreateResumeButton);
-
- const notification = await screen.findByRole('alert');
- expect(
- getByText(
- notification,
- /You might need to fill up all the required fields/i,
- ),
- ).toBeInTheDocument();
- dismissNotification(notification);
- });
- });
-
- describe('with valid name', () => {
- const resumeName = 'Resume for SW development roles';
- let now = 0;
-
- beforeEach(() => {
- now = new Date().getTime();
-
- fireEvent.change(nameTextBox, {
- target: { value: resumeName },
- });
-
- const modalCreateResumeButton = screen.getByRole('button', {
- name: /create resume/i,
- });
- fireEvent.click(modalCreateResumeButton);
- });
-
- it('renders loading message', async () => {
- await waitFor(() =>
- expect(
- screen.getByRole('button', {
- name: /loading/i,
- }),
- ).toBeInTheDocument(),
- );
- await waitForElementToBeRemoved(() =>
- screen.getByRole('button', {
- name: /loading/i,
- }),
- );
-
- await waitForModalWindowToHaveBeenClosed();
- await waitForResumeToBeRenderedInPreview(resumeName);
- });
-
- it('closes modal window', async () => {
- await waitFor(() =>
- expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
- );
-
- await waitForResumeToBeRenderedInPreview(resumeName);
- });
-
- it('renders created resume in preview', async () => {
- await waitForModalWindowToHaveBeenClosed();
-
- await waitFor(() =>
- expect(
- expectResumeToBeRenderedInPreview(resumeName),
- ).resolves.toBeUndefined(),
- );
- });
-
- it('adds resume in initial state to database', async () => {
- await waitForModalWindowToHaveBeenClosed();
- await waitForResumeToBeRenderedInPreview(resumeName);
-
- const actualUserResumes = (
- await FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(user.uid)
- .once('value')
- ).val();
- expect(Object.values(actualUserResumes)).toHaveLength(3);
-
- const actualUserResumesFiltered = Object.values(
- actualUserResumes,
- ).filter((resume) => resume.name === resumeName);
- expect(actualUserResumesFiltered).toHaveLength(1);
- const createdResume = actualUserResumesFiltered[0];
- expect(createdResume.id).toBeTruthy();
- expect(createdResume.preview).toBeTruthy();
- expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
- expect(createdResume.createdAt).toBeTruthy();
- expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
- expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
- });
- });
- });
-
- describe('when resume is deleted', () => {
- let mockDatabaseRemoveFunction = null;
- let resumeToDelete = null;
- let undeletedResume = null;
- let resumeToDeleteId = null;
-
- const waitForDatabaseRemoveToHaveCompleted = async () => {
- await waitFor(() => mockDatabaseRemoveFunction.mock.results[0].value);
- };
-
- const expectDatabaseRemoveToHaveCompleted = async () => {
- await waitFor(() =>
- expect(mockDatabaseRemoveFunction).toHaveBeenCalledTimes(1),
- );
- await waitFor(() =>
- expect(
- mockDatabaseRemoveFunction.mock.results[0].value,
- ).resolves.toBeUndefined(),
- );
- };
-
- const waitForResumeToDisappearFromPreview = async (resumeName) => {
- await waitFor(() =>
- screen.queryByText(resumeName) ? Promise.reject() : Promise.resolve(),
- );
- };
-
- beforeEach(async () => {
- await setup();
-
- [resumeToDelete] = Object.values(userResumes).filter(
- (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
- );
- resumeToDeleteId = resumeToDelete.id;
- [undeletedResume] = Object.values(userResumes).filter(
- (resume) => resume.id === DatabaseConstants.initialStateResumeId,
- );
-
- mockDatabaseRemoveFunction = jest.spyOn(
- FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/${resumeToDeleteId}`,
- ),
- 'remove',
- );
-
- const resumeToDeleteMenuToggle = await screen.findByTestId(
- `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToDeleteId}`,
- );
- fireEvent.click(resumeToDeleteMenuToggle);
-
- const menuItems = screen.getAllByRole('menuitem');
- let deleteMenuItem = null;
- for (let index = 0; index < menuItems.length; index++) {
- if (queryByText(menuItems[index], /delete/i)) {
- deleteMenuItem = menuItems[index];
- break;
- }
- }
- fireEvent.click(deleteMenuItem);
- });
-
- it('removes it from database and preview', async () => {
- await findAndDismissNotification();
-
- await expectDatabaseRemoveToHaveCompleted();
-
- await waitFor(() =>
- expect(
- waitForResumeToDisappearFromPreview(resumeToDelete.name),
- ).resolves.toBeUndefined(),
- );
- await expectResumeToBeRenderedInPreview(undeletedResume.name);
- });
-
- it('displays notification', async () => {
- const notification = await screen.findByRole('alert');
- expect(
- getByText(
- notification,
- new RegExp(`${resumeToDelete.name} was deleted successfully`, 'i'),
- ),
- ).toBeInTheDocument();
- dismissNotification(notification);
-
- await waitForDatabaseRemoveToHaveCompleted();
- await waitForResumeToDisappearFromPreview(resumeToDelete.name);
- });
-
- it('closes menu', async () => {
- const menuItems = screen.queryAllByRole('menuitem');
- expect(menuItems).toHaveLength(0);
-
- await findAndDismissNotification();
- await waitForDatabaseRemoveToHaveCompleted();
- await waitForResumeToDisappearFromPreview(resumeToDelete.name);
- });
- });
-
- describe('when resume is duplicated', () => {
- let resumeToDuplicate = null;
- let resumeToDuplicateId = null;
- let duplicateResumeName = null;
- let now = 0;
-
- beforeEach(async () => {
- await setup(true, true);
-
- now = new Date().getTime();
-
- [resumeToDuplicate] = Object.values(userResumes).filter(
- (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
- );
- resumeToDuplicateId = resumeToDuplicate.id;
- duplicateResumeName = `${resumeToDuplicate.name} Copy`;
-
- const resumeToDuplicateMenuToggle = await screen.findByTestId(
- `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToDuplicateId}`,
- );
- fireEvent.click(resumeToDuplicateMenuToggle);
-
- const menuItems = screen.getAllByRole('menuitem');
- let duplicateMenuItem = null;
- for (let index = 0; index < menuItems.length; index++) {
- if (queryByText(menuItems[index], /duplicate/i)) {
- duplicateMenuItem = menuItems[index];
- break;
- }
- }
- fireEvent.click(duplicateMenuItem);
- });
-
- it('renders duplicate resume in preview', async () => {
- await waitFor(() =>
- expect(
- expectResumeToBeRenderedInPreview(duplicateResumeName),
- ).resolves.toBeUndefined(),
- );
- });
-
- it('adds duplicate resume to database', async () => {
- await waitForResumeToBeRenderedInPreview(duplicateResumeName);
-
- const actualUserResumes = (
- await FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(user.uid)
- .once('value')
- ).val();
- expect(Object.values(actualUserResumes)).toHaveLength(3);
-
- const actualUserResumesFiltered = Object.values(actualUserResumes).filter(
- (resume) =>
- resume.name === duplicateResumeName &&
- resume.id !== resumeToDuplicateId,
- );
- expect(actualUserResumesFiltered).toHaveLength(1);
- const createdResume = actualUserResumesFiltered[0];
- expect(createdResume.id).toBeTruthy();
- expect(createdResume.preview).toBeTruthy();
- expect(createdResume.preview).toEqual(unsplashPhotoResponseUrl);
- expect(createdResume.createdAt).toBeTruthy();
- expect(createdResume.createdAt).toBeGreaterThanOrEqual(now);
- expect(createdResume.createdAt).toEqual(createdResume.updatedAt);
- const expectedResume = {
- ...resumeToDuplicate,
- id: createdResume.id,
- name: createdResume.name,
- preview: createdResume.preview,
- createdAt: createdResume.createdAt,
- updatedAt: createdResume.updatedAt,
- };
- expect(createdResume).toEqual(expectedResume);
- });
-
- it('closes menu', async () => {
- const menuItems = screen.queryAllByRole('menuitem');
- expect(menuItems).toHaveLength(0);
-
- await waitForResumeToBeRenderedInPreview(duplicateResumeName);
- });
- });
-
- describe('while loading', () => {
- beforeEach(async () => {
- await setup(false);
- });
-
- it('renders loading screen', async () => {
- expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
- await waitForLoadingScreenToDisappearFn();
-
- await waitForResumeToBeRenderedInPreview(
- Object.values(userResumes)[0].name,
- );
- await waitForResumeToBeRenderedInPreview(
- Object.values(userResumes)[1].name,
- );
- });
- });
-});
diff --git a/src/pages/app/__tests__/helpers/dashboard.js b/src/pages/app/__tests__/helpers/dashboard.js
new file mode 100644
index 000000000..f97226da0
--- /dev/null
+++ b/src/pages/app/__tests__/helpers/dashboard.js
@@ -0,0 +1,158 @@
+import React from 'react';
+import {
+ fireEvent,
+ render,
+ screen,
+ waitFor,
+ waitForElementToBeRemoved,
+} from '@testing-library/react';
+
+import fetchMock from 'jest-fetch-mock';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import '../../../../i18n/index';
+import '../../../../utils/dayjs';
+import { dataTestId as loadingScreenTestId } from '../../../../components/router/LoadingScreen';
+import { unsplashPhotoRequestUrl, delay } from '../../../../utils/index';
+import { SettingsProvider } from '../../../../contexts/SettingsContext';
+import { ModalProvider } from '../../../../contexts/ModalContext';
+import { UserProvider } from '../../../../contexts/UserContext';
+import { DatabaseProvider } from '../../../../contexts/DatabaseContext';
+import { ResumeProvider } from '../../../../contexts/ResumeContext';
+import { StorageProvider } from '../../../../contexts/StorageContext';
+import Wrapper from '../../../../components/shared/Wrapper';
+import Dashboard from '../../dashboard';
+
+const waitForResumeToBeRenderedInPreview = async (resumeName) => {
+ await screen.findByText(resumeName);
+};
+
+const waitForResumeToDisappearFromPreview = async (resumeName) => {
+ await waitFor(() =>
+ screen.queryByText(resumeName) ? Promise.reject() : Promise.resolve(),
+ );
+};
+
+const expectResumeToBeRenderedInPreview = async (resumeName) => {
+ await waitFor(() => {
+ expect(screen.getByText(resumeName)).toBeInTheDocument();
+ });
+};
+
+const waitForModalWindowToHaveBeenClosed = async () => {
+ await waitForElementToBeRemoved(() =>
+ screen.getByRole('textbox', { name: /name/i }),
+ );
+};
+
+const dismissNotification = (notification) => {
+ fireEvent.click(notification);
+};
+
+const findAndDismissNotification = async () => {
+ const notification = await screen.findByRole('alert');
+ dismissNotification(notification);
+};
+
+const expectLoadingScreenToBeRendered = () => {
+ expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
+};
+
+const waitForLoadingScreenToDisappearFn = async () => {
+ await waitForElementToBeRemoved(() =>
+ screen.getByTestId(loadingScreenTestId),
+ );
+};
+
+const unsplashPhotoResponseUrl = 'https://test-url-123456789.com';
+
+const setupFetchMockFn = () => {
+ fetchMock.resetMocks();
+
+ fetchMock.mockImplementationOnce(async (input) => {
+ await delay(100);
+
+ if (input === unsplashPhotoRequestUrl) {
+ return {
+ url: unsplashPhotoResponseUrl,
+ };
+ }
+
+ throw new Error('Unsupported input.');
+ });
+};
+
+// eslint-disable-next-line no-underscore-dangle
+async function _setup(user, waitForLoadingScreenToDisappear, setupFetchMock) {
+ if (setupFetchMock) {
+ setupFetchMockFn();
+ }
+
+ FirebaseStub.database().initializeData();
+
+ const userResumes = (
+ await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(user.uid)
+ .once('value')
+ ).val();
+
+ FirebaseStub.auth().signInAnonymously();
+
+ render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ if (waitForLoadingScreenToDisappear) {
+ await waitForLoadingScreenToDisappearFn();
+ }
+
+ return userResumes;
+}
+
+async function setup(user) {
+ const userResumes = await _setup(user, false, false);
+ return userResumes;
+}
+
+async function setupAndWaitForLoadingScreenToDisappear(user) {
+ const userResumes = await _setup(user, true, false);
+ return userResumes;
+}
+
+async function setupWithFetchMockAndWaitForLoadingScreenToDisappear(user) {
+ const userResumes = await _setup(user, true, true);
+ return userResumes;
+}
+
+export default setup;
+
+export {
+ setupAndWaitForLoadingScreenToDisappear,
+ setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+ waitForResumeToBeRenderedInPreview,
+ waitForResumeToDisappearFromPreview,
+ expectResumeToBeRenderedInPreview,
+ waitForModalWindowToHaveBeenClosed,
+ dismissNotification,
+ findAndDismissNotification,
+ expectLoadingScreenToBeRendered,
+ waitForLoadingScreenToDisappearFn as waitForLoadingScreenToDisappear,
+ unsplashPhotoResponseUrl,
+};
From f72d2639e5d44ea25ec4694a54784b2572a2b131 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 10:27:30 +0100
Subject: [PATCH 13/18] Builder page: unit tests separated in different files
---
.../__tests__/builder.dataPersistence.test.js | 39 +++
.../__tests__/builder.errorHandling.test.js | 24 ++
.../app/__tests__/builder.rendering.test.js | 63 +++++
.../app/__tests__/builder.settings.test.js | 54 ++++
src/pages/app/__tests__/builder.test.js | 260 ------------------
src/pages/app/__tests__/helpers/builder.js | 127 +++++++++
src/pages/app/__tests__/helpers/dashboard.js | 6 +-
7 files changed, 311 insertions(+), 262 deletions(-)
create mode 100644 src/pages/app/__tests__/builder.dataPersistence.test.js
create mode 100644 src/pages/app/__tests__/builder.errorHandling.test.js
create mode 100644 src/pages/app/__tests__/builder.rendering.test.js
create mode 100644 src/pages/app/__tests__/builder.settings.test.js
delete mode 100644 src/pages/app/__tests__/builder.test.js
create mode 100644 src/pages/app/__tests__/helpers/builder.js
diff --git a/src/pages/app/__tests__/builder.dataPersistence.test.js b/src/pages/app/__tests__/builder.dataPersistence.test.js
new file mode 100644
index 000000000..9f1fef644
--- /dev/null
+++ b/src/pages/app/__tests__/builder.dataPersistence.test.js
@@ -0,0 +1,39 @@
+import { fireEvent, screen } from '@testing-library/react';
+
+import { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import {
+ setupAndWait,
+ expectDatabaseUpdateToHaveCompleted,
+} from './helpers/builder';
+
+const testTimeoutInMilliseconds = 20000;
+jest.setTimeout(testTimeoutInMilliseconds);
+
+test('when input value is changed, updates database', async () => {
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+ const { mockDatabaseUpdateFunction } = await setupAndWait(
+ resumeId,
+ true,
+ true,
+ );
+
+ const input = screen.getByRole('textbox', { name: /address line 1/i });
+ const newInputValue = 'test street 123';
+ const now = new Date().getTime();
+
+ fireEvent.change(input, { target: { value: newInputValue } });
+
+ expect(input.value).toBe(newInputValue);
+
+ await expectDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ const mockDatabaseUpdateFunctionCallArgument =
+ mockDatabaseUpdateFunction.mock.calls[0][0];
+ expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(resumeId);
+ expect(mockDatabaseUpdateFunctionCallArgument.profile.address.line1).toBe(
+ newInputValue,
+ );
+ expect(
+ mockDatabaseUpdateFunctionCallArgument.updatedAt,
+ ).toBeGreaterThanOrEqual(now);
+});
diff --git a/src/pages/app/__tests__/builder.errorHandling.test.js b/src/pages/app/__tests__/builder.errorHandling.test.js
new file mode 100644
index 000000000..f573f9b50
--- /dev/null
+++ b/src/pages/app/__tests__/builder.errorHandling.test.js
@@ -0,0 +1,24 @@
+import { navigate as mockNavigateFunction } from 'gatsby';
+import { fireEvent, getByText, screen, waitFor } from '@testing-library/react';
+
+import setup from './helpers/builder';
+
+test('if resume does not exist, navigates to Dashboard and displays notification', async () => {
+ await setup('xxxxxx');
+
+ await waitFor(() => expect(mockNavigateFunction).toHaveBeenCalledTimes(1));
+ expect(mockNavigateFunction).toHaveBeenCalledWith('/app/dashboard');
+
+ const notification = await screen.findByRole('alert');
+ expect(
+ getByText(
+ notification,
+ /The resume you were looking for does not exist anymore/i,
+ ),
+ ).toBeInTheDocument();
+ fireEvent.click(notification);
+
+ await waitFor(() =>
+ expect(mockNavigateFunction.mock.results[0].value).resolves.toBeUndefined(),
+ );
+});
diff --git a/src/pages/app/__tests__/builder.rendering.test.js b/src/pages/app/__tests__/builder.rendering.test.js
new file mode 100644
index 000000000..950296522
--- /dev/null
+++ b/src/pages/app/__tests__/builder.rendering.test.js
@@ -0,0 +1,63 @@
+import {
+ fireEvent,
+ getByText,
+ screen,
+ waitForElementToBeRemoved,
+} from '@testing-library/react';
+
+import { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { dataTestId as loadingScreenTestId } from '../../../components/router/LoadingScreen';
+
+import setup, {
+ setupAndWait,
+ waitForDatabaseUpdateToHaveCompleted,
+} from './helpers/builder';
+
+const testTimeoutInMilliseconds = 10000;
+jest.setTimeout(testTimeoutInMilliseconds);
+
+test('renders first and last name', async () => {
+ const { resume } = await setupAndWait(
+ DatabaseConstants.demoStateResume1Id,
+ true,
+ true,
+ );
+
+ expect(
+ screen.getByRole('textbox', { name: /first name/i }),
+ ).toHaveDisplayValue(resume.profile.firstName);
+ expect(
+ screen.getByRole('textbox', { name: /last name/i }),
+ ).toHaveDisplayValue(resume.profile.lastName);
+ expect(
+ screen.getAllByText(new RegExp(resume.profile.firstName, 'i')).length,
+ ).toBeTruthy();
+ expect(
+ screen.getAllByText(new RegExp(resume.profile.lastName, 'i')).length,
+ ).toBeTruthy();
+});
+
+test('renders loading screen', async () => {
+ const { mockDatabaseUpdateFunction } = await setup(
+ DatabaseConstants.demoStateResume1Id,
+ );
+
+ expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
+
+ await waitForElementToBeRemoved(() =>
+ screen.getByTestId(loadingScreenTestId),
+ );
+
+ await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+});
+
+test('if resume is in initial state, renders load demo data notification', async () => {
+ await setup(DatabaseConstants.initialStateResumeId);
+
+ const notification = await screen.findByRole('alert');
+ expect(
+ getByText(notification, /Not sure where to begin\? Try loading demo data/i),
+ ).toBeInTheDocument();
+ fireEvent.click(notification);
+});
diff --git a/src/pages/app/__tests__/builder.settings.test.js b/src/pages/app/__tests__/builder.settings.test.js
new file mode 100644
index 000000000..7db8a1c1a
--- /dev/null
+++ b/src/pages/app/__tests__/builder.settings.test.js
@@ -0,0 +1,54 @@
+import { fireEvent, screen } from '@testing-library/react';
+
+import { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { languageStorageItemKey } from '../../../contexts/SettingsContext';
+
+import {
+ setupAndWait,
+ expectDatabaseUpdateToHaveCompleted,
+} from './helpers/builder';
+
+const testTimeoutInMilliseconds = 20000;
+jest.setTimeout(testTimeoutInMilliseconds);
+
+test('allows to change the language', async () => {
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+ const { mockDatabaseUpdateFunction } = await setupAndWait(
+ resumeId,
+ true,
+ true,
+ );
+
+ const languageElement = screen.getByLabelText(/language/i);
+ const italianLanguageCode = 'it';
+ const now = new Date().getTime();
+
+ fireEvent.change(languageElement, {
+ target: { value: italianLanguageCode },
+ });
+
+ expect(languageElement).toHaveValue(italianLanguageCode);
+
+ expect(screen.queryByLabelText(/date of birth/i)).not.toBeInTheDocument();
+ expect(screen.getByLabelText(/data di nascita/i)).toBeInTheDocument();
+
+ const languageStorageItem = localStorage.getItem(languageStorageItemKey);
+ expect(languageStorageItem).toBe(italianLanguageCode);
+
+ await expectDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ const mockDatabaseUpdateFunctionCallArgument =
+ mockDatabaseUpdateFunction.mock.calls[0][0];
+ expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(resumeId);
+ expect(mockDatabaseUpdateFunctionCallArgument.metadata.language).toBe(
+ italianLanguageCode,
+ );
+ expect(
+ mockDatabaseUpdateFunctionCallArgument.updatedAt,
+ ).toBeGreaterThanOrEqual(now);
+});
+
+afterEach(() => {
+ const englishLanguageCode = 'en';
+ localStorage.setItem(languageStorageItemKey, englishLanguageCode);
+});
diff --git a/src/pages/app/__tests__/builder.test.js b/src/pages/app/__tests__/builder.test.js
deleted file mode 100644
index e22d6e9d7..000000000
--- a/src/pages/app/__tests__/builder.test.js
+++ /dev/null
@@ -1,260 +0,0 @@
-import { navigate as mockNavigateFunction } from 'gatsby';
-import React from 'react';
-import {
- fireEvent,
- getByText,
- render,
- screen,
- waitFor,
- waitForElementToBeRemoved,
-} from '@testing-library/react';
-
-import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
-
-import { dataTestId as loadingScreenTestId } from '../../../components/router/LoadingScreen';
-import {
- SettingsProvider,
- languageStorageItemKey,
-} from '../../../contexts/SettingsContext';
-import { ModalProvider } from '../../../contexts/ModalContext';
-import { UserProvider } from '../../../contexts/UserContext';
-import {
- DatabaseProvider,
- DebounceWaitTime,
-} from '../../../contexts/DatabaseContext';
-import { ResumeProvider } from '../../../contexts/ResumeContext';
-import { StorageProvider } from '../../../contexts/StorageContext';
-import Wrapper from '../../../components/shared/Wrapper';
-import Builder from '../builder';
-
-describe('Builder', () => {
- let resumeId = null;
- let resume = null;
- let mockDatabaseUpdateFunction = null;
-
- const fnWaitForDatabaseUpdateToHaveCompleted = async () => {
- await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0], {
- timeout: DebounceWaitTime,
- });
- await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
- };
-
- const expectDatabaseUpdateToHaveCompleted = async () => {
- await waitFor(
- () => expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
- {
- timeout: DebounceWaitTime,
- },
- );
- await waitFor(() =>
- expect(
- mockDatabaseUpdateFunction.mock.results[0].value,
- ).resolves.toBeUndefined(),
- );
- };
-
- async function setup(
- resumeIdParameter,
- waitForLoadingScreenToDisappear = true,
- waitForDatabaseUpdateToHaveCompleted = true,
- ) {
- FirebaseStub.database().initializeData();
-
- resumeId = resumeIdParameter;
- resume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
-
- mockDatabaseUpdateFunction = jest.spyOn(
- FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/${resumeId}`,
- ),
- 'update',
- );
-
- FirebaseStub.auth().signInAnonymously();
-
- render(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- );
-
- if (waitForLoadingScreenToDisappear) {
- await waitForElementToBeRemoved(() =>
- screen.getByTestId(loadingScreenTestId),
- );
- }
-
- if (waitForDatabaseUpdateToHaveCompleted) {
- await fnWaitForDatabaseUpdateToHaveCompleted();
- }
-
- mockDatabaseUpdateFunction.mockClear();
- }
-
- describe('handles errors', () => {
- describe('if resume does not exist', () => {
- beforeEach(async () => {
- await setup('xxxxxx', false, false);
- });
-
- it('navigates to Dashboard and displays notification', async () => {
- await waitFor(() =>
- expect(mockNavigateFunction).toHaveBeenCalledTimes(1),
- );
- expect(mockNavigateFunction).toHaveBeenCalledWith('/app/dashboard');
-
- const notification = await screen.findByRole('alert');
- expect(
- getByText(
- notification,
- /The resume you were looking for does not exist anymore/i,
- ),
- ).toBeInTheDocument();
- fireEvent.click(notification);
-
- await waitFor(() =>
- expect(
- mockNavigateFunction.mock.results[0].value,
- ).resolves.toBeUndefined(),
- );
- });
- });
- });
-
- describe('renders', () => {
- beforeEach(async () => {
- await setup(DatabaseConstants.demoStateResume1Id);
- });
-
- it('first and last name', () => {
- expect(
- screen.getByRole('textbox', { name: /first name/i }),
- ).toHaveDisplayValue(resume.profile.firstName);
- expect(
- screen.getByRole('textbox', { name: /last name/i }),
- ).toHaveDisplayValue(resume.profile.lastName);
- expect(
- screen.getAllByText(new RegExp(resume.profile.firstName, 'i')).length,
- ).toBeTruthy();
- expect(
- screen.getAllByText(new RegExp(resume.profile.lastName, 'i')).length,
- ).toBeTruthy();
- });
- });
-
- describe('settings', () => {
- beforeEach(async () => {
- await setup(DatabaseConstants.demoStateResume1Id);
- });
-
- it('allow to change the language', async () => {
- const languageElement = screen.getByLabelText(/language/i);
- const italianLanguageCode = 'it';
- const now = new Date().getTime();
-
- fireEvent.change(languageElement, {
- target: { value: italianLanguageCode },
- });
-
- expect(languageElement).toHaveValue(italianLanguageCode);
-
- expect(screen.queryByLabelText(/date of birth/i)).not.toBeInTheDocument();
- expect(screen.getByLabelText(/data di nascita/i)).toBeInTheDocument();
-
- const languageStorageItem = localStorage.getItem(languageStorageItemKey);
- expect(languageStorageItem).toBe(italianLanguageCode);
-
- await expectDatabaseUpdateToHaveCompleted();
- const mockDatabaseUpdateFunctionCallArgument =
- mockDatabaseUpdateFunction.mock.calls[0][0];
- expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(resumeId);
- expect(mockDatabaseUpdateFunctionCallArgument.metadata.language).toBe(
- italianLanguageCode,
- );
- expect(
- mockDatabaseUpdateFunctionCallArgument.updatedAt,
- ).toBeGreaterThanOrEqual(now);
- });
-
- afterEach(() => {
- const englishLanguageCode = 'en';
- localStorage.setItem(languageStorageItemKey, englishLanguageCode);
- });
- });
-
- describe('updates data', () => {
- beforeEach(async () => {
- await setup(DatabaseConstants.demoStateResume1Id);
- });
-
- it('when input value is changed', async () => {
- const input = screen.getByRole('textbox', { name: /address line 1/i });
- const newInputValue = 'test street 123';
- const now = new Date().getTime();
-
- fireEvent.change(input, { target: { value: newInputValue } });
-
- expect(input.value).toBe(newInputValue);
-
- await expectDatabaseUpdateToHaveCompleted();
- const mockDatabaseUpdateFunctionCallArgument =
- mockDatabaseUpdateFunction.mock.calls[0][0];
- expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(resumeId);
- expect(mockDatabaseUpdateFunctionCallArgument.profile.address.line1).toBe(
- newInputValue,
- );
- expect(
- mockDatabaseUpdateFunctionCallArgument.updatedAt,
- ).toBeGreaterThanOrEqual(now);
- });
- });
-
- describe('while loading', () => {
- beforeEach(async () => {
- await setup(DatabaseConstants.demoStateResume1Id, false, false);
- });
-
- it('renders loading screen', async () => {
- expect(screen.getByTestId(loadingScreenTestId)).toBeInTheDocument();
-
- await waitForElementToBeRemoved(() =>
- screen.getByTestId(loadingScreenTestId),
- );
-
- await fnWaitForDatabaseUpdateToHaveCompleted();
- });
- });
-
- describe('with resume in initial state', () => {
- beforeEach(async () => {
- await setup(DatabaseConstants.initialStateResumeId, false, false);
- });
-
- it('displays load demo data notification', async () => {
- const notification = await screen.findByRole('alert');
- expect(
- getByText(
- notification,
- /Not sure where to begin\? Try loading demo data/i,
- ),
- ).toBeInTheDocument();
- fireEvent.click(notification);
- });
- });
-});
diff --git a/src/pages/app/__tests__/helpers/builder.js b/src/pages/app/__tests__/helpers/builder.js
new file mode 100644
index 000000000..b05eca1b7
--- /dev/null
+++ b/src/pages/app/__tests__/helpers/builder.js
@@ -0,0 +1,127 @@
+import React from 'react';
+import {
+ render,
+ screen,
+ waitFor,
+ waitForElementToBeRemoved,
+} from '@testing-library/react';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { dataTestId as loadingScreenTestId } from '../../../../components/router/LoadingScreen';
+import { SettingsProvider } from '../../../../contexts/SettingsContext';
+import { ModalProvider } from '../../../../contexts/ModalContext';
+import { UserProvider } from '../../../../contexts/UserContext';
+import {
+ DatabaseProvider,
+ DebounceWaitTime,
+} from '../../../../contexts/DatabaseContext';
+import { ResumeProvider } from '../../../../contexts/ResumeContext';
+import { StorageProvider } from '../../../../contexts/StorageContext';
+import Wrapper from '../../../../components/shared/Wrapper';
+import Builder from '../../builder';
+
+const waitForDatabaseUpdateToHaveCompletedFn = async (
+ mockDatabaseUpdateFunction,
+) => {
+ await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0], {
+ timeout: DebounceWaitTime,
+ });
+ await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
+};
+
+const expectDatabaseUpdateToHaveCompleted = async (
+ mockDatabaseUpdateFunction,
+) => {
+ await waitFor(
+ () => expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
+ {
+ timeout: DebounceWaitTime,
+ },
+ );
+ await waitFor(() =>
+ expect(
+ mockDatabaseUpdateFunction.mock.results[0].value,
+ ).resolves.toBeUndefined(),
+ );
+};
+
+// eslint-disable-next-line no-underscore-dangle
+async function _setup(
+ resumeId,
+ waitForLoadingScreenToDisappear,
+ waitForDatabaseUpdateToHaveCompleted,
+) {
+ FirebaseStub.database().initializeData();
+
+ const resume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+
+ const mockDatabaseUpdateFunction = jest.spyOn(
+ FirebaseStub.database().ref(`${DatabaseConstants.resumesPath}/${resumeId}`),
+ 'update',
+ );
+
+ FirebaseStub.auth().signInAnonymously();
+
+ render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ );
+
+ if (waitForLoadingScreenToDisappear) {
+ await waitForElementToBeRemoved(() =>
+ screen.getByTestId(loadingScreenTestId),
+ );
+ }
+
+ if (waitForDatabaseUpdateToHaveCompleted) {
+ await waitForDatabaseUpdateToHaveCompletedFn(mockDatabaseUpdateFunction);
+ }
+
+ mockDatabaseUpdateFunction.mockClear();
+
+ return { resume, mockDatabaseUpdateFunction };
+}
+
+async function setup(resumeId) {
+ const returnValue = await _setup(resumeId, false, false);
+ return returnValue;
+}
+
+async function setupAndWait(
+ resumeId,
+ waitForLoadingScreenToDisappear,
+ waitForDatabaseUpdateToHaveCompleted,
+) {
+ const returnValue = await _setup(
+ resumeId,
+ waitForLoadingScreenToDisappear,
+ waitForDatabaseUpdateToHaveCompleted,
+ );
+ return returnValue;
+}
+
+export default setup;
+
+export {
+ setupAndWait,
+ waitForDatabaseUpdateToHaveCompletedFn as waitForDatabaseUpdateToHaveCompleted,
+ expectDatabaseUpdateToHaveCompleted,
+};
diff --git a/src/pages/app/__tests__/helpers/dashboard.js b/src/pages/app/__tests__/helpers/dashboard.js
index f97226da0..4eba4f3eb 100644
--- a/src/pages/app/__tests__/helpers/dashboard.js
+++ b/src/pages/app/__tests__/helpers/dashboard.js
@@ -41,8 +41,10 @@ const expectResumeToBeRenderedInPreview = async (resumeName) => {
};
const waitForModalWindowToHaveBeenClosed = async () => {
- await waitForElementToBeRemoved(() =>
- screen.getByRole('textbox', { name: /name/i }),
+ await waitFor(() =>
+ screen.queryByRole('textbox', { name: /name/i })
+ ? Promise.reject()
+ : Promise.resolve(),
);
};
From 4634b4f0a040d172bfed58f09241d3158b151c3f Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 10:40:26 +0100
Subject: [PATCH 14/18] Castform: unit tests refactoring to reduce nesting
---
src/templates/__tests__/Castform.test.js | 75 ++++++++++++------------
1 file changed, 38 insertions(+), 37 deletions(-)
diff --git a/src/templates/__tests__/Castform.test.js b/src/templates/__tests__/Castform.test.js
index 6f29ffed6..51cc84c0e 100644
--- a/src/templates/__tests__/Castform.test.js
+++ b/src/templates/__tests__/Castform.test.js
@@ -6,47 +6,48 @@ import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import '../../i18n/index';
import Castform from '../Castform';
-describe('Castform', () => {
- let resume = {};
+const birthDateLabelMatcher = /Date of birth/i;
- beforeEach(async () => {
- FirebaseStub.database().initializeData();
+async function setup(resumeId) {
+ FirebaseStub.database().initializeData();
- const resumeId = DatabaseConstants.initialStateResumeId;
- resume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
- });
+ const resume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
- it('renders correctly', () => {
- const { container } = render();
+ return resume;
+}
- expect(container).toBeTruthy();
- expect(container).toBeInTheDocument();
- });
+test('renders correctly', async () => {
+ const resume = await setup(DatabaseConstants.initialStateResumeId);
- describe('date of birth', () => {
- const birthDateLabelMatcher = /Date of birth/i;
+ const { container } = render();
- it('is not shown if not provided', () => {
- render();
-
- expect(screen.queryByText(birthDateLabelMatcher)).toBeNull();
- });
-
- it('is shown if provided', () => {
- const birthDate = new Date(1990, 0, 20);
- const birthDateFormatted = '20 January 1990';
- resume.profile.birthDate = birthDate;
-
- render();
-
- expect(screen.getByText(birthDateLabelMatcher)).toBeTruthy();
- expect(screen.getByText(birthDateLabelMatcher)).toBeInTheDocument();
- expect(screen.getByText(birthDateFormatted)).toBeTruthy();
- expect(screen.getByText(birthDateFormatted)).toBeInTheDocument();
- });
- });
+ expect(container).toBeTruthy();
+ expect(container).toBeInTheDocument();
+});
+
+test('date of birth is not shown if not provided', async () => {
+ const resume = await setup(DatabaseConstants.initialStateResumeId);
+
+ render();
+
+ expect(screen.queryByText(birthDateLabelMatcher)).toBeNull();
+});
+
+test('date of birth is shown if provided', async () => {
+ const resume = await setup(DatabaseConstants.initialStateResumeId);
+
+ const birthDate = new Date(1990, 0, 20);
+ const birthDateFormatted = '20 January 1990';
+ resume.profile.birthDate = birthDate;
+
+ render();
+
+ expect(screen.getByText(birthDateLabelMatcher)).toBeTruthy();
+ expect(screen.getByText(birthDateLabelMatcher)).toBeInTheDocument();
+ expect(screen.getByText(birthDateFormatted)).toBeTruthy();
+ expect(screen.getByText(birthDateFormatted)).toBeInTheDocument();
});
From 23386839a691aebb198cce97ca405942ee2f17af Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 12:39:16 +0100
Subject: [PATCH 15/18] Firebase Stub: unit tests separated in different files
---
.../__tests__/gatsby-plugin-firebase.test.js | 552 ------------------
.../gatsby-plugin-firebase/auth.test.js | 51 ++
.../database.ref.filtering.test.js | 53 ++
.../database.ref.off.test.js | 51 ++
.../database.ref.on.valueEventType.test.js | 45 ++
.../database.ref.once.test.js | 59 ++
.../database.ref.remove.test.js | 77 +++
.../database.ref.set.test.js | 71 +++
.../database.ref.test.js | 26 +
.../database.ref.update.test.js | 86 +++
.../gatsby-plugin-firebase/database.test.js | 52 ++
11 files changed, 571 insertions(+), 552 deletions(-)
delete mode 100644 __mocks__/__tests__/gatsby-plugin-firebase.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/auth.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.filtering.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.off.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.on.valueEventType.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.once.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.remove.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.set.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.ref.update.test.js
create mode 100644 __mocks__/__tests__/gatsby-plugin-firebase/database.test.js
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase.test.js b/__mocks__/__tests__/gatsby-plugin-firebase.test.js
deleted file mode 100644
index f80e06c08..000000000
--- a/__mocks__/__tests__/gatsby-plugin-firebase.test.js
+++ /dev/null
@@ -1,552 +0,0 @@
-import { waitFor } from '@testing-library/react';
-import FirebaseStub, {
- AuthConstants,
- DatabaseConstants,
-} from '../gatsby-plugin-firebase';
-
-describe('FirebaseStub', () => {
- describe('auth', () => {
- it('reuses existing Auth instance', () => {
- const auth1 = FirebaseStub.auth();
- const auth2 = FirebaseStub.auth();
-
- expect(auth1.uuid).toBeTruthy();
- expect(auth2.uuid).toBeTruthy();
- expect(auth1.uuid).toEqual(auth2.uuid);
- });
-
- it('returns anonymous user 1 when signing in anonymously', async () => {
- const user = await FirebaseStub.auth().signInAnonymously();
-
- expect(user).toBeTruthy();
- expect(user).toEqual(AuthConstants.anonymousUser1);
- });
-
- it('calls onAuthStateChanged observer with anonymous user 1 when signing in anonymously', async () => {
- let user = null;
- let error = null;
- FirebaseStub.auth().onAuthStateChanged(
- (_user) => {
- user = _user;
- },
- (_error) => {
- error = _error;
- },
- );
-
- await FirebaseStub.auth().signInAnonymously();
-
- expect(user).toBeTruthy();
- expect(user).toEqual(AuthConstants.anonymousUser1);
- expect(error).toBeNull();
- });
-
- it('onAuthStateChanged unsubscribe removes observer', () => {
- const observer = () => {};
- const unsubscribe = FirebaseStub.auth().onAuthStateChanged(observer);
- expect(unsubscribe).toBeTruthy();
- expect(
- FirebaseStub.auth().onAuthStateChangedObservers.indexOf(observer),
- ).toBeGreaterThanOrEqual(0);
-
- unsubscribe();
-
- expect(
- FirebaseStub.auth().onAuthStateChangedObservers.indexOf(observer),
- ).not.toBeGreaterThanOrEqual(0);
- });
- });
-
- describe('database', () => {
- beforeEach(() => {
- FirebaseStub.database().initializeData();
- });
-
- it('reuses existing Database instance', () => {
- const database1 = FirebaseStub.database();
- const database2 = FirebaseStub.database();
-
- expect(database1.uuid).toBeTruthy();
- expect(database2.uuid).toBeTruthy();
- expect(database1.uuid).toEqual(database2.uuid);
- });
-
- describe('ref function', () => {
- it('reuses existing Reference instance', () => {
- const ref1 = FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/123`,
- );
- const ref2 = FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/123`,
- );
-
- expect(ref1).toBeTruthy();
- expect(ref2).toBeTruthy();
- expect(ref1).toEqual(ref2);
- });
-
- it('leading slash in reference path is ignored', () => {
- const path = `${DatabaseConstants.resumesPath}/123`;
-
- const ref1 = FirebaseStub.database().ref(path);
- expect(ref1).toBeTruthy();
- expect(ref1.path).toEqual(path);
-
- const ref2 = FirebaseStub.database().ref(`/${path}`);
- expect(ref2).toBeTruthy();
- expect(ref2).toEqual(ref1);
- });
- });
-
- it('ServerValue.TIMESTAMP returns current time in milliseconds', () => {
- const now = new Date().getTime();
- const timestamp = FirebaseStub.database.ServerValue.TIMESTAMP;
-
- expect(timestamp).toBeTruthy();
- expect(timestamp).toBeGreaterThanOrEqual(now);
- });
-
- it('initializing data sets up resumes and users', async () => {
- const resumesRef = FirebaseStub.database().ref(
- DatabaseConstants.resumesPath,
- );
- const resumesDataSnapshot = await resumesRef.once('value');
- const resumes = resumesDataSnapshot.val();
- expect(resumes).toBeTruthy();
- expect(Object.keys(resumes)).toHaveLength(3);
- const demoStateResume1 = resumes[DatabaseConstants.demoStateResume1Id];
- expect(demoStateResume1).toBeTruthy();
- expect(demoStateResume1.id).toEqual(DatabaseConstants.demoStateResume1Id);
- expect(demoStateResume1.user).toEqual(DatabaseConstants.user1.uid);
- const demoStateResume2 = resumes[DatabaseConstants.demoStateResume2Id];
- expect(demoStateResume2).toBeTruthy();
- expect(demoStateResume2.id).toEqual(DatabaseConstants.demoStateResume2Id);
- expect(demoStateResume2.user).toEqual(DatabaseConstants.user2.uid);
- const initialStateResume =
- resumes[DatabaseConstants.initialStateResumeId];
- expect(initialStateResume).toBeTruthy();
- expect(initialStateResume.id).toEqual(
- DatabaseConstants.initialStateResumeId,
- );
- expect(initialStateResume.user).toEqual(DatabaseConstants.user1.uid);
-
- const usersRef = FirebaseStub.database().ref(DatabaseConstants.usersPath);
- const usersDataSnapshot = await usersRef.once('value');
- const users = usersDataSnapshot.val();
- expect(users).toBeTruthy();
- expect(Object.keys(users)).toHaveLength(2);
- const anonymousUser1 = users[DatabaseConstants.user1.uid];
- expect(anonymousUser1).toBeTruthy();
- expect(anonymousUser1).toEqual(DatabaseConstants.user1);
- const anonymousUser2 = users[DatabaseConstants.user2.uid];
- expect(anonymousUser2).toBeTruthy();
- expect(anonymousUser2).toEqual(DatabaseConstants.user2);
- });
-
- it('retrieves resume if it exists', async () => {
- const resume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
-
- expect(resume).toBeTruthy();
- expect(resume.id).toEqual(DatabaseConstants.demoStateResume1Id);
- });
-
- it('retrieves null if resume does not exist', async () => {
- const resumeId = 'invalidResumeId';
-
- const resume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
-
- expect(resume).toBeNull();
- });
-
- it('retrieves user if it exists', async () => {
- const user = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.usersPath}/${DatabaseConstants.user1.uid}`)
- .once('value')
- ).val();
-
- expect(user).toBeTruthy();
- expect(user).toEqual(DatabaseConstants.user1);
- });
-
- it('retrieves null if user does not exist', async () => {
- const userId = 'invalidUserId';
-
- const user = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.usersPath}/${userId}`)
- .once('value')
- ).val();
-
- expect(user).toBeNull();
- });
-
- describe('on function', () => {
- describe('value event', () => {
- it('triggers event with true if on the connected reference path', async () => {
- let snapshotValue = null;
-
- FirebaseStub.database()
- .ref(DatabaseConstants.connectedPath)
- .on('value', (snapshot) => {
- snapshotValue = snapshot.val();
- });
-
- await waitFor(() =>
- snapshotValue ? Promise.resolve(true) : Promise.reject(),
- );
-
- expect(snapshotValue).not.toBeNull();
- expect(snapshotValue).toBe(true);
- });
-
- it('triggers event with resumes if on the resumes reference path', async () => {
- const resumesDataSnapshot = await FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .once('value');
- const resumes = resumesDataSnapshot.val();
- let snapshotValue = null;
-
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .on('value', (snapshot) => {
- snapshotValue = snapshot.val();
- });
-
- await waitFor(() =>
- snapshotValue ? Promise.resolve(true) : Promise.reject(),
- );
-
- expect(snapshotValue).not.toBeNull();
- expect(snapshotValue).toEqual(resumes);
- });
- });
- });
-
- it('can filter resumes by user', async () => {
- let snapshotValue = null;
-
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(DatabaseConstants.user1.uid)
- .on('value', (snapshot) => {
- snapshotValue = snapshot.val();
- });
-
- await waitFor(() =>
- snapshotValue ? Promise.resolve(true) : Promise.reject(),
- );
-
- expect(snapshotValue).not.toBeNull();
- expect(Object.keys(snapshotValue)).toHaveLength(2);
- Object.values(snapshotValue).forEach((resume) =>
- expect(resume.user).toEqual(DatabaseConstants.user1.uid),
- );
- });
-
- it('previously set query parameters are not kept when retrieving reference again', () => {
- let reference = null;
-
- reference = FirebaseStub.database().ref(DatabaseConstants.resumesPath);
- expect(reference).toBeTruthy();
- const { uuid } = reference;
- expect(reference.orderByChildPath).toHaveLength(0);
- expect(reference.equalToValue).toHaveLength(0);
-
- reference = FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo('testuser1');
- expect(reference).toBeTruthy();
- expect(reference.uuid).toBe(uuid);
- expect(reference.orderByChildPath).toBe('user');
- expect(reference.equalToValue).toBe('testuser1');
-
- reference = FirebaseStub.database().ref(DatabaseConstants.resumesPath);
- expect(reference).toBeTruthy();
- expect(reference.uuid).toBe(uuid);
- expect(reference.orderByChildPath).toHaveLength(0);
- expect(reference.equalToValue).toHaveLength(0);
- });
-
- describe('set function', () => {
- it('inserts data', async () => {
- const existingResume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
- expect(existingResume).toBeTruthy();
-
- const newResume = JSON.parse(JSON.stringify(existingResume));
- newResume.id = 'newre1';
- newResume.name = `Test Resume ${newResume.id}`;
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
- .set(newResume);
-
- const actualResume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
- .once('value')
- ).val();
- expect(actualResume).toBeTruthy();
- expect(actualResume).toEqual(newResume);
- });
-
- it('triggers events', async () => {
- let snapshotValue = null;
- const callback = jest.fn((snapshot) => {
- snapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(DatabaseConstants.user1.uid)
- .on('value', callback);
- await waitFor(() => callback.mock.calls[0][0]);
- callback.mockClear();
- snapshotValue = null;
-
- const existingResume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
- expect(existingResume).toBeTruthy();
-
- const newResume = JSON.parse(JSON.stringify(existingResume));
- newResume.id = 'newre1';
- newResume.name = `Test Resume ${newResume.id}`;
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
- .set(newResume);
-
- await waitFor(() => callback.mock.calls[0][0]);
-
- expect(callback.mock.calls).toHaveLength(1);
- expect(snapshotValue).not.toBeNull();
- expect(Object.keys(snapshotValue)).toHaveLength(3);
- expect(snapshotValue[newResume.id]).toBeTruthy();
- expect(snapshotValue[newResume.id]).toEqual(newResume);
- });
- });
-
- describe('update function', () => {
- it('can spy on it', async () => {
- const referencePath = `${DatabaseConstants.resumesPath}/123456`;
- const functionSpy = jest.spyOn(
- FirebaseStub.database().ref(referencePath),
- 'update',
- );
- const updateArgument = 'test value 123';
-
- await FirebaseStub.database().ref(referencePath).update(updateArgument);
-
- expect(functionSpy).toHaveBeenCalledTimes(1);
- const functionCallArgument = functionSpy.mock.calls[0][0];
- expect(functionCallArgument).toBeTruthy();
- expect(functionCallArgument).toEqual(updateArgument);
- });
-
- it('updates data', async () => {
- const resumeId = DatabaseConstants.demoStateResume1Id;
- const existingResume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
- expect(existingResume).toBeTruthy();
-
- const resumeName = 'Test Resume renamed';
- existingResume.name = resumeName;
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .update(existingResume);
-
- const actualResume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
- expect(actualResume).toBeTruthy();
- expect(existingResume).toEqual(actualResume);
- expect(actualResume.name).toEqual(resumeName);
- });
-
- it('triggers events', async () => {
- let snapshotValue = null;
- const callback = jest.fn((snapshot) => {
- snapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(DatabaseConstants.user1.uid)
- .on('value', callback);
- await waitFor(() => callback.mock.calls[0][0]);
- callback.mockClear();
- snapshotValue = null;
-
- const existingResume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
- expect(existingResume).toBeTruthy();
-
- existingResume.name = 'Test Resume renamed';
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${existingResume.id}`)
- .update(existingResume);
-
- await waitFor(() => callback.mock.calls[0][0]);
-
- expect(callback.mock.calls).toHaveLength(1);
- expect(snapshotValue).not.toBeNull();
- expect(Object.keys(snapshotValue)).toHaveLength(2);
- expect(snapshotValue[existingResume.id]).toBeTruthy();
- expect(snapshotValue[existingResume.id]).toEqual(existingResume);
- });
- });
-
- describe('remove function', () => {
- it('deletes data', async () => {
- const resumeId = DatabaseConstants.demoStateResume1Id;
- const removedResume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
- expect(removedResume).toBeTruthy();
-
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .remove();
-
- const actualResume = (
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
- .once('value')
- ).val();
- expect(actualResume).toBeNull();
- });
-
- it('triggers events', async () => {
- const userUid = DatabaseConstants.user1.uid;
-
- let valueCallbackSnapshotValue = null;
- const valueCallback = jest.fn((snapshot) => {
- valueCallbackSnapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(userUid)
- .on('value', valueCallback);
- await waitFor(() => valueCallback.mock.calls[0][0]);
- valueCallback.mockClear();
- valueCallbackSnapshotValue = null;
-
- let childRemovedCallbackSnapshotValue = null;
- const childRemovedCallback = jest.fn((snapshot) => {
- childRemovedCallbackSnapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(userUid)
- .on('child_removed', childRemovedCallback);
-
- const removedResume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
- expect(removedResume).toBeTruthy();
- expect(removedResume.user).toEqual(userUid);
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${removedResume.id}`)
- .remove();
-
- await waitFor(() => childRemovedCallback.mock.calls[0][0]);
- expect(childRemovedCallback.mock.calls).toHaveLength(1);
- expect(childRemovedCallbackSnapshotValue).toBeTruthy();
- expect(childRemovedCallbackSnapshotValue).toEqual(removedResume);
-
- await waitFor(() => valueCallback.mock.calls[0][0]);
- expect(valueCallback.mock.calls).toHaveLength(1);
- expect(valueCallbackSnapshotValue).toBeTruthy();
- expect(removedResume.id in valueCallbackSnapshotValue).toBe(false);
- });
- });
-
- describe('off function', () => {
- it('removes event callbacks', async () => {
- const userUid = DatabaseConstants.user1.uid;
-
- let valueCallbackSnapshotValue = null;
- const valueCallback = jest.fn((snapshot) => {
- valueCallbackSnapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(userUid)
- .on('value', valueCallback);
- await waitFor(() => valueCallback.mock.calls[0][0]);
- valueCallback.mockClear();
- valueCallbackSnapshotValue = null;
-
- let childRemovedCallbackSnapshotValue = null;
- const childRemovedCallback = jest.fn((snapshot) => {
- childRemovedCallbackSnapshotValue = snapshot.val();
- });
- FirebaseStub.database()
- .ref(DatabaseConstants.resumesPath)
- .orderByChild('user')
- .equalTo(userUid)
- .on('child_removed', childRemovedCallback);
-
- const removedResume = (
- await FirebaseStub.database()
- .ref(
- `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
- )
- .once('value')
- ).val();
- expect(removedResume).toBeTruthy();
-
- FirebaseStub.database().ref(DatabaseConstants.resumesPath).off();
-
- await FirebaseStub.database()
- .ref(`${DatabaseConstants.resumesPath}/${removedResume.id}`)
- .remove();
-
- expect(childRemovedCallback.mock.calls).toHaveLength(0);
- expect(childRemovedCallbackSnapshotValue).toBeNull();
- expect(valueCallback.mock.calls).toHaveLength(0);
- expect(valueCallbackSnapshotValue).toBeNull();
- });
- });
- });
-});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/auth.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/auth.test.js
new file mode 100644
index 000000000..d70a5c1da
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/auth.test.js
@@ -0,0 +1,51 @@
+import FirebaseStub, { AuthConstants } from '../../gatsby-plugin-firebase';
+
+test('reuses existing Auth instance', () => {
+ const auth1 = FirebaseStub.auth();
+ const auth2 = FirebaseStub.auth();
+
+ expect(auth1.uuid).toBeTruthy();
+ expect(auth2.uuid).toBeTruthy();
+ expect(auth1.uuid).toEqual(auth2.uuid);
+});
+
+test('returns anonymous user 1 when signing in anonymously', async () => {
+ const user = await FirebaseStub.auth().signInAnonymously();
+
+ expect(user).toBeTruthy();
+ expect(user).toEqual(AuthConstants.anonymousUser1);
+});
+
+test('calls onAuthStateChanged observer with anonymous user 1 when signing in anonymously', async () => {
+ let user = null;
+ let error = null;
+ FirebaseStub.auth().onAuthStateChanged(
+ (_user) => {
+ user = _user;
+ },
+ (_error) => {
+ error = _error;
+ },
+ );
+
+ await FirebaseStub.auth().signInAnonymously();
+
+ expect(user).toBeTruthy();
+ expect(user).toEqual(AuthConstants.anonymousUser1);
+ expect(error).toBeNull();
+});
+
+test('onAuthStateChanged unsubscribe removes observer', () => {
+ const observer = () => {};
+ const unsubscribe = FirebaseStub.auth().onAuthStateChanged(observer);
+ expect(unsubscribe).toBeTruthy();
+ expect(
+ FirebaseStub.auth().onAuthStateChangedObservers.indexOf(observer),
+ ).toBeGreaterThanOrEqual(0);
+
+ unsubscribe();
+
+ expect(
+ FirebaseStub.auth().onAuthStateChangedObservers.indexOf(observer),
+ ).not.toBeGreaterThanOrEqual(0);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.filtering.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.filtering.test.js
new file mode 100644
index 000000000..83a73880b
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.filtering.test.js
@@ -0,0 +1,53 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('can filter resumes by user', async () => {
+ FirebaseStub.database().initializeData();
+
+ let snapshotValue = null;
+
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(DatabaseConstants.user1.uid)
+ .on('value', (snapshot) => {
+ snapshotValue = snapshot.val();
+ });
+
+ await waitFor(() =>
+ snapshotValue ? Promise.resolve(true) : Promise.reject(),
+ );
+
+ expect(snapshotValue).not.toBeNull();
+ expect(Object.keys(snapshotValue)).toHaveLength(2);
+ Object.values(snapshotValue).forEach((resume) =>
+ expect(resume.user).toEqual(DatabaseConstants.user1.uid),
+ );
+});
+
+test('previously set query parameters are not kept when retrieving reference again', () => {
+ FirebaseStub.database().initializeData();
+
+ let reference = null;
+
+ reference = FirebaseStub.database().ref(DatabaseConstants.resumesPath);
+ expect(reference).toBeTruthy();
+ const { uuid } = reference;
+ expect(reference.orderByChildPath).toHaveLength(0);
+ expect(reference.equalToValue).toHaveLength(0);
+
+ reference = FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo('testuser1');
+ expect(reference).toBeTruthy();
+ expect(reference.uuid).toBe(uuid);
+ expect(reference.orderByChildPath).toBe('user');
+ expect(reference.equalToValue).toBe('testuser1');
+
+ reference = FirebaseStub.database().ref(DatabaseConstants.resumesPath);
+ expect(reference).toBeTruthy();
+ expect(reference.uuid).toBe(uuid);
+ expect(reference.orderByChildPath).toHaveLength(0);
+ expect(reference.equalToValue).toHaveLength(0);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.off.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.off.test.js
new file mode 100644
index 000000000..a9f68fa0d
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.off.test.js
@@ -0,0 +1,51 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('removes event callbacks', async () => {
+ FirebaseStub.database().initializeData();
+
+ const userUid = DatabaseConstants.user1.uid;
+
+ let valueCallbackSnapshotValue = null;
+ const valueCallback = jest.fn((snapshot) => {
+ valueCallbackSnapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(userUid)
+ .on('value', valueCallback);
+ await waitFor(() => valueCallback.mock.calls[0][0]);
+ valueCallback.mockClear();
+ valueCallbackSnapshotValue = null;
+
+ let childRemovedCallbackSnapshotValue = null;
+ const childRemovedCallback = jest.fn((snapshot) => {
+ childRemovedCallbackSnapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(userUid)
+ .on('child_removed', childRemovedCallback);
+
+ const removedResume = (
+ await FirebaseStub.database()
+ .ref(
+ `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
+ )
+ .once('value')
+ ).val();
+ expect(removedResume).toBeTruthy();
+
+ FirebaseStub.database().ref(DatabaseConstants.resumesPath).off();
+
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${removedResume.id}`)
+ .remove();
+
+ expect(childRemovedCallback.mock.calls).toHaveLength(0);
+ expect(childRemovedCallbackSnapshotValue).toBeNull();
+ expect(valueCallback.mock.calls).toHaveLength(0);
+ expect(valueCallbackSnapshotValue).toBeNull();
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.on.valueEventType.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.on.valueEventType.test.js
new file mode 100644
index 000000000..9901b782b
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.on.valueEventType.test.js
@@ -0,0 +1,45 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('triggers event with true if on the connected reference path', async () => {
+ FirebaseStub.database().initializeData();
+
+ let snapshotValue = null;
+
+ FirebaseStub.database()
+ .ref(DatabaseConstants.connectedPath)
+ .on('value', (snapshot) => {
+ snapshotValue = snapshot.val();
+ });
+
+ await waitFor(() =>
+ snapshotValue ? Promise.resolve(true) : Promise.reject(),
+ );
+
+ expect(snapshotValue).not.toBeNull();
+ expect(snapshotValue).toBe(true);
+});
+
+test('triggers event with resumes if on the resumes reference path', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumesDataSnapshot = await FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .once('value');
+ const resumes = resumesDataSnapshot.val();
+
+ let snapshotValue = null;
+
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .on('value', (snapshot) => {
+ snapshotValue = snapshot.val();
+ });
+
+ await waitFor(() =>
+ snapshotValue ? Promise.resolve(true) : Promise.reject(),
+ );
+
+ expect(snapshotValue).not.toBeNull();
+ expect(snapshotValue).toEqual(resumes);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.once.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.once.test.js
new file mode 100644
index 000000000..9c018f89e
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.once.test.js
@@ -0,0 +1,59 @@
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('retrieves resume if it exists', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+
+ const resume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+
+ expect(resume).toBeTruthy();
+ expect(resume.id).toEqual(resumeId);
+});
+
+test('retrieves null if resume does not exist', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumeId = 'invalidResumeId';
+
+ const resume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+
+ expect(resume).toBeNull();
+});
+
+test('retrieves user if it exists', async () => {
+ FirebaseStub.database().initializeData();
+
+ const expectedUser = DatabaseConstants.user1;
+
+ const user = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.usersPath}/${expectedUser.uid}`)
+ .once('value')
+ ).val();
+
+ expect(user).toBeTruthy();
+ expect(user).toEqual(expectedUser);
+});
+
+test('retrieves null if user does not exist', async () => {
+ FirebaseStub.database().initializeData();
+
+ const userId = 'invalidUserId';
+
+ const user = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.usersPath}/${userId}`)
+ .once('value')
+ ).val();
+
+ expect(user).toBeNull();
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.remove.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.remove.test.js
new file mode 100644
index 000000000..3d96a0c37
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.remove.test.js
@@ -0,0 +1,77 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('deletes data', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+ const removedResume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+ expect(removedResume).toBeTruthy();
+
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .remove();
+
+ const actualResume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+ expect(actualResume).toBeNull();
+});
+
+test('triggers events', async () => {
+ FirebaseStub.database().initializeData();
+
+ const userUid = DatabaseConstants.user1.uid;
+
+ let valueCallbackSnapshotValue = null;
+ const valueCallback = jest.fn((snapshot) => {
+ valueCallbackSnapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(userUid)
+ .on('value', valueCallback);
+ await waitFor(() => valueCallback.mock.calls[0][0]);
+ valueCallback.mockClear();
+ valueCallbackSnapshotValue = null;
+
+ let childRemovedCallbackSnapshotValue = null;
+ const childRemovedCallback = jest.fn((snapshot) => {
+ childRemovedCallbackSnapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(userUid)
+ .on('child_removed', childRemovedCallback);
+
+ const removedResume = (
+ await FirebaseStub.database()
+ .ref(
+ `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
+ )
+ .once('value')
+ ).val();
+ expect(removedResume).toBeTruthy();
+ expect(removedResume.user).toEqual(userUid);
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${removedResume.id}`)
+ .remove();
+
+ await waitFor(() => childRemovedCallback.mock.calls[0][0]);
+ expect(childRemovedCallback.mock.calls).toHaveLength(1);
+ expect(childRemovedCallbackSnapshotValue).toBeTruthy();
+ expect(childRemovedCallbackSnapshotValue).toEqual(removedResume);
+
+ await waitFor(() => valueCallback.mock.calls[0][0]);
+ expect(valueCallback.mock.calls).toHaveLength(1);
+ expect(valueCallbackSnapshotValue).toBeTruthy();
+ expect(removedResume.id in valueCallbackSnapshotValue).toBe(false);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.set.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.set.test.js
new file mode 100644
index 000000000..1ac8a1e15
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.set.test.js
@@ -0,0 +1,71 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('inserts data', async () => {
+ FirebaseStub.database().initializeData();
+
+ const existingResume = (
+ await FirebaseStub.database()
+ .ref(
+ `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
+ )
+ .once('value')
+ ).val();
+ expect(existingResume).toBeTruthy();
+
+ const newResume = JSON.parse(JSON.stringify(existingResume));
+ newResume.id = 'newre1';
+ newResume.name = `Test Resume ${newResume.id}`;
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
+ .set(newResume);
+
+ const actualResume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
+ .once('value')
+ ).val();
+ expect(actualResume).toBeTruthy();
+ expect(actualResume).toEqual(newResume);
+});
+
+test('triggers events', async () => {
+ FirebaseStub.database().initializeData();
+
+ let snapshotValue = null;
+ const callback = jest.fn((snapshot) => {
+ snapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(DatabaseConstants.user1.uid)
+ .on('value', callback);
+ await waitFor(() => callback.mock.calls[0][0]);
+ callback.mockClear();
+ snapshotValue = null;
+
+ const existingResume = (
+ await FirebaseStub.database()
+ .ref(
+ `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
+ )
+ .once('value')
+ ).val();
+ expect(existingResume).toBeTruthy();
+
+ const newResume = JSON.parse(JSON.stringify(existingResume));
+ newResume.id = 'newre1';
+ newResume.name = `Test Resume ${newResume.id}`;
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${newResume.id}`)
+ .set(newResume);
+
+ await waitFor(() => callback.mock.calls[0][0]);
+
+ expect(callback.mock.calls).toHaveLength(1);
+ expect(snapshotValue).not.toBeNull();
+ expect(Object.keys(snapshotValue)).toHaveLength(3);
+ expect(snapshotValue[newResume.id]).toBeTruthy();
+ expect(snapshotValue[newResume.id]).toEqual(newResume);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.test.js
new file mode 100644
index 000000000..9ea786b52
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.test.js
@@ -0,0 +1,26 @@
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('reuses existing Reference instance', () => {
+ const ref1 = FirebaseStub.database().ref(
+ `${DatabaseConstants.resumesPath}/123`,
+ );
+ const ref2 = FirebaseStub.database().ref(
+ `${DatabaseConstants.resumesPath}/123`,
+ );
+
+ expect(ref1).toBeTruthy();
+ expect(ref2).toBeTruthy();
+ expect(ref1).toEqual(ref2);
+});
+
+test('leading slash in reference path is ignored', () => {
+ const path = `${DatabaseConstants.resumesPath}/123`;
+
+ const ref1 = FirebaseStub.database().ref(path);
+ expect(ref1).toBeTruthy();
+ expect(ref1.path).toEqual(path);
+
+ const ref2 = FirebaseStub.database().ref(`/${path}`);
+ expect(ref2).toBeTruthy();
+ expect(ref2).toEqual(ref1);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.update.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.update.test.js
new file mode 100644
index 000000000..1c9d30bfc
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.ref.update.test.js
@@ -0,0 +1,86 @@
+import { waitFor } from '@testing-library/react';
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('can spy on it', async () => {
+ FirebaseStub.database().initializeData();
+
+ const referencePath = `${DatabaseConstants.resumesPath}/123456`;
+ const functionSpy = jest.spyOn(
+ FirebaseStub.database().ref(referencePath),
+ 'update',
+ );
+ const updateArgument = 'test value 123';
+
+ await FirebaseStub.database().ref(referencePath).update(updateArgument);
+
+ expect(functionSpy).toHaveBeenCalledTimes(1);
+ const functionCallArgument = functionSpy.mock.calls[0][0];
+ expect(functionCallArgument).toBeTruthy();
+ expect(functionCallArgument).toEqual(updateArgument);
+});
+
+test('updates data', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+ const existingResume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+ expect(existingResume).toBeTruthy();
+
+ const resumeName = 'Test Resume renamed';
+ existingResume.name = resumeName;
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .update(existingResume);
+
+ const actualResume = (
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
+ .once('value')
+ ).val();
+ expect(actualResume).toBeTruthy();
+ expect(existingResume).toEqual(actualResume);
+ expect(actualResume.name).toEqual(resumeName);
+});
+
+test('triggers events', async () => {
+ FirebaseStub.database().initializeData();
+
+ let snapshotValue = null;
+ const callback = jest.fn((snapshot) => {
+ snapshotValue = snapshot.val();
+ });
+ FirebaseStub.database()
+ .ref(DatabaseConstants.resumesPath)
+ .orderByChild('user')
+ .equalTo(DatabaseConstants.user1.uid)
+ .on('value', callback);
+ await waitFor(() => callback.mock.calls[0][0]);
+ callback.mockClear();
+ snapshotValue = null;
+
+ const existingResume = (
+ await FirebaseStub.database()
+ .ref(
+ `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`,
+ )
+ .once('value')
+ ).val();
+ expect(existingResume).toBeTruthy();
+
+ existingResume.name = 'Test Resume renamed';
+ await FirebaseStub.database()
+ .ref(`${DatabaseConstants.resumesPath}/${existingResume.id}`)
+ .update(existingResume);
+
+ await waitFor(() => callback.mock.calls[0][0]);
+
+ expect(callback.mock.calls).toHaveLength(1);
+ expect(snapshotValue).not.toBeNull();
+ expect(Object.keys(snapshotValue)).toHaveLength(2);
+ expect(snapshotValue[existingResume.id]).toBeTruthy();
+ expect(snapshotValue[existingResume.id]).toEqual(existingResume);
+});
diff --git a/__mocks__/__tests__/gatsby-plugin-firebase/database.test.js b/__mocks__/__tests__/gatsby-plugin-firebase/database.test.js
new file mode 100644
index 000000000..8a97c0a94
--- /dev/null
+++ b/__mocks__/__tests__/gatsby-plugin-firebase/database.test.js
@@ -0,0 +1,52 @@
+import FirebaseStub, { DatabaseConstants } from '../../gatsby-plugin-firebase';
+
+test('reuses existing Database instance', () => {
+ const database1 = FirebaseStub.database();
+ const database2 = FirebaseStub.database();
+
+ expect(database1.uuid).toBeTruthy();
+ expect(database2.uuid).toBeTruthy();
+ expect(database1.uuid).toEqual(database2.uuid);
+});
+
+test('ServerValue.TIMESTAMP returns current time in milliseconds', () => {
+ const now = new Date().getTime();
+ const timestamp = FirebaseStub.database.ServerValue.TIMESTAMP;
+
+ expect(timestamp).toBeTruthy();
+ expect(timestamp).toBeGreaterThanOrEqual(now);
+});
+
+test('initializing data sets up resumes and users', async () => {
+ FirebaseStub.database().initializeData();
+
+ const resumesRef = FirebaseStub.database().ref(DatabaseConstants.resumesPath);
+ const resumesDataSnapshot = await resumesRef.once('value');
+ const resumes = resumesDataSnapshot.val();
+ expect(resumes).toBeTruthy();
+ expect(Object.keys(resumes)).toHaveLength(3);
+ const demoStateResume1 = resumes[DatabaseConstants.demoStateResume1Id];
+ expect(demoStateResume1).toBeTruthy();
+ expect(demoStateResume1.id).toEqual(DatabaseConstants.demoStateResume1Id);
+ expect(demoStateResume1.user).toEqual(DatabaseConstants.user1.uid);
+ const demoStateResume2 = resumes[DatabaseConstants.demoStateResume2Id];
+ expect(demoStateResume2).toBeTruthy();
+ expect(demoStateResume2.id).toEqual(DatabaseConstants.demoStateResume2Id);
+ expect(demoStateResume2.user).toEqual(DatabaseConstants.user2.uid);
+ const initialStateResume = resumes[DatabaseConstants.initialStateResumeId];
+ expect(initialStateResume).toBeTruthy();
+ expect(initialStateResume.id).toEqual(DatabaseConstants.initialStateResumeId);
+ expect(initialStateResume.user).toEqual(DatabaseConstants.user1.uid);
+
+ const usersRef = FirebaseStub.database().ref(DatabaseConstants.usersPath);
+ const usersDataSnapshot = await usersRef.once('value');
+ const users = usersDataSnapshot.val();
+ expect(users).toBeTruthy();
+ expect(Object.keys(users)).toHaveLength(2);
+ const anonymousUser1 = users[DatabaseConstants.user1.uid];
+ expect(anonymousUser1).toBeTruthy();
+ expect(anonymousUser1).toEqual(DatabaseConstants.user1);
+ const anonymousUser2 = users[DatabaseConstants.user2.uid];
+ expect(anonymousUser2).toBeTruthy();
+ expect(anonymousUser2).toEqual(DatabaseConstants.user2);
+});
From fd79891a1a4c3dd57c1ab6666940c99b519c0c03 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 14:01:17 +0100
Subject: [PATCH 16/18] Dashboard: unit tests related to rename resume
---
.../__tests__/dashboard.createResume.test.js | 4 +-
.../__tests__/dashboard.deleteResume.test.js | 6 +-
.../dashboard.duplicateResume.test.js | 6 +-
.../__tests__/dashboard.renameResume.test.js | 214 ++++++++++++++++++
.../app/__tests__/dashboard.rendering.test.js | 8 +-
src/pages/app/__tests__/helpers/dashboard.js | 19 +-
6 files changed, 237 insertions(+), 20 deletions(-)
create mode 100644 src/pages/app/__tests__/dashboard.renameResume.test.js
diff --git a/src/pages/app/__tests__/dashboard.createResume.test.js b/src/pages/app/__tests__/dashboard.createResume.test.js
index 72fc0ad64..17a5d6167 100644
--- a/src/pages/app/__tests__/dashboard.createResume.test.js
+++ b/src/pages/app/__tests__/dashboard.createResume.test.js
@@ -15,7 +15,7 @@ import {
waitForModalWindowToHaveBeenClosed,
dismissNotification,
unsplashPhotoResponseUrl,
- setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+ setupWithFetchMockAndWait,
} from './helpers/dashboard';
const tooShortResumeName = 'CV 1';
@@ -23,7 +23,7 @@ const validResumeName = 'Resume for SW development roles';
async function setup() {
const user = DatabaseConstants.user1;
- await setupWithFetchMockAndWaitForLoadingScreenToDisappear(user);
+ await setupWithFetchMockAndWait(user, true);
const dashboardCreateResumeButton = await screen.findByTestId(
createResumeButtonDataTestId,
diff --git a/src/pages/app/__tests__/dashboard.deleteResume.test.js b/src/pages/app/__tests__/dashboard.deleteResume.test.js
index 9d3b39b30..1b84ac1d5 100644
--- a/src/pages/app/__tests__/dashboard.deleteResume.test.js
+++ b/src/pages/app/__tests__/dashboard.deleteResume.test.js
@@ -10,7 +10,7 @@ import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
import {
- setupAndWaitForLoadingScreenToDisappear,
+ setupAndWait,
waitForResumeToDisappearFromPreview,
expectResumeToBeRenderedInPreview,
dismissNotification,
@@ -37,9 +37,7 @@ const expectDatabaseRemoveToHaveCompleted = async (
};
async function setup() {
- const userResumes = await setupAndWaitForLoadingScreenToDisappear(
- DatabaseConstants.user1,
- );
+ const userResumes = await setupAndWait(DatabaseConstants.user1, true);
const [resumeToDelete] = Object.values(userResumes).filter(
(resume) => resume.id === DatabaseConstants.demoStateResume1Id,
diff --git a/src/pages/app/__tests__/dashboard.duplicateResume.test.js b/src/pages/app/__tests__/dashboard.duplicateResume.test.js
index 432714182..9b9c254c9 100644
--- a/src/pages/app/__tests__/dashboard.duplicateResume.test.js
+++ b/src/pages/app/__tests__/dashboard.duplicateResume.test.js
@@ -9,7 +9,7 @@ import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
import {
- setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+ setupWithFetchMockAndWait,
waitForResumeToBeRenderedInPreview,
expectResumeToBeRenderedInPreview,
unsplashPhotoResponseUrl,
@@ -17,9 +17,7 @@ import {
async function setup() {
const user = DatabaseConstants.user1;
- const userResumes = await setupWithFetchMockAndWaitForLoadingScreenToDisappear(
- user,
- );
+ const userResumes = await setupWithFetchMockAndWait(user, true);
const [resumeToDuplicate] = Object.values(userResumes).filter(
(resume) => resume.id === DatabaseConstants.demoStateResume1Id,
diff --git a/src/pages/app/__tests__/dashboard.renameResume.test.js b/src/pages/app/__tests__/dashboard.renameResume.test.js
new file mode 100644
index 000000000..4ad7556f8
--- /dev/null
+++ b/src/pages/app/__tests__/dashboard.renameResume.test.js
@@ -0,0 +1,214 @@
+import {
+ fireEvent,
+ getByText,
+ queryByText,
+ screen,
+ waitFor,
+ waitForElementToBeRemoved,
+} from '@testing-library/react';
+
+import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
+import {
+ setupAndWait,
+ waitForResumeToBeRenderedInPreview,
+ expectResumeToBeRenderedInPreview,
+ dismissNotification,
+ waitForModalWindowToHaveBeenClosed,
+} from './helpers/dashboard';
+
+const tooShortResumeName = 'CV 2';
+const validResumeName = 'Resume for SW development roles - renamed';
+
+const waitForDatabaseUpdateToHaveCompleted = async (
+ mockDatabaseUpdateFunction,
+) => {
+ await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0]);
+ await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
+};
+
+const expectDatabaseUpdateToHaveCompleted = async (
+ mockDatabaseUpdateFunction,
+) => {
+ await waitFor(() =>
+ expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
+ );
+ await waitFor(() =>
+ expect(
+ mockDatabaseUpdateFunction.mock.results[0].value,
+ ).resolves.toBeUndefined(),
+ );
+};
+
+async function setup() {
+ const userResumes = await setupAndWait(DatabaseConstants.user1, true);
+
+ const [resumeToRename] = Object.values(userResumes).filter(
+ (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
+ );
+ const resumeToRenameId = resumeToRename.id;
+
+ const mockDatabaseUpdateFunction = jest.spyOn(
+ FirebaseStub.database().ref(
+ `${DatabaseConstants.resumesPath}/${resumeToRenameId}`,
+ ),
+ 'update',
+ );
+ mockDatabaseUpdateFunction.mockClear();
+
+ const resumeToRenameMenuToggle = await screen.findByTestId(
+ `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToRenameId}`,
+ );
+ fireEvent.click(resumeToRenameMenuToggle);
+
+ const menuItems = screen.getAllByRole('menuitem');
+ let renameMenuItem = null;
+ for (let index = 0; index < menuItems.length; index++) {
+ if (queryByText(menuItems[index], /rename/i)) {
+ renameMenuItem = menuItems[index];
+ break;
+ }
+ }
+ fireEvent.click(renameMenuItem);
+
+ const nameTextBox = screen.getByRole('textbox', { name: /name/i });
+
+ return { resumeToRename, mockDatabaseUpdateFunction, nameTextBox };
+}
+
+async function setupAndSubmit(resumeNewName) {
+ const {
+ resumeToRename,
+ mockDatabaseUpdateFunction,
+ nameTextBox,
+ } = await setup();
+
+ fireEvent.change(nameTextBox, {
+ target: { value: resumeNewName },
+ });
+
+ const modalEditResumeButton = screen.getByRole('button', {
+ name: /edit resume/i,
+ });
+ fireEvent.click(modalEditResumeButton);
+
+ return {
+ renamedResume: resumeToRename,
+ mockDatabaseUpdateFunction,
+ nameTextBox,
+ };
+}
+
+test('renders current name in modal window', async () => {
+ const { resumeToRename, nameTextBox } = await setup();
+
+ expect(nameTextBox).toHaveValue(resumeToRename.name);
+});
+
+describe('with invalid name', () => {
+ test('displays validation error', async () => {
+ const { nameTextBox } = await setup();
+
+ fireEvent.change(nameTextBox, { target: { value: tooShortResumeName } });
+ fireEvent.blur(nameTextBox);
+
+ await waitFor(() =>
+ expect(
+ screen.getByText(/Please enter at least 5 characters/i),
+ ).toBeInTheDocument(),
+ );
+ });
+
+ test('displays notification', async () => {
+ await setupAndSubmit(tooShortResumeName);
+
+ const notification = await screen.findByRole('alert');
+ /*
+ const notification = await screen.findByText(
+ /You might need to fill up all the required fields/i,
+ );
+ */
+ expect(
+ getByText(
+ notification,
+ /You might need to fill up all the required fields/i,
+ ),
+ ).toBeInTheDocument();
+ dismissNotification(notification);
+ });
+});
+
+describe('with valid name', () => {
+ test('renders loading message', async () => {
+ const { mockDatabaseUpdateFunction } = await setupAndSubmit(
+ validResumeName,
+ );
+
+ await waitFor(() =>
+ expect(
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ ).toBeInTheDocument(),
+ );
+ await waitForElementToBeRemoved(() =>
+ screen.getByRole('button', {
+ name: /loading/i,
+ }),
+ );
+
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+ });
+
+ test('closes modal window', async () => {
+ const { mockDatabaseUpdateFunction } = await setupAndSubmit(
+ validResumeName,
+ );
+
+ await waitFor(() =>
+ expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
+ );
+
+ await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+ });
+
+ test('renders renamed resume in preview', async () => {
+ const { mockDatabaseUpdateFunction } = await setupAndSubmit(
+ validResumeName,
+ );
+
+ await waitForModalWindowToHaveBeenClosed();
+ await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+
+ await waitFor(() =>
+ expect(
+ expectResumeToBeRenderedInPreview(validResumeName),
+ ).resolves.toBeUndefined(),
+ );
+ });
+
+ test('updates database', async () => {
+ const now = new Date().getTime();
+ const { renamedResume, mockDatabaseUpdateFunction } = await setupAndSubmit(
+ validResumeName,
+ );
+ const renamedResumeId = renamedResume.id;
+
+ await waitForModalWindowToHaveBeenClosed();
+
+ await expectDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ const mockDatabaseUpdateFunctionCallArgument =
+ mockDatabaseUpdateFunction.mock.calls[0][0];
+ expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(renamedResumeId);
+ expect(mockDatabaseUpdateFunctionCallArgument.name).toBe(validResumeName);
+ expect(
+ mockDatabaseUpdateFunctionCallArgument.updatedAt,
+ ).toBeGreaterThanOrEqual(now);
+
+ await waitForResumeToBeRenderedInPreview(validResumeName);
+ });
+});
diff --git a/src/pages/app/__tests__/dashboard.rendering.test.js b/src/pages/app/__tests__/dashboard.rendering.test.js
index 76271428e..838736771 100644
--- a/src/pages/app/__tests__/dashboard.rendering.test.js
+++ b/src/pages/app/__tests__/dashboard.rendering.test.js
@@ -4,7 +4,7 @@ import { DatabaseConstants } from 'gatsby-plugin-firebase';
import { createResumeButtonDataTestId } from '../../../components/dashboard/CreateResume';
import setup, {
- setupAndWaitForLoadingScreenToDisappear,
+ setupAndWait,
expectResumeToBeRenderedInPreview,
expectLoadingScreenToBeRendered,
waitForLoadingScreenToDisappear,
@@ -20,7 +20,7 @@ it('renders loading screen', async () => {
});
it('renders document title', async () => {
- await setupAndWaitForLoadingScreenToDisappear(user);
+ await setupAndWait(user, true);
await waitFor(() => {
expect(document.title).toEqual('Dashboard | Reactive Resume');
@@ -28,7 +28,7 @@ it('renders document title', async () => {
});
it('renders create resume', async () => {
- await setupAndWaitForLoadingScreenToDisappear(user);
+ await setupAndWait(user, true);
await waitFor(() => {
expect(screen.getByText(/create resume/i)).toBeInTheDocument();
@@ -41,7 +41,7 @@ it('renders create resume', async () => {
});
it('renders preview of user resumes', async () => {
- const userResumes = await setupAndWaitForLoadingScreenToDisappear(user);
+ const userResumes = await setupAndWait(user, true);
expect(Object.keys(userResumes)).toHaveLength(2);
diff --git a/src/pages/app/__tests__/helpers/dashboard.js b/src/pages/app/__tests__/helpers/dashboard.js
index 4eba4f3eb..884ec0ed5 100644
--- a/src/pages/app/__tests__/helpers/dashboard.js
+++ b/src/pages/app/__tests__/helpers/dashboard.js
@@ -133,21 +133,28 @@ async function setup(user) {
return userResumes;
}
-async function setupAndWaitForLoadingScreenToDisappear(user) {
- const userResumes = await _setup(user, true, false);
+async function setupAndWait(user, waitForLoadingScreenToDisappear) {
+ const userResumes = await _setup(
+ user,
+ waitForLoadingScreenToDisappear,
+ false,
+ );
return userResumes;
}
-async function setupWithFetchMockAndWaitForLoadingScreenToDisappear(user) {
- const userResumes = await _setup(user, true, true);
+async function setupWithFetchMockAndWait(
+ user,
+ waitForLoadingScreenToDisappear,
+) {
+ const userResumes = await _setup(user, waitForLoadingScreenToDisappear, true);
return userResumes;
}
export default setup;
export {
- setupAndWaitForLoadingScreenToDisappear,
- setupWithFetchMockAndWaitForLoadingScreenToDisappear,
+ setupAndWait,
+ setupWithFetchMockAndWait,
waitForResumeToBeRenderedInPreview,
waitForResumeToDisappearFromPreview,
expectResumeToBeRenderedInPreview,
From a2b637fa71332c51f71e99e3acb3513b0b27b519 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 14:02:56 +0100
Subject: [PATCH 17/18] Dashboard: unit tests related to rename resume
---
src/pages/app/__tests__/dashboard.renameResume.test.js | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/pages/app/__tests__/dashboard.renameResume.test.js b/src/pages/app/__tests__/dashboard.renameResume.test.js
index 4ad7556f8..b458e1506 100644
--- a/src/pages/app/__tests__/dashboard.renameResume.test.js
+++ b/src/pages/app/__tests__/dashboard.renameResume.test.js
@@ -124,11 +124,6 @@ describe('with invalid name', () => {
await setupAndSubmit(tooShortResumeName);
const notification = await screen.findByRole('alert');
- /*
- const notification = await screen.findByText(
- /You might need to fill up all the required fields/i,
- );
- */
expect(
getByText(
notification,
From f2bc5e36b33f4f3639ca84503f4ad2c024687510 Mon Sep 17 00:00:00 2001
From: gianantoniopini <63844628+gianantoniopini@users.noreply.github.com>
Date: Tue, 2 Feb 2021 14:03:35 +0100
Subject: [PATCH 18/18] Dashboard: removed unit tests related to rename resume
---
.../__tests__/dashboard.renameResume.test.js | 209 ------------------
1 file changed, 209 deletions(-)
delete mode 100644 src/pages/app/__tests__/dashboard.renameResume.test.js
diff --git a/src/pages/app/__tests__/dashboard.renameResume.test.js b/src/pages/app/__tests__/dashboard.renameResume.test.js
deleted file mode 100644
index b458e1506..000000000
--- a/src/pages/app/__tests__/dashboard.renameResume.test.js
+++ /dev/null
@@ -1,209 +0,0 @@
-import {
- fireEvent,
- getByText,
- queryByText,
- screen,
- waitFor,
- waitForElementToBeRemoved,
-} from '@testing-library/react';
-
-import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
-
-import { menuToggleDataTestIdPrefix as resumePreviewMenuToggleDataTestIdPrefix } from '../../../components/dashboard/ResumePreview';
-import {
- setupAndWait,
- waitForResumeToBeRenderedInPreview,
- expectResumeToBeRenderedInPreview,
- dismissNotification,
- waitForModalWindowToHaveBeenClosed,
-} from './helpers/dashboard';
-
-const tooShortResumeName = 'CV 2';
-const validResumeName = 'Resume for SW development roles - renamed';
-
-const waitForDatabaseUpdateToHaveCompleted = async (
- mockDatabaseUpdateFunction,
-) => {
- await waitFor(() => mockDatabaseUpdateFunction.mock.calls[0][0]);
- await waitFor(() => mockDatabaseUpdateFunction.mock.results[0].value);
-};
-
-const expectDatabaseUpdateToHaveCompleted = async (
- mockDatabaseUpdateFunction,
-) => {
- await waitFor(() =>
- expect(mockDatabaseUpdateFunction).toHaveBeenCalledTimes(1),
- );
- await waitFor(() =>
- expect(
- mockDatabaseUpdateFunction.mock.results[0].value,
- ).resolves.toBeUndefined(),
- );
-};
-
-async function setup() {
- const userResumes = await setupAndWait(DatabaseConstants.user1, true);
-
- const [resumeToRename] = Object.values(userResumes).filter(
- (resume) => resume.id === DatabaseConstants.demoStateResume1Id,
- );
- const resumeToRenameId = resumeToRename.id;
-
- const mockDatabaseUpdateFunction = jest.spyOn(
- FirebaseStub.database().ref(
- `${DatabaseConstants.resumesPath}/${resumeToRenameId}`,
- ),
- 'update',
- );
- mockDatabaseUpdateFunction.mockClear();
-
- const resumeToRenameMenuToggle = await screen.findByTestId(
- `${resumePreviewMenuToggleDataTestIdPrefix}${resumeToRenameId}`,
- );
- fireEvent.click(resumeToRenameMenuToggle);
-
- const menuItems = screen.getAllByRole('menuitem');
- let renameMenuItem = null;
- for (let index = 0; index < menuItems.length; index++) {
- if (queryByText(menuItems[index], /rename/i)) {
- renameMenuItem = menuItems[index];
- break;
- }
- }
- fireEvent.click(renameMenuItem);
-
- const nameTextBox = screen.getByRole('textbox', { name: /name/i });
-
- return { resumeToRename, mockDatabaseUpdateFunction, nameTextBox };
-}
-
-async function setupAndSubmit(resumeNewName) {
- const {
- resumeToRename,
- mockDatabaseUpdateFunction,
- nameTextBox,
- } = await setup();
-
- fireEvent.change(nameTextBox, {
- target: { value: resumeNewName },
- });
-
- const modalEditResumeButton = screen.getByRole('button', {
- name: /edit resume/i,
- });
- fireEvent.click(modalEditResumeButton);
-
- return {
- renamedResume: resumeToRename,
- mockDatabaseUpdateFunction,
- nameTextBox,
- };
-}
-
-test('renders current name in modal window', async () => {
- const { resumeToRename, nameTextBox } = await setup();
-
- expect(nameTextBox).toHaveValue(resumeToRename.name);
-});
-
-describe('with invalid name', () => {
- test('displays validation error', async () => {
- const { nameTextBox } = await setup();
-
- fireEvent.change(nameTextBox, { target: { value: tooShortResumeName } });
- fireEvent.blur(nameTextBox);
-
- await waitFor(() =>
- expect(
- screen.getByText(/Please enter at least 5 characters/i),
- ).toBeInTheDocument(),
- );
- });
-
- test('displays notification', async () => {
- await setupAndSubmit(tooShortResumeName);
-
- const notification = await screen.findByRole('alert');
- expect(
- getByText(
- notification,
- /You might need to fill up all the required fields/i,
- ),
- ).toBeInTheDocument();
- dismissNotification(notification);
- });
-});
-
-describe('with valid name', () => {
- test('renders loading message', async () => {
- const { mockDatabaseUpdateFunction } = await setupAndSubmit(
- validResumeName,
- );
-
- await waitFor(() =>
- expect(
- screen.getByRole('button', {
- name: /loading/i,
- }),
- ).toBeInTheDocument(),
- );
- await waitForElementToBeRemoved(() =>
- screen.getByRole('button', {
- name: /loading/i,
- }),
- );
-
- await waitForModalWindowToHaveBeenClosed();
- await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
- await waitForResumeToBeRenderedInPreview(validResumeName);
- });
-
- test('closes modal window', async () => {
- const { mockDatabaseUpdateFunction } = await setupAndSubmit(
- validResumeName,
- );
-
- await waitFor(() =>
- expect(waitForModalWindowToHaveBeenClosed()).resolves.toBeUndefined(),
- );
-
- await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
- await waitForResumeToBeRenderedInPreview(validResumeName);
- });
-
- test('renders renamed resume in preview', async () => {
- const { mockDatabaseUpdateFunction } = await setupAndSubmit(
- validResumeName,
- );
-
- await waitForModalWindowToHaveBeenClosed();
- await waitForDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
-
- await waitFor(() =>
- expect(
- expectResumeToBeRenderedInPreview(validResumeName),
- ).resolves.toBeUndefined(),
- );
- });
-
- test('updates database', async () => {
- const now = new Date().getTime();
- const { renamedResume, mockDatabaseUpdateFunction } = await setupAndSubmit(
- validResumeName,
- );
- const renamedResumeId = renamedResume.id;
-
- await waitForModalWindowToHaveBeenClosed();
-
- await expectDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
- const mockDatabaseUpdateFunctionCallArgument =
- mockDatabaseUpdateFunction.mock.calls[0][0];
- expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(renamedResumeId);
- expect(mockDatabaseUpdateFunctionCallArgument.name).toBe(validResumeName);
- expect(
- mockDatabaseUpdateFunctionCallArgument.updatedAt,
- ).toBeGreaterThanOrEqual(now);
-
- await waitForResumeToBeRenderedInPreview(validResumeName);
- });
-});