diff --git a/__mocks__/__tests__/gatsby-plugin-firebase.test.js b/__mocks__/__tests__/gatsby-plugin-firebase.test.js index 8d11abd5..dc11cf38 100644 --- a/__mocks__/__tests__/gatsby-plugin-firebase.test.js +++ b/__mocks__/__tests__/gatsby-plugin-firebase.test.js @@ -281,7 +281,7 @@ describe('FirebaseStub', () => { expect(reference.equalToValue).toHaveLength(0); }); - it('triggers callback with resumes when creating new one', async () => { + it('triggers callback with resumes when creating a new one', async () => { const userUid = DatabaseConstants.user1.uid; let snapshotValue = null; @@ -333,5 +333,56 @@ describe('FirebaseStub', () => { expect(snapshotValue[newResume.id]).toBeTruthy(); expect(snapshotValue[newResume.id].id).toBe(newResume.id); }); + + it('triggers callback with resumes when updating an existing one', async () => { + const userUid = DatabaseConstants.user1.uid; + + let snapshotValue = null; + const callback = jest.fn((snapshot) => { + snapshotValue = snapshot.val(); + }); + + FirebaseStub.database() + .ref(DatabaseConstants.resumesPath) + .orderByChild('user') + .equalTo(userUid) + .on('value', callback); + + await waitFor(() => callback.mock.calls[0][0]); + + expect(callback.mock.calls).toHaveLength(1); + callback.mockClear(); + expect(snapshotValue).not.toBeNull(); + expect(Object.keys(snapshotValue)).toHaveLength(2); + Object.values(snapshotValue).forEach((resume) => + expect(resume.user).toEqual(userUid), + ); + snapshotValue = null; + + const existingResume = ( + await FirebaseStub.database() + .ref( + `${DatabaseConstants.resumesPath}/${DatabaseConstants.demoStateResume1Id}`, + ) + .once('value') + ).val(); + expect(existingResume).toBeTruthy(); + expect(existingResume.user).toEqual(userUid); + + 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); + callback.mockClear(); + expect(snapshotValue).not.toBeNull(); + expect(Object.keys(snapshotValue)).toHaveLength(2); + expect(snapshotValue[existingResume.id]).toBeTruthy(); + expect(snapshotValue[existingResume.id].name).toBe(existingResume.name); + }); }); }); diff --git a/__mocks__/gatsby-plugin-firebase/database/database.js b/__mocks__/gatsby-plugin-firebase/database/database.js index 029071c2..b6fcbdcb 100644 --- a/__mocks__/gatsby-plugin-firebase/database/database.js +++ b/__mocks__/gatsby-plugin-firebase/database/database.js @@ -39,7 +39,7 @@ class Database { return this._uuid; } - getData(dataPath) { + _getData(dataPath) { if (!dataPath) { throw new Error('dataPath must be provided.'); } @@ -64,12 +64,41 @@ class Database { return null; } - getReference(referencePath) { + _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 = {}; @@ -106,7 +135,7 @@ class Database { } ref(referencePath) { - const existingRef = this.getReference(referencePath); + const existingRef = this._getReference(referencePath); if (existingRef) { existingRef.initializeQueryParameters(); return existingRef; @@ -114,38 +143,13 @@ class Database { const newRef = new Reference( referencePath, - (dataPath) => this.getData(dataPath), - (dataPath, value) => this.setData(dataPath, value), - (refPath) => this.getReference(refPath), + (dataPath) => this._getData(dataPath), + (dataPath, value) => this._setData(dataPath, value), + (refPath) => this._getReference(refPath), ); this._references[newRef.path] = newRef; return newRef; } - - 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; - } - - this._data[dataPathElements[0]][dataPathElements[1]] = value; - } } export default Database; diff --git a/__mocks__/gatsby-plugin-firebase/database/reference.js b/__mocks__/gatsby-plugin-firebase/database/reference.js index c14df0db..117906ed 100644 --- a/__mocks__/gatsby-plugin-firebase/database/reference.js +++ b/__mocks__/gatsby-plugin-firebase/database/reference.js @@ -68,27 +68,7 @@ class Reference { return this._equalToValue; } - debounceEventCallback(eventType) { - if (!(eventType in this.eventCallbacks)) { - return; - } - - let snapshot = new DataSnapshot(eventType, () => this.getData(), null); - - if (this.path === DatabaseConstants.connectedPath) { - snapshot = new DataSnapshot(eventType, () => this.getData(), true); - } else if (this.path === DatabaseConstants.resumesPath) { - snapshot = new DataSnapshot(eventType, () => this.getData()); - } - - const debouncedEventCallback = debounce( - this.eventCallbacks[eventType], - 100, - ); - debouncedEventCallback(snapshot); - } - - getData() { + _getData() { const databaseData = this._getDatabaseData(this.path); if (!databaseData) { @@ -106,6 +86,49 @@ class Reference { return databaseData; } + _setData(value) { + if (typeof value === 'undefined') { + throw new Error('value must be provided.'); + } + + this._setDatabaseData(this.path, value); + + this.debounceEventCallback(DatabaseConstants.valueEventType); + + const pathElements = this.path.split('/'); + if (pathElements.length === 2) { + const parentReference = this._getReference(pathElements[0]); + if (parentReference) { + parentReference.debounceEventCallback(DatabaseConstants.valueEventType); + } + } + } + + debounceEventCallback(eventType) { + if (!(eventType in this.eventCallbacks)) { + return; + } + + let snapshot = new DataSnapshot(eventType, () => this._getData(), null); + + if (this.path === DatabaseConstants.connectedPath) { + snapshot = new DataSnapshot(eventType, () => this._getData(), true); + } else if (this.path === DatabaseConstants.resumesPath) { + snapshot = new DataSnapshot(eventType, () => this._getData()); + } + + const debouncedEventCallback = debounce( + this.eventCallbacks[eventType], + 100, + ); + debouncedEventCallback(snapshot); + } + + equalTo(value) { + this._equalToValue = value; + return this; + } + initializeQueryParameters() { this._orderByChildPath = ''; this._equalToValue = ''; @@ -126,7 +149,7 @@ class Reference { } async once(eventType) { - const newDataSnapshot = new DataSnapshot(eventType, () => this.getData()); + const newDataSnapshot = new DataSnapshot(eventType, () => this._getData()); const existingDataSnapshot = this._dataSnapshots[newDataSnapshot.eventType]; if (existingDataSnapshot) { return Promise.resolve(existingDataSnapshot); @@ -141,36 +164,14 @@ class Reference { return this; } - equalTo(value) { - this._equalToValue = value; - return this; - } - async update(value) { - if (typeof value === 'undefined') { - throw new Error('value must be provided.'); - } + this._setData(value); - const result = this !== null; - return Promise.resolve(result); + return Promise.resolve(true); } async set(value) { - if (typeof value === 'undefined') { - throw new Error('value must be provided.'); - } - - this._setDatabaseData(this.path, value); - - this.debounceEventCallback(DatabaseConstants.valueEventType); - - const pathElements = this.path.split('/'); - if (pathElements.length === 2) { - const parentReference = this._getReference(pathElements[0]); - if (parentReference) { - parentReference.debounceEventCallback(DatabaseConstants.valueEventType); - } - } + this._setData(value); return Promise.resolve(true); }