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] 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 f80e06c0..00000000 --- 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 00000000..d70a5c1d --- /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 00000000..83a73880 --- /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 00000000..a9f68fa0 --- /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 00000000..9901b782 --- /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 00000000..9c018f89 --- /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 00000000..3d96a0c3 --- /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 00000000..1ac8a1e1 --- /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 00000000..9ea786b5 --- /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 00000000..1c9d30bf --- /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 00000000..8a97c0a9 --- /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); +});