mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-19 03:01:53 +10:00
Merge pull request #423 from gianantoniopini/develop
Unit testing environment set up and addition of some unit tests
This commit is contained in:
@ -8,8 +8,13 @@
|
|||||||
"FileReader": true,
|
"FileReader": true,
|
||||||
"localStorage": true
|
"localStorage": true
|
||||||
},
|
},
|
||||||
"extends": ["airbnb", "prettier"],
|
"extends": [
|
||||||
"plugins": ["prettier"],
|
"airbnb",
|
||||||
|
"plugin:jest/recommended",
|
||||||
|
"plugin:jest/style",
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"plugins": ["jest", "prettier"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
||||||
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
|
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -20,6 +20,9 @@ coverage
|
|||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|
||||||
|
# Coverage directory used by Jest
|
||||||
|
test-coverage
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
|
|||||||
555
__mocks__/__tests__/gatsby-plugin-firebase.test.js
Normal file
555
__mocks__/__tests__/gatsby-plugin-firebase.test.js
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
import { waitFor } from '@testing-library/react';
|
||||||
|
import FirebaseStub, {
|
||||||
|
AuthConstants,
|
||||||
|
DatabaseConstants,
|
||||||
|
} from '../gatsby-plugin-firebase';
|
||||||
|
|
||||||
|
describe('FirebaseStub', () => {
|
||||||
|
describe('auth', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
FirebaseStub.auth().dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
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).toHaveLength(1);
|
||||||
|
expect(FirebaseStub.auth().onAuthStateChangedObservers[0]).toEqual(
|
||||||
|
observer,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsubscribe();
|
||||||
|
|
||||||
|
expect(FirebaseStub.auth().onAuthStateChangedObservers).toHaveLength(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', async () => {
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
2
__mocks__/file-mock.js
Normal file
2
__mocks__/file-mock.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const mockFile = 'test-file-stub';
|
||||||
|
export default mockFile;
|
||||||
24
__mocks__/gatsby-plugin-firebase.js
Normal file
24
__mocks__/gatsby-plugin-firebase.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import Auth from './gatsby-plugin-firebase/auth/auth';
|
||||||
|
import Database from './gatsby-plugin-firebase/database/database';
|
||||||
|
import AuthConstants from './gatsby-plugin-firebase/constants/auth';
|
||||||
|
import DatabaseConstants from './gatsby-plugin-firebase/constants/database';
|
||||||
|
|
||||||
|
class FirebaseStub {
|
||||||
|
static auth() {
|
||||||
|
return Auth.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static database() {
|
||||||
|
return Database.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FirebaseStub.database.ServerValue = {};
|
||||||
|
Object.defineProperty(FirebaseStub.database.ServerValue, 'TIMESTAMP', {
|
||||||
|
get() {
|
||||||
|
return new Date().getTime();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default FirebaseStub;
|
||||||
|
export { AuthConstants, DatabaseConstants };
|
||||||
58
__mocks__/gatsby-plugin-firebase/auth/auth.js
Normal file
58
__mocks__/gatsby-plugin-firebase/auth/auth.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
import Constants from '../constants/auth';
|
||||||
|
|
||||||
|
const singleton = Symbol('');
|
||||||
|
const singletonEnforcer = Symbol('');
|
||||||
|
|
||||||
|
class Auth {
|
||||||
|
constructor(enforcer) {
|
||||||
|
if (enforcer !== singletonEnforcer) {
|
||||||
|
throw new Error('Cannot construct singleton');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._uuid = uuidv4();
|
||||||
|
this._onAuthStateChangedObservers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get instance() {
|
||||||
|
if (!this[singleton]) {
|
||||||
|
this[singleton] = new Auth(singletonEnforcer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this[singleton];
|
||||||
|
}
|
||||||
|
|
||||||
|
get uuid() {
|
||||||
|
return this._uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get onAuthStateChangedObservers() {
|
||||||
|
return this._onAuthStateChangedObservers;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
this._onAuthStateChangedObservers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
onAuthStateChanged(observer) {
|
||||||
|
this.onAuthStateChangedObservers.push(observer);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this._onAuthStateChangedObservers = this.onAuthStateChangedObservers.filter(
|
||||||
|
(obs) => obs !== observer,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async signInAnonymously() {
|
||||||
|
const user = Constants.anonymousUser1;
|
||||||
|
|
||||||
|
this.onAuthStateChangedObservers.forEach((observer) => observer(user));
|
||||||
|
|
||||||
|
return Promise.resolve(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Auth;
|
||||||
27
__mocks__/gatsby-plugin-firebase/constants/auth.js
Normal file
27
__mocks__/gatsby-plugin-firebase/constants/auth.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const anonymousUser1 = {
|
||||||
|
displayName: 'Anonymous User 1',
|
||||||
|
email: 'anonymous1@noemail.com',
|
||||||
|
isAnonymous: true,
|
||||||
|
name: 'Anonymous 1',
|
||||||
|
uid: 'anonym123',
|
||||||
|
};
|
||||||
|
|
||||||
|
const anonymousUser2 = {
|
||||||
|
displayName: 'Anonymous User 2',
|
||||||
|
email: 'anonymous2@noemail.com',
|
||||||
|
isAnonymous: true,
|
||||||
|
name: 'Anonymous 2',
|
||||||
|
uid: 'anonym456',
|
||||||
|
};
|
||||||
|
|
||||||
|
class Auth {
|
||||||
|
static get anonymousUser1() {
|
||||||
|
return anonymousUser1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get anonymousUser2() {
|
||||||
|
return anonymousUser2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Auth;
|
||||||
65
__mocks__/gatsby-plugin-firebase/constants/database.js
Normal file
65
__mocks__/gatsby-plugin-firebase/constants/database.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import AuthConstants from './auth';
|
||||||
|
|
||||||
|
const valueEventType = 'value';
|
||||||
|
const childRemovedEventType = 'child_removed';
|
||||||
|
|
||||||
|
const resumesPath = 'resumes';
|
||||||
|
const usersPath = 'users';
|
||||||
|
const connectedPath = '.info/connected';
|
||||||
|
|
||||||
|
const demoStateResume1Id = 'demo_1';
|
||||||
|
const demoStateResume2Id = 'demo_2';
|
||||||
|
const initialStateResumeId = 'initst';
|
||||||
|
|
||||||
|
const user1 = {
|
||||||
|
uid: AuthConstants.anonymousUser1.uid,
|
||||||
|
isAnonymous: AuthConstants.anonymousUser1.isAnonymous,
|
||||||
|
};
|
||||||
|
const user2 = {
|
||||||
|
uid: AuthConstants.anonymousUser2.uid,
|
||||||
|
isAnonymous: AuthConstants.anonymousUser2.isAnonymous,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
static get valueEventType() {
|
||||||
|
return valueEventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get childRemovedEventType() {
|
||||||
|
return childRemovedEventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get resumesPath() {
|
||||||
|
return resumesPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get usersPath() {
|
||||||
|
return usersPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get connectedPath() {
|
||||||
|
return connectedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get demoStateResume1Id() {
|
||||||
|
return demoStateResume1Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get demoStateResume2Id() {
|
||||||
|
return demoStateResume2Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get initialStateResumeId() {
|
||||||
|
return initialStateResumeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get user1() {
|
||||||
|
return user1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get user2() {
|
||||||
|
return user2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Database;
|
||||||
24
__mocks__/gatsby-plugin-firebase/database/dataSnapshot.js
Normal file
24
__mocks__/gatsby-plugin-firebase/database/dataSnapshot.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
class DataSnapshot {
|
||||||
|
constructor(getData, value = undefined) {
|
||||||
|
if (!getData) {
|
||||||
|
throw new Error('getData must be provided.');
|
||||||
|
} else if (typeof getData !== 'function') {
|
||||||
|
throw new Error('getData should be a function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._getData = getData;
|
||||||
|
|
||||||
|
this._value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
val() {
|
||||||
|
return typeof this.value !== 'undefined' ? this.value : this._getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DataSnapshot;
|
||||||
156
__mocks__/gatsby-plugin-firebase/database/database.js
Normal file
156
__mocks__/gatsby-plugin-firebase/database/database.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
import DatabaseConstants from '../constants/database';
|
||||||
|
import Reference from './reference';
|
||||||
|
|
||||||
|
const singleton = Symbol('');
|
||||||
|
const singletonEnforcer = Symbol('');
|
||||||
|
|
||||||
|
const readFile = (fileRelativePath) => {
|
||||||
|
const fileAbsolutePath = path.resolve(__dirname, fileRelativePath);
|
||||||
|
const fileBuffer = fs.readFileSync(fileAbsolutePath);
|
||||||
|
const fileData = JSON.parse(fileBuffer);
|
||||||
|
return fileData;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
constructor(enforcer) {
|
||||||
|
if (enforcer !== singletonEnforcer) {
|
||||||
|
throw new Error('Cannot construct singleton');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._uuid = uuidv4();
|
||||||
|
this._data = {};
|
||||||
|
this._references = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get instance() {
|
||||||
|
if (!this[singleton]) {
|
||||||
|
this[singleton] = new Database(singletonEnforcer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this[singleton];
|
||||||
|
}
|
||||||
|
|
||||||
|
get uuid() {
|
||||||
|
return this._uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getData(dataPath) {
|
||||||
|
if (!dataPath) {
|
||||||
|
throw new Error('dataPath must be provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataPathElements = dataPath.split('/');
|
||||||
|
if (!(dataPathElements[0] in this._data)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataPathElements.length === 1) {
|
||||||
|
return this._data[dataPathElements[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataPathElements.length === 2) {
|
||||||
|
if (!(dataPathElements[1] in this._data[dataPathElements[0]])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._data[dataPathElements[0]][dataPathElements[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getReference(referencePath) {
|
||||||
|
return referencePath in this._references
|
||||||
|
? this._references[referencePath]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setData(dataPath, value) {
|
||||||
|
if (!dataPath) {
|
||||||
|
throw new Error('dataPath must be provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
throw new Error('value is undefined.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataPathElements = dataPath.split('/');
|
||||||
|
if (dataPathElements.length !== 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dataPathElements[0] in this._data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataPathElements[1]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
delete this._data[dataPathElements[0]][dataPathElements[1]];
|
||||||
|
} else {
|
||||||
|
this._data[dataPathElements[0]][dataPathElements[1]] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeData() {
|
||||||
|
const resumes = {};
|
||||||
|
|
||||||
|
const demoStateResume1 = readFile('../../../src/data/demoState.json');
|
||||||
|
const date = new Date('December 15, 2020 11:20:25');
|
||||||
|
demoStateResume1.updatedAt = date.valueOf();
|
||||||
|
date.setMonth(date.getMonth() - 2);
|
||||||
|
demoStateResume1.createdAt = date.valueOf();
|
||||||
|
demoStateResume1.user = DatabaseConstants.user1.uid;
|
||||||
|
resumes[DatabaseConstants.demoStateResume1Id] = demoStateResume1;
|
||||||
|
|
||||||
|
const demoStateResume2 = JSON.parse(JSON.stringify(demoStateResume1));
|
||||||
|
demoStateResume2.user = DatabaseConstants.user2.uid;
|
||||||
|
resumes[DatabaseConstants.demoStateResume2Id] = demoStateResume2;
|
||||||
|
|
||||||
|
const initialStateResume = readFile('../../../src/data/initialState.json');
|
||||||
|
initialStateResume.updatedAt = date.valueOf();
|
||||||
|
initialStateResume.createdAt = date.valueOf();
|
||||||
|
initialStateResume.user = DatabaseConstants.user1.uid;
|
||||||
|
resumes[DatabaseConstants.initialStateResumeId] = initialStateResume;
|
||||||
|
|
||||||
|
Object.keys(resumes).forEach((key) => {
|
||||||
|
const resume = resumes[key];
|
||||||
|
resume.id = key;
|
||||||
|
resume.name = `Test Resume ${key}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._data[DatabaseConstants.resumesPath] = resumes;
|
||||||
|
|
||||||
|
const users = {};
|
||||||
|
users[DatabaseConstants.user1.uid] = DatabaseConstants.user1;
|
||||||
|
users[DatabaseConstants.user2.uid] = DatabaseConstants.user2;
|
||||||
|
this._data[DatabaseConstants.usersPath] = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref(referencePath) {
|
||||||
|
const newRef = new Reference(
|
||||||
|
referencePath,
|
||||||
|
(dataPath) => this._getData(dataPath),
|
||||||
|
(dataPath, value) => this._setData(dataPath, value),
|
||||||
|
(refPath) => this._getReference(refPath),
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingRef = this._getReference(newRef.path);
|
||||||
|
if (existingRef) {
|
||||||
|
existingRef.initializeQueryParameters();
|
||||||
|
return existingRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._references[newRef.path] = newRef;
|
||||||
|
return newRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Database;
|
||||||
213
__mocks__/gatsby-plugin-firebase/database/reference.js
Normal file
213
__mocks__/gatsby-plugin-firebase/database/reference.js
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
|
import DatabaseConstants from '../constants/database';
|
||||||
|
import DataSnapshot from './dataSnapshot';
|
||||||
|
|
||||||
|
const parsePath = (path) => {
|
||||||
|
if (!path) {
|
||||||
|
throw new Error('path must be provided.');
|
||||||
|
} else if (typeof path !== 'string') {
|
||||||
|
throw new Error('path should be a string.');
|
||||||
|
} else {
|
||||||
|
let parsedPath = path.trim();
|
||||||
|
|
||||||
|
if (parsedPath[0] === '/') {
|
||||||
|
parsedPath = parsedPath.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedPath;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Reference {
|
||||||
|
constructor(path, getDatabaseData, setDatabaseData, getReference) {
|
||||||
|
this._path = parsePath(path);
|
||||||
|
|
||||||
|
this._uuid = uuidv4();
|
||||||
|
|
||||||
|
if (this.path === DatabaseConstants.connectedPath) {
|
||||||
|
this._dataSnapshot = new DataSnapshot(() => {}, true);
|
||||||
|
} else {
|
||||||
|
this._dataSnapshot = new DataSnapshot(() => this._getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getDatabaseData) {
|
||||||
|
throw new Error('getDatabaseData must be provided.');
|
||||||
|
} else if (typeof getDatabaseData !== 'function') {
|
||||||
|
throw new Error('getDatabaseData should be a function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._getDatabaseData = getDatabaseData;
|
||||||
|
|
||||||
|
if (!setDatabaseData) {
|
||||||
|
throw new Error('setDatabaseData must be provided.');
|
||||||
|
} else if (typeof getDatabaseData !== 'function') {
|
||||||
|
throw new Error('setDatabaseData should be a function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setDatabaseData = setDatabaseData;
|
||||||
|
|
||||||
|
if (!getReference) {
|
||||||
|
throw new Error('getReference must be provided.');
|
||||||
|
} else if (typeof getDatabaseData !== 'function') {
|
||||||
|
throw new Error('getReference should be a function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._getReference = getReference;
|
||||||
|
|
||||||
|
this._eventCallbacks = {};
|
||||||
|
|
||||||
|
this.initializeQueryParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
get path() {
|
||||||
|
return this._path;
|
||||||
|
}
|
||||||
|
|
||||||
|
get uuid() {
|
||||||
|
return this._uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
get eventCallbacks() {
|
||||||
|
return this._eventCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
get orderByChildPath() {
|
||||||
|
return this._orderByChildPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
get equalToValue() {
|
||||||
|
return this._equalToValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getData() {
|
||||||
|
const databaseData = this._getDatabaseData(this.path);
|
||||||
|
|
||||||
|
if (!databaseData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.orderByChildPath && this.equalToValue) {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(databaseData).filter(
|
||||||
|
([, value]) => value[this.orderByChildPath] === this.equalToValue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return databaseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getParent() {
|
||||||
|
const pathElements = this.path.split('/');
|
||||||
|
|
||||||
|
let parent = null;
|
||||||
|
if (pathElements.length === 2) {
|
||||||
|
parent = this._getReference(pathElements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDataUpdate(value) {
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
throw new Error('value must be provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentData = this._getData();
|
||||||
|
const parentReference = this._getParent();
|
||||||
|
|
||||||
|
this._setDatabaseData(this.path, value);
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
if (parentReference) {
|
||||||
|
parentReference.triggerEventCallback(
|
||||||
|
DatabaseConstants.childRemovedEventType,
|
||||||
|
currentData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.triggerEventCallback(DatabaseConstants.valueEventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentReference) {
|
||||||
|
parentReference.triggerEventCallback(DatabaseConstants.valueEventType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEventCallback(eventType, snapshotValue = undefined) {
|
||||||
|
if (!(eventType in this.eventCallbacks)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const snapshot =
|
||||||
|
this.path === DatabaseConstants.connectedPath
|
||||||
|
? this._dataSnapshot
|
||||||
|
: new DataSnapshot(() => this._getData(), snapshotValue);
|
||||||
|
|
||||||
|
const debouncedEventCallback = debounce(
|
||||||
|
this.eventCallbacks[eventType],
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
debouncedEventCallback(snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
equalTo(value) {
|
||||||
|
this._equalToValue = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeQueryParameters() {
|
||||||
|
this._orderByChildPath = '';
|
||||||
|
this._equalToValue = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
off() {
|
||||||
|
this._eventCallbacks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
on(eventType, callback) {
|
||||||
|
this.eventCallbacks[eventType] = callback;
|
||||||
|
|
||||||
|
if (eventType === DatabaseConstants.valueEventType) {
|
||||||
|
this.triggerEventCallback(eventType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async once(eventType) {
|
||||||
|
if (!eventType) {
|
||||||
|
throw new Error('eventType must be provided.');
|
||||||
|
} else if (typeof eventType !== 'string') {
|
||||||
|
throw new Error('eventType should be a string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(this._dataSnapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
orderByChild(path) {
|
||||||
|
this._orderByChildPath = path;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(value) {
|
||||||
|
this._handleDataUpdate(value);
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove() {
|
||||||
|
this._handleDataUpdate(null);
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(value) {
|
||||||
|
this._handleDataUpdate(value);
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Reference;
|
||||||
80
__mocks__/gatsby.js
Normal file
80
__mocks__/gatsby.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Gatsby = jest.requireActual('gatsby');
|
||||||
|
|
||||||
|
const fluidImageShapes = [
|
||||||
|
{
|
||||||
|
aspectRatio: 2,
|
||||||
|
src: 'test_image.jpg',
|
||||||
|
srcSet: 'some srcSet',
|
||||||
|
srcSetWebp: 'some srcSetWebp',
|
||||||
|
sizes: '(max-width: 600px) 100vw, 600px',
|
||||||
|
base64: 'string_of_base64',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
aspectRatio: 3,
|
||||||
|
src: 'test_image_2.jpg',
|
||||||
|
srcSet: 'some other srcSet',
|
||||||
|
srcSetWebp: 'some other srcSetWebp',
|
||||||
|
sizes: '(max-width: 400px) 100vw, 400px',
|
||||||
|
base64: 'string_of_base64',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const useStaticQuery = () => ({
|
||||||
|
site: {
|
||||||
|
siteMetadata: {
|
||||||
|
title: 'Test title',
|
||||||
|
description: 'Test description',
|
||||||
|
author: 'Test author',
|
||||||
|
siteUrl: 'https://testsiteurl/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onyx: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pikachu: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gengar: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
castform: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
glalie: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
celebi: {
|
||||||
|
childImageSharp: {
|
||||||
|
fluid: fluidImageShapes[1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...Gatsby,
|
||||||
|
graphql: jest.fn(),
|
||||||
|
Link: jest.fn().mockImplementation(({ to, ...rest }) =>
|
||||||
|
React.createElement('a', {
|
||||||
|
...rest,
|
||||||
|
href: to,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
useStaticQuery,
|
||||||
|
};
|
||||||
5
jest-preprocess.js
Normal file
5
jest-preprocess.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const babelOptions = {
|
||||||
|
presets: ['babel-preset-gatsby'],
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = require('babel-jest').createTransformer(babelOptions);
|
||||||
36
jest.config.js
Normal file
36
jest.config.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
module.exports = {
|
||||||
|
testRegex: '/*.test.js$',
|
||||||
|
collectCoverage: true,
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'**/*.{js,jsx}',
|
||||||
|
'!\\.cache/**',
|
||||||
|
'!node_modules/**',
|
||||||
|
'!public/**',
|
||||||
|
'!test-coverage/**',
|
||||||
|
],
|
||||||
|
coverageDirectory: 'test-coverage',
|
||||||
|
coverageThreshold: {
|
||||||
|
global: {
|
||||||
|
branches: 0,
|
||||||
|
functions: 0,
|
||||||
|
lines: 0,
|
||||||
|
statements: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
verbose: true,
|
||||||
|
transform: {
|
||||||
|
'^.+\\.jsx?$': `<rootDir>/jest-preprocess.js`,
|
||||||
|
},
|
||||||
|
moduleNameMapper: {
|
||||||
|
'.+\\.(css|styl|less|sass|scss)$': `identity-obj-proxy`,
|
||||||
|
'.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `<rootDir>/__mocks__/file-mock.js`,
|
||||||
|
},
|
||||||
|
testPathIgnorePatterns: [`node_modules`, `\\.cache`],
|
||||||
|
transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
|
||||||
|
globals: {
|
||||||
|
__PATH_PREFIX__: ``,
|
||||||
|
},
|
||||||
|
testURL: `http://localhost`,
|
||||||
|
setupFiles: [`<rootDir>/loadershim.js`],
|
||||||
|
setupFilesAfterEnv: [`<rootDir>/jest.setup.js`],
|
||||||
|
};
|
||||||
1
jest.setup.js
Normal file
1
jest.setup.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
3
loadershim.js
Normal file
3
loadershim.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
global.___loader = {
|
||||||
|
enqueue: jest.fn(),
|
||||||
|
};
|
||||||
4884
package-lock.json
generated
4884
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -7,13 +7,14 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint --fix .",
|
"lint:fix": "eslint --fix .",
|
||||||
|
"prebuild": "npm run test",
|
||||||
"build": "gatsby build",
|
"build": "gatsby build",
|
||||||
"develop": "gatsby develop",
|
"develop": "gatsby develop",
|
||||||
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
|
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
|
||||||
"start": "npm run develop",
|
"start": "npm run develop",
|
||||||
"serve": "gatsby serve",
|
"serve": "gatsby serve",
|
||||||
"clean": "gatsby clean",
|
"clean": "gatsby clean",
|
||||||
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.2",
|
"@material-ui/core": "^4.11.2",
|
||||||
@ -61,14 +62,21 @@
|
|||||||
"yup": "^0.32.8"
|
"yup": "^0.32.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^5.11.8",
|
||||||
|
"@testing-library/react": "^11.2.3",
|
||||||
|
"babel-jest": "^26.6.3",
|
||||||
|
"babel-preset-gatsby": "^0.10.0",
|
||||||
"eslint": "^7.17.0",
|
"eslint": "^7.17.0",
|
||||||
"eslint-config-airbnb": "^18.2.1",
|
"eslint-config-airbnb": "^18.2.1",
|
||||||
"eslint-config-prettier": "^7.1.0",
|
"eslint-config-prettier": "^7.1.0",
|
||||||
"eslint-loader": "^4.0.2",
|
"eslint-loader": "^4.0.2",
|
||||||
|
"eslint-plugin-jest": "^24.1.3",
|
||||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-react": "^7.22.0",
|
"eslint-plugin-react": "^7.22.0",
|
||||||
"gatsby-plugin-eslint": "^2.0.8",
|
"gatsby-plugin-eslint": "^2.0.8",
|
||||||
|
"identity-obj-proxy": "^3.0.0",
|
||||||
|
"jest": "^26.6.3",
|
||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
"stylelint": "^13.8.0",
|
"stylelint": "^13.8.0",
|
||||||
"stylelint-config-standard": "^20.0.0",
|
"stylelint-config-standard": "^20.0.0",
|
||||||
|
|||||||
@ -128,4 +128,7 @@ export default DatabaseContext;
|
|||||||
|
|
||||||
const memoizedProvider = memo(DatabaseProvider);
|
const memoizedProvider = memo(DatabaseProvider);
|
||||||
|
|
||||||
export { memoizedProvider as DatabaseProvider };
|
export {
|
||||||
|
memoizedProvider as DatabaseProvider,
|
||||||
|
DEBOUNCE_WAIT_TIME as DebounceWaitTime,
|
||||||
|
};
|
||||||
|
|||||||
147
src/pages/app/__tests__/builder.test.js
Normal file
147
src/pages/app/__tests__/builder.test.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
act,
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
|
||||||
|
import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
|
||||||
|
|
||||||
|
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 Builder from '../builder';
|
||||||
|
|
||||||
|
describe('Builder', () => {
|
||||||
|
let resumeId = null;
|
||||||
|
let resume = null;
|
||||||
|
let mockUpdateFunction = null;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
FirebaseStub.database().initializeData();
|
||||||
|
|
||||||
|
resumeId = DatabaseConstants.demoStateResume1Id;
|
||||||
|
resume = (
|
||||||
|
await FirebaseStub.database()
|
||||||
|
.ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
|
||||||
|
.once('value')
|
||||||
|
).val();
|
||||||
|
mockUpdateFunction = jest.spyOn(
|
||||||
|
FirebaseStub.database().ref(
|
||||||
|
`${DatabaseConstants.resumesPath}/${resumeId}`,
|
||||||
|
),
|
||||||
|
'update',
|
||||||
|
);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<SettingsProvider>
|
||||||
|
<ModalProvider>
|
||||||
|
<UserProvider>
|
||||||
|
<DatabaseProvider>
|
||||||
|
<ResumeProvider>
|
||||||
|
<StorageProvider>
|
||||||
|
<Builder id={resume.id} />
|
||||||
|
</StorageProvider>
|
||||||
|
</ResumeProvider>
|
||||||
|
</DatabaseProvider>
|
||||||
|
</UserProvider>
|
||||||
|
</ModalProvider>
|
||||||
|
</SettingsProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await FirebaseStub.auth().signInAnonymously();
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => mockUpdateFunction.mock.calls[0][0], {
|
||||||
|
timeout: DebounceWaitTime,
|
||||||
|
});
|
||||||
|
mockUpdateFunction.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('renders', () => {
|
||||||
|
it('first and last name', async () => {
|
||||||
|
expect(
|
||||||
|
screen.getByLabelText(new RegExp('first name', 'i')),
|
||||||
|
).toHaveDisplayValue(resume.profile.firstName);
|
||||||
|
expect(
|
||||||
|
screen.getByLabelText(new RegExp('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('updates data', () => {
|
||||||
|
it('when input value is changed', async () => {
|
||||||
|
const input = screen.getByLabelText(new RegExp('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 waitFor(() => mockUpdateFunction.mock.calls[0][0], {
|
||||||
|
timeout: DebounceWaitTime,
|
||||||
|
});
|
||||||
|
expect(mockUpdateFunction).toHaveBeenCalledTimes(1);
|
||||||
|
const mockUpdateFunctionCallArgument =
|
||||||
|
mockUpdateFunction.mock.calls[0][0];
|
||||||
|
expect(mockUpdateFunctionCallArgument.id).toBe(resume.id);
|
||||||
|
expect(mockUpdateFunctionCallArgument.profile.address.line1).toBe(
|
||||||
|
newInputValue,
|
||||||
|
);
|
||||||
|
expect(mockUpdateFunctionCallArgument.updatedAt).toBeGreaterThanOrEqual(
|
||||||
|
now,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('settings', () => {
|
||||||
|
it('allow to change the language', async () => {
|
||||||
|
const languageSelectElement = screen.getByLabelText('Language');
|
||||||
|
const newLanguage = 'it';
|
||||||
|
const now = new Date().getTime();
|
||||||
|
|
||||||
|
fireEvent.change(languageSelectElement, {
|
||||||
|
target: { value: newLanguage },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(languageSelectElement).toHaveValue(newLanguage);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByLabelText(new RegExp('date of birth', 'i')),
|
||||||
|
).toBeNull();
|
||||||
|
expect(
|
||||||
|
screen.getByLabelText(new RegExp('data di nascita', 'i')),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
await waitFor(() => mockUpdateFunction.mock.calls[0][0], {
|
||||||
|
timeout: DebounceWaitTime,
|
||||||
|
});
|
||||||
|
expect(mockUpdateFunction).toHaveBeenCalledTimes(1);
|
||||||
|
const mockUpdateFunctionCallArgument =
|
||||||
|
mockUpdateFunction.mock.calls[0][0];
|
||||||
|
expect(mockUpdateFunctionCallArgument.id).toBe(resume.id);
|
||||||
|
expect(mockUpdateFunctionCallArgument.metadata.language).toBe(
|
||||||
|
newLanguage,
|
||||||
|
);
|
||||||
|
expect(mockUpdateFunctionCallArgument.updatedAt).toBeGreaterThanOrEqual(
|
||||||
|
now,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
76
src/pages/app/__tests__/dashboard.test.js
Normal file
76
src/pages/app/__tests__/dashboard.test.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { act, render, screen, waitFor } from '@testing-library/react';
|
||||||
|
|
||||||
|
import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
|
||||||
|
|
||||||
|
import '../../../i18n/index';
|
||||||
|
import '../../../utils/dayjs';
|
||||||
|
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 Dashboard from '../dashboard';
|
||||||
|
|
||||||
|
describe('Dashboard', () => {
|
||||||
|
let resumes = null;
|
||||||
|
const user = DatabaseConstants.user1;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
FirebaseStub.database().initializeData();
|
||||||
|
|
||||||
|
resumes = (
|
||||||
|
await FirebaseStub.database()
|
||||||
|
.ref(DatabaseConstants.resumesPath)
|
||||||
|
.orderByChild('user')
|
||||||
|
.equalTo(user.uid)
|
||||||
|
.once('value')
|
||||||
|
).val();
|
||||||
|
|
||||||
|
render(
|
||||||
|
<SettingsProvider>
|
||||||
|
<ModalProvider>
|
||||||
|
<UserProvider>
|
||||||
|
<DatabaseProvider>
|
||||||
|
<ResumeProvider>
|
||||||
|
<StorageProvider>
|
||||||
|
<Dashboard user={user} />
|
||||||
|
</StorageProvider>
|
||||||
|
</ResumeProvider>
|
||||||
|
</DatabaseProvider>
|
||||||
|
</UserProvider>
|
||||||
|
</ModalProvider>
|
||||||
|
</SettingsProvider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await FirebaseStub.auth().signInAnonymously();
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => screen.getByText('Create Resume'));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('renders', () => {
|
||||||
|
it('document title', async () => {
|
||||||
|
expect(document.title).toEqual('Dashboard | Reactive Resume');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create resume', async () => {
|
||||||
|
expect(screen.getByText('Create Resume')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preview of user resumes', async () => {
|
||||||
|
expect(Object.keys(resumes)).toHaveLength(2);
|
||||||
|
|
||||||
|
expect(Object.values(resumes)[0].user).toEqual(user.uid);
|
||||||
|
expect(
|
||||||
|
screen.getByText(Object.values(resumes)[0].name),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(Object.values(resumes)[1].user).toEqual(user.uid);
|
||||||
|
expect(
|
||||||
|
screen.getByText(Object.values(resumes)[1].name),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
52
src/templates/__tests__/Castform.test.js
Normal file
52
src/templates/__tests__/Castform.test.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import FirebaseStub, { DatabaseConstants } from 'gatsby-plugin-firebase';
|
||||||
|
|
||||||
|
import '../../i18n/index';
|
||||||
|
import Castform from '../Castform';
|
||||||
|
|
||||||
|
describe('Castform', () => {
|
||||||
|
let resume = {};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
FirebaseStub.database().initializeData();
|
||||||
|
|
||||||
|
const resumeId = DatabaseConstants.initialStateResumeId;
|
||||||
|
resume = (
|
||||||
|
await FirebaseStub.database()
|
||||||
|
.ref(`${DatabaseConstants.resumesPath}/${resumeId}`)
|
||||||
|
.once('value')
|
||||||
|
).val();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const { container } = render(<Castform data={resume} />);
|
||||||
|
|
||||||
|
expect(container).toBeTruthy();
|
||||||
|
expect(container).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('date of birth', () => {
|
||||||
|
const birthDateLabelMatcher = /Date of birth/i;
|
||||||
|
|
||||||
|
it('is not shown if not provided', () => {
|
||||||
|
render(<Castform data={resume} />);
|
||||||
|
|
||||||
|
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(<Castform data={resume} />);
|
||||||
|
|
||||||
|
expect(screen.getByText(birthDateLabelMatcher)).toBeTruthy();
|
||||||
|
expect(screen.getByText(birthDateLabelMatcher)).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(birthDateFormatted)).toBeTruthy();
|
||||||
|
expect(screen.getByText(birthDateFormatted)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user