Firebase Stub: added support for data remove

This commit is contained in:
gianantoniopini
2021-01-14 17:16:01 +01:00
parent 46781bba60
commit 6ac0f37ada
4 changed files with 109 additions and 43 deletions

View File

@ -384,5 +384,63 @@ describe('FirebaseStub', () => {
expect(snapshotValue[existingResume.id]).toBeTruthy();
expect(snapshotValue[existingResume.id].name).toBe(existingResume.name);
});
it('triggers callback with removed resume when removing an existing one', 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]);
expect(valueCallback.mock.calls).toHaveLength(1);
valueCallback.mockClear();
expect(valueCallbackSnapshotValue).not.toBeNull();
expect(Object.keys(valueCallbackSnapshotValue)).toHaveLength(2);
Object.values(valueCallbackSnapshotValue).forEach((resume) =>
expect(resume.user).toEqual(userUid),
);
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);
childRemovedCallback.mockClear();
expect(childRemovedCallbackSnapshotValue).toBeTruthy();
expect(childRemovedCallbackSnapshotValue.id).toBe(removedResume.id);
await waitFor(() => valueCallback.mock.calls[0][0]);
expect(valueCallback.mock.calls).toHaveLength(1);
valueCallback.mockClear();
expect(valueCallbackSnapshotValue).toBeTruthy();
expect(removedResume.id in valueCallbackSnapshotValue).toBe(false);
});
});
});

View File

@ -1,6 +1,7 @@
import AuthConstants from './auth';
const valueEventType = 'value';
const childRemovedEventType = 'child_removed';
const resumesPath = 'resumes';
const usersPath = 'users';
@ -24,6 +25,10 @@ class Database {
return valueEventType;
}
static get childRemovedEventType() {
return childRemovedEventType;
}
static get resumesPath() {
return resumesPath;
}

View File

@ -1,16 +1,6 @@
/* eslint-disable no-underscore-dangle */
import DatabaseConstants from '../constants/database';
class DataSnapshot {
constructor(eventType, getData, value = undefined) {
if (!eventType) {
throw new Error('eventType must be provided.');
} else if (typeof eventType !== 'string') {
throw new Error('eventType should be a string.');
}
this._eventType = eventType;
constructor(getData, value = undefined) {
if (!getData) {
throw new Error('getData must be provided.');
} else if (typeof getData !== 'function') {
@ -22,21 +12,13 @@ class DataSnapshot {
this._value = value;
}
get eventType() {
return this._eventType;
}
get value() {
return this._value;
}
val() {
if (this.eventType === DatabaseConstants.valueEventType) {
return typeof this.value !== 'undefined' ? this.value : this._getData();
}
return undefined;
}
}
export default DataSnapshot;

View File

@ -17,7 +17,7 @@ class Reference {
this._uuid = uuidv4();
this._dataSnapshots = {};
this._dataSnapshot = null;
if (!getDatabaseData) {
throw new Error('getDatabaseData must be provided.');
@ -91,31 +91,42 @@ class Reference {
throw new Error('value must be provided.');
}
this._setDatabaseData(this.path, value);
this.debounceEventCallback(DatabaseConstants.valueEventType);
const currentData = this._getData();
const pathElements = this.path.split('/');
let parentReference = null;
if (pathElements.length === 2) {
const parentReference = this._getReference(pathElements[0]);
parentReference = this._getReference(pathElements[0]);
}
this._setDatabaseData(this.path, value);
if (value === null) {
if (parentReference) {
parentReference.debounceEventCallback(
DatabaseConstants.childRemovedEventType,
currentData,
);
parentReference.debounceEventCallback(DatabaseConstants.valueEventType);
}
} else {
const eventType = DatabaseConstants.valueEventType;
this.debounceEventCallback(eventType);
if (parentReference) {
parentReference.debounceEventCallback(eventType);
}
}
}
debounceEventCallback(eventType) {
debounceEventCallback(eventType, snapshotValue = undefined) {
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 snapshot =
this.path === DatabaseConstants.connectedPath
? new DataSnapshot(() => this._getData(), true)
: new DataSnapshot(() => this._getData(), snapshotValue);
const debouncedEventCallback = debounce(
this.eventCallbacks[eventType],
@ -139,23 +150,27 @@ class Reference {
}
on(eventType, callback) {
if (eventType !== DatabaseConstants.valueEventType) {
return;
}
this._eventCallbacks[eventType] = callback;
if (eventType === DatabaseConstants.valueEventType) {
this.debounceEventCallback(eventType);
}
}
async once(eventType) {
const newDataSnapshot = new DataSnapshot(eventType, () => this._getData());
const existingDataSnapshot = this._dataSnapshots[newDataSnapshot.eventType];
if (existingDataSnapshot) {
return Promise.resolve(existingDataSnapshot);
if (!eventType) {
throw new Error('eventType must be provided.');
} else if (typeof eventType !== 'string') {
throw new Error('eventType should be a string.');
}
this._dataSnapshots[newDataSnapshot.eventType] = newDataSnapshot;
if (this._dataSnapshot) {
return Promise.resolve(this._dataSnapshot);
}
const newDataSnapshot = new DataSnapshot(() => this._getData());
this._dataSnapshot = newDataSnapshot;
return Promise.resolve(newDataSnapshot);
}
@ -170,6 +185,12 @@ class Reference {
return Promise.resolve(true);
}
async remove() {
this._setData(null);
return Promise.resolve(true);
}
async set(value) {
this._setData(value);