mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-14 00:32:35 +10:00
Firebase Stub: simple implementation of data changes listener
This commit is contained in:
@ -281,7 +281,7 @@ describe('FirebaseStub', () => {
|
|||||||
expect(reference.equalToValue).toHaveLength(0);
|
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;
|
const userUid = DatabaseConstants.user1.uid;
|
||||||
|
|
||||||
let snapshotValue = null;
|
let snapshotValue = null;
|
||||||
@ -333,5 +333,56 @@ describe('FirebaseStub', () => {
|
|||||||
expect(snapshotValue[newResume.id]).toBeTruthy();
|
expect(snapshotValue[newResume.id]).toBeTruthy();
|
||||||
expect(snapshotValue[newResume.id].id).toBe(newResume.id);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class Database {
|
|||||||
return this._uuid;
|
return this._uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
getData(dataPath) {
|
_getData(dataPath) {
|
||||||
if (!dataPath) {
|
if (!dataPath) {
|
||||||
throw new Error('dataPath must be provided.');
|
throw new Error('dataPath must be provided.');
|
||||||
}
|
}
|
||||||
@ -64,12 +64,41 @@ class Database {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getReference(referencePath) {
|
_getReference(referencePath) {
|
||||||
return referencePath in this._references
|
return referencePath in this._references
|
||||||
? this._references[referencePath]
|
? this._references[referencePath]
|
||||||
: null;
|
: 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() {
|
initializeData() {
|
||||||
const resumes = {};
|
const resumes = {};
|
||||||
|
|
||||||
@ -106,7 +135,7 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref(referencePath) {
|
ref(referencePath) {
|
||||||
const existingRef = this.getReference(referencePath);
|
const existingRef = this._getReference(referencePath);
|
||||||
if (existingRef) {
|
if (existingRef) {
|
||||||
existingRef.initializeQueryParameters();
|
existingRef.initializeQueryParameters();
|
||||||
return existingRef;
|
return existingRef;
|
||||||
@ -114,38 +143,13 @@ class Database {
|
|||||||
|
|
||||||
const newRef = new Reference(
|
const newRef = new Reference(
|
||||||
referencePath,
|
referencePath,
|
||||||
(dataPath) => this.getData(dataPath),
|
(dataPath) => this._getData(dataPath),
|
||||||
(dataPath, value) => this.setData(dataPath, value),
|
(dataPath, value) => this._setData(dataPath, value),
|
||||||
(refPath) => this.getReference(refPath),
|
(refPath) => this._getReference(refPath),
|
||||||
);
|
);
|
||||||
this._references[newRef.path] = newRef;
|
this._references[newRef.path] = newRef;
|
||||||
return 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;
|
export default Database;
|
||||||
|
|||||||
@ -68,27 +68,7 @@ class Reference {
|
|||||||
return this._equalToValue;
|
return this._equalToValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
debounceEventCallback(eventType) {
|
_getData() {
|
||||||
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() {
|
|
||||||
const databaseData = this._getDatabaseData(this.path);
|
const databaseData = this._getDatabaseData(this.path);
|
||||||
|
|
||||||
if (!databaseData) {
|
if (!databaseData) {
|
||||||
@ -106,6 +86,49 @@ class Reference {
|
|||||||
return databaseData;
|
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() {
|
initializeQueryParameters() {
|
||||||
this._orderByChildPath = '';
|
this._orderByChildPath = '';
|
||||||
this._equalToValue = '';
|
this._equalToValue = '';
|
||||||
@ -126,7 +149,7 @@ class Reference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async once(eventType) {
|
async once(eventType) {
|
||||||
const newDataSnapshot = new DataSnapshot(eventType, () => this.getData());
|
const newDataSnapshot = new DataSnapshot(eventType, () => this._getData());
|
||||||
const existingDataSnapshot = this._dataSnapshots[newDataSnapshot.eventType];
|
const existingDataSnapshot = this._dataSnapshots[newDataSnapshot.eventType];
|
||||||
if (existingDataSnapshot) {
|
if (existingDataSnapshot) {
|
||||||
return Promise.resolve(existingDataSnapshot);
|
return Promise.resolve(existingDataSnapshot);
|
||||||
@ -141,36 +164,14 @@ class Reference {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
equalTo(value) {
|
|
||||||
this._equalToValue = value;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
async update(value) {
|
async update(value) {
|
||||||
if (typeof value === 'undefined') {
|
this._setData(value);
|
||||||
throw new Error('value must be provided.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = this !== null;
|
return Promise.resolve(true);
|
||||||
return Promise.resolve(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async set(value) {
|
async set(value) {
|
||||||
if (typeof value === 'undefined') {
|
this._setData(value);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user