Skip to content
This repository was archived by the owner on Feb 7, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/firestore-query-snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
var _ = require('./lodash');
var DocumentSnapshot = require('./firestore-document-snapshot');

function MockFirestoreQuerySnapshot (ref, data, keyOrder) {
function MockFirestoreQuerySnapshot (ref, data, keyOrder, changes = {}) {
this.changes = changes;
this._ref = ref;
this.data = _.cloneDeep(data) || {};
this.keyOrder = keyOrder;
Expand All @@ -25,4 +26,30 @@ MockFirestoreQuerySnapshot.prototype.forEach = function (callback, context) {
});
};


MockFirestoreQuerySnapshot.prototype.docChanges = function () {
var {added = {}, removed = {}, modified = {}} = this.changes || {};
const result = [];

_.forEach(added, addChange(result, 'added'));
_.forEach(modified, addChange(result, 'modified'));
_.forEach(removed, addChange(result, 'removed'));

return result;
};

function addChange (result, changeType) {
return function(value, key) {
result.push({
type: changeType,
doc: {
id: key,
data: function() {
return value;
}
}
});
};
}

module.exports = MockFirestoreQuerySnapshot;
31 changes: 28 additions & 3 deletions src/firestore-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,41 @@ MockFirestoreQuery.prototype.onSnapshot = function (optionsOrObserverOrOnNext, o
onError = onErrorArg;
}
var context = {
data: self._results(),
data: {
results: {}
},
};
var onSnapshot = function () {
// compare the current state to the one from when this function was created
// and send the data to the callback if different.
if (err === null) {
self.get().then(function (querySnapshot) {
var results = self._results();
if (JSON.stringify(results) !== JSON.stringify(context.data) || includeMetadataChanges) {
onNext(new QuerySnapshot(self.parent === null ? self : self.parent.collection(self.id), results.results, results.keyOrder));

var added = {};
var removed = {};
var modified = {};

_.forEach(results.results, function(nextValue, nextKey) {
if(Object.keys(context.data.results || {}).indexOf(nextKey) === -1) {
added[nextKey] = nextValue;
} else if (!_.isEqual(context.data.results[nextKey], nextValue)) {
modified[nextKey] = nextValue;
}
});

_.forEach(context.data.results, function(value, key) {
if (Object.keys(results.results).indexOf(key) === -1) {
removed[key] = value;
}
});

var hasAdditions = Object.keys(added).length > 0;
var hasRemovals = Object.keys(removed).length > 0;
var hasModififations = Object.keys(modified).length > 0;

if (hasAdditions || hasRemovals || hasModififations || includeMetadataChanges) {
onNext(new QuerySnapshot(self.parent === null ? self : self.parent.collection(self.id), results.results, results.keyOrder, {added, removed, modified}));
// onNext(new QuerySnapshot(self.id, self.ref, results));
context.data = results;
}
Expand Down
2 changes: 1 addition & 1 deletion test/.jshintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"node": true,
"mocha": true,
"esversion" : "6"
"esversion" : "8"
}
91 changes: 91 additions & 0 deletions test/unit/firestore-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,97 @@ describe('MockFirestoreCollection', function () {
collection.flush();
});

it('returns value on first call', function(done) {
collection.doc('a').update({name: 'A'}, {setMerge: true});
db.autoFlush();

collection.onSnapshot(function(snap) {
var names = [];
snap.docs.forEach(function(doc) {
names.push(doc.data().name);
});
expect(names).to.contain('A');
expect(names).not.to.contain('a');
done();
});
});

it('(TODO) returns doc changes as "added" on first call', function (done) {
collection.onSnapshot(function(snap) {
var names = [];
var changes = snap.docChanges();
// TODO!
expect(changes).to.have.length(6);
const allAdded = _.every(changes, function(change) {
return change.type === 'added';
});
expect(allAdded).to.equal(true);
done();
});
collection.doc('a').update({name: 'A'}, {setMerge: true});
collection.flush();
});

it('(TODO) returns doc changes as "added" on document addition', function (done) {
db.autoFlush();
var call = 0;
collection.onSnapshot(function(snap) {
call += 1;
if (call === 1) {
collection.add({name: 'New'});
}
if (call === 2) {
var changes = snap.docChanges();
expect(changes).to.have.length(1);
expect(changes[0]).to.have.property('type', 'added');
done();
}
});

// collection.add({name: 'New'});
// collection.flush();
});

it('(TODO) returns doc changes as "modified" on document modification', function (done) {
db.autoFlush();
var call = 0;
collection.onSnapshot(async function(snap) {
call += 1;
if (call === 1) {
await collection.doc('1').update({name: 'Modified'});
}
if (call === 2) {
var changes = snap.docChanges();
expect(changes).to.have.length(1);
expect(changes[0]).to.have.property('type', 'modified');
done();
}
});

// collection.add({name: 'New'});
// collection.flush();
});

it('(TODO) returns doc changes as "removed" on document deletion', function (done) {
db.autoFlush();
var call = 0;
collection.onSnapshot(async function(snap) {
call += 1;
if (call === 1) {
await collection.doc('1').delete();
}
if (call === 2) {
var changes = snap.docChanges();
expect(changes).to.have.length(1);
expect(changes[0]).to.have.property('type', 'removed');
done();
}
});

// collection.add({name: 'New'});
// collection.flush();
});

it('calls callback after multiple updates', function (done) {
var callCount = 0;
collection.onSnapshot(function(snap) {
Expand Down