mock-cloud-firestore
Version:
Mock library for Cloud Firestore
1,624 lines (1,257 loc) • 48.4 kB
JavaScript
import sinon from 'sinon';
import firebase from 'firebase';
import CollectionReference from './firebase/firestore/collection-reference';
import DocumentReference from './firebase/firestore/document-reference';
import DocumentSnapshot from './firebase/firestore/document-snapshot';
import FieldValue from './firebase/firestore/field-value';
import Firestore from './firebase/firestore';
import MockFirebase from '.';
import QuerySnapshot from './firebase/firestore/query-snapshot';
import Query from './firebase/firestore/query';
import fixtureData from './utils/test-helpers/fixture-data';
let mockFirebase;
QUnit.module('Unit | mock-cloud-firestore', (hooks) => {
QUnit.config.testTimeout = 3000;
hooks.beforeEach(() => {
mockFirebase = new MockFirebase(fixtureData(), { isNaiveSnapshotListenerEnabled: true });
});
QUnit.module('CollectionReference', () => {
QUnit.module('getter/setter: id', () => {
QUnit.test('should return collection identifier', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').id;
// Assert
assert.equal(result, 'users');
});
});
QUnit.module('getter/setter: firestore', () => {
QUnit.test('should return the firestore the collection is in', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').firestore;
// Assert
assert.ok(result instanceof Firestore);
});
});
QUnit.module('getter/setter: parent', () => {
QUnit.test('should return DocumentReference if this is a subcollection', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').collection('friends').parent;
// Assert
assert.ok(result instanceof DocumentReference);
});
QUnit.test('should return null if there is no parent', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').parent;
// Assert
assert.equal(result, null);
});
});
QUnit.module('function: add', () => {
QUnit.test('should add a new document', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const ref = await db.collection('users').add({ username: 'new_user' });
// Assert
const snapshot = await ref.get();
assert.deepEqual(snapshot.data(), { username: 'new_user' });
});
});
QUnit.module('function: doc', () => {
QUnit.test('should return the document reference using an ID', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a');
// Assert
assert.ok(result instanceof DocumentReference);
});
QUnit.test('should return the document reference using a path', (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a/friends/user_b');
// Assert
assert.ok(result instanceof DocumentReference);
assert.equal(result.id, 'user_b');
});
QUnit.test('should throw an error when getting doc reference on an odd number of segment', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
db.collection('users').doc('user_a/friends');
} catch (error) {
// Assert
assert.equal(error.message, 'Invalid document reference. Document references must have an even number of segments, but users/user_a/friends has 3.');
}
});
QUnit.test('should create document reference when not providing an ID', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc();
// Assert
assert.ok(result.id);
});
});
QUnit.module('function: endAt', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').endAt(15);
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: endBefore', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').endBefore(15);
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: get', () => {
QUnit.test('should return the query snapshot', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = await db.collection('users').get();
// Assert
assert.ok(result instanceof QuerySnapshot);
});
});
QUnit.module('function: limit', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').limit(15);
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: onSnapshot', () => {
QUnit.test('should return a function for unsubscribing', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').onSnapshot(() => {});
// Assert
assert.ok(typeof result === 'function');
});
QUnit.test('should fire callback', (assert) => {
assert.expect(1);
// Arrange
const done = assert.async();
const db = mockFirebase.firestore();
// Act
db.collection('users').onSnapshot((snapshot) => {
// Assert
assert.ok(snapshot instanceof QuerySnapshot);
done();
});
});
QUnit.test('should listen for changes in the data', (assert) => {
assert.expect(5);
// Arrange
const db = mockFirebase.firestore();
const snapshots = [];
const snapshotDone = assert.async();
const unsubscribe = db.collection('users').onSnapshot((snapshot) => {
snapshots.push(snapshot.docs.map(doc => doc.data()));
if (snapshots.length === 2) {
assert.equal(snapshots[0].length, 3);
assert.equal(snapshots[0][1].username, 'user_b');
assert.equal(snapshots[0][1].age, 10);
assert.equal(snapshots[1][1].username, 'user_b');
assert.equal(snapshots[1][1].age, 2);
snapshotDone();
}
if (snapshots.length > 2) {
assert.ok(false, 'Should not be called more than twice');
}
});
setTimeout(() => {
const unsubscribeDone = assert.async();
db.collection('users').doc('user_b').update({
age: 2,
});
unsubscribe();
setTimeout(() => {
db.collection('users').doc('user_b').update({
age: 3,
});
unsubscribeDone();
}, 100);
}, 100);
});
});
QUnit.module('function: orderBy', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age');
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: startAfter', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').startAfter(15);
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: startAt', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').startAt(15);
// Assert
assert.ok(result instanceof Query);
});
});
QUnit.module('function: where', () => {
QUnit.test('should return an instance of Query', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').where('name', '==', 'Foo');
// Assert
assert.ok(result instanceof Query);
});
});
});
QUnit.module('DocumentReference', () => {
QUnit.module('getter/setter: id', () => {
QUnit.test('should return document identifier', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').id;
// Assert
assert.equal(result, 'user_a');
});
});
QUnit.module('getter/setter: firestore', () => {
QUnit.test('should return the firestore the document is in', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').firestore;
// Assert
assert.ok(result instanceof Firestore);
});
});
QUnit.module('getter/setter: parent', () => {
QUnit.test('should return CollectionReference of which the DocumentReference belongs to', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').parent;
// Assert
assert.ok(result instanceof CollectionReference);
});
});
QUnit.module('function: collection', () => {
QUnit.test('should return the collection reference of an ID', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').collection('friends');
// Assert
assert.ok(result instanceof CollectionReference);
});
QUnit.test('should return the collection reference of a path', (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db
.collection('users')
.doc('user_a')
.collection('friends/user_b/wew_so_deep');
// Assert
assert.ok(result instanceof CollectionReference);
assert.equal(result.id, 'wew_so_deep');
});
QUnit.test('should throw an error when getting collection reference on an even number of segment', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
db.collection('users').doc('user_a').collection('friends/user_b');
} catch (error) {
// Assert
assert.equal(error.message, 'Invalid collection reference. Collection references must have an odd number of segments, but users/user_a/friends/user_b has 4.');
}
});
});
QUnit.module('function: delete', () => {
QUnit.test('should delete the document', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
// Act
await ref.delete();
// Assert
const record = await ref.get();
assert.equal(record.exists, false);
});
QUnit.test('should delete the document coming from a query', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const querySnapshot = await db.collection('users').where('age', '==', 15).get();
// Act
querySnapshot.forEach(async (docSnapshot) => {
await docSnapshot.ref.delete();
});
// Assert
const docSnapshot = await db.collection('users').doc('user_a').get();
assert.equal(docSnapshot.exists, false);
});
});
QUnit.module('function: get', () => {
QUnit.test('should return the document snapshot', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = await db.collection('users').doc('user_a').get();
// Assert
assert.ok(result instanceof DocumentSnapshot);
});
});
QUnit.module('function: onSnapshot', () => {
QUnit.test('should return a function for unsubscribing', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').doc('user_a').onSnapshot(() => {});
// Assert
assert.ok(typeof result === 'function');
});
QUnit.test('should fire callback', (assert) => {
assert.expect(1);
// Arrange
const done = assert.async();
const db = mockFirebase.firestore();
// Act
db.collection('users').doc('user_a').onSnapshot((snapshot) => {
// Assert
assert.ok(snapshot instanceof DocumentSnapshot);
done();
});
});
QUnit.test('should listen for changes in the data', (assert) => {
assert.expect(4);
// Arrange
const onSnapshotDone = assert.async();
const db = mockFirebase.firestore();
const snapshots = [];
// Act
const unsubscribe = db.collection('users').doc('user_a').onSnapshot((snapshot) => {
// Assert
assert.ok(snapshot instanceof DocumentSnapshot);
snapshots.push(snapshot.data());
if (snapshots.length === 2) {
assert.equal(snapshots[0].age, 15);
assert.equal(snapshots[1].age, 10);
onSnapshotDone();
}
if (snapshots.length > 2) {
assert.ok(false, 'Should not be called more than twice');
}
});
const unsubscribeDone = assert.async();
setTimeout(() => {
db.collection('users').doc('user_a').update({
age: 10,
});
unsubscribe();
setTimeout(() => {
db.collection('users').doc('user_b').update({
age: 2,
});
unsubscribeDone();
}, 100);
}, 100);
});
});
QUnit.module('function: set', () => {
QUnit.test('should set the data using the non-merge option', async (assert) => {
assert.expect(8);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
// Act
await ref.set({
'address.home': 'San Francisco',
age: null,
name: 'user_a',
dad: db.collection('users').doc('user_b'),
modifiedOn: firebase.firestore.FieldValue.serverTimestamp(),
pinnedBooks: firebase.firestore.FieldValue.arrayUnion('book_100'),
pinnedFoods: firebase.firestore.FieldValue.arrayRemove('food_1'),
});
// Assert
const snapshot = await ref.get();
const data = snapshot.data();
assert.equal(Object.keys(data).length, 7);
assert.equal(data['address.home'], 'San Francisco');
assert.equal(data.age, null);
assert.deepEqual(data.dad, db.collection('users').doc('user_b'));
assert.ok(data.modifiedOn.toDate() instanceof Date);
assert.deepEqual(data.pinnedBooks, ['book_100']);
assert.deepEqual(data.pinnedFoods, []);
assert.equal(data.name, 'user_a');
});
QUnit.test('should set the data using the merge option', async (assert) => {
assert.expect(12);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
// Act
await ref.set({
'address.home': 'Seattle',
address: { home: 'Seattle' },
name: firebase.firestore.FieldValue.delete(),
dad: db.collection('users').doc('user_b'),
modifiedOn: firebase.firestore.FieldValue.serverTimestamp(),
activeYears: firebase.firestore.FieldValue.increment(-1),
pinnedBooks: firebase.firestore.FieldValue.arrayUnion('book_100'),
pinnedFoods: firebase.firestore.FieldValue.arrayRemove('food_1'),
}, { merge: true });
// Assert
const snapshot = await ref.get();
const data = snapshot.data();
assert.equal(Object.keys(data).length, 10);
assert.deepEqual(data.address, { home: 'Seattle', work: 'Silicon Valley' });
assert.equal(data['address.home'], 'Seattle');
assert.equal(data.age, 15);
assert.deepEqual(data.createdOn.toDate(), new Date('2017-01-01'));
assert.deepEqual(data.dad, db.collection('users').doc('user_b'));
assert.ok(data.modifiedOn.toDate() instanceof Date);
assert.equal(data.activeYears, 1);
assert.deepEqual(data.pinnedBooks, ['book_1', 'book_2', 'book_100']);
assert.deepEqual(data.pinnedFoods, ['food_2']);
assert.equal(data.name, undefined);
assert.equal(data.username, 'user_a');
});
});
QUnit.module('function: update', () => {
QUnit.test('should update the data', async (assert) => {
assert.expect(12);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
// Act
await ref.update({
address: { temp: 'Seattle' },
'address.work': 'Bay Area',
'address.home': firebase.firestore.FieldValue.delete(),
'contact.mobile.personal': 67890,
age: firebase.firestore.FieldValue.delete(),
dad: db.collection('users').doc('user_b'),
activeYears: firebase.firestore.FieldValue.increment(1),
modifiedOn: firebase.firestore.FieldValue.serverTimestamp(),
pinnedBooks: firebase.firestore.FieldValue.arrayUnion('book_100'),
pinnedFoods: firebase.firestore.FieldValue.arrayRemove('food_1'),
name: 'user_a',
});
// Assert
const snapshot = await ref.get();
const {
address,
age,
contact,
createdOn,
dad,
modifiedOn,
name,
activeYears,
pinnedBooks,
pinnedFoods,
username,
} = snapshot.data();
assert.equal(Object.keys(snapshot.data()).length, 10);
assert.deepEqual(address, { work: 'Bay Area', temp: 'Seattle' });
assert.equal(age, undefined);
assert.deepEqual(contact, {
mobile: { personal: 67890 },
});
assert.deepEqual(createdOn.toDate(), new Date('2017-01-01'));
assert.deepEqual(dad, db.collection('users').doc('user_b'));
assert.ok(modifiedOn.toDate() instanceof Date);
assert.equal(activeYears, 3);
assert.equal(name, 'user_a');
assert.deepEqual(pinnedBooks, ['book_1', 'book_2', 'book_100']);
assert.deepEqual(pinnedFoods, ['food_2']);
assert.equal(username, 'user_a');
});
QUnit.test('should create the field if incrementing a field that is nonexistent', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
// Act
await ref.update({
nonExistentField: firebase.firestore.FieldValue.increment(1),
});
// Assert
const snapshot = await ref.get();
const data = snapshot.data();
assert.equal(data.nonExistentField, 1);
});
QUnit.test('should throw error when updating data that does not exist', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_100');
try {
// Act
await ref.update({ name: 'user_100' });
} catch (e) {
// Assert
assert.ok(true);
}
});
QUnit.test('should throw error when updating data with an undefined value', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
try {
// Act
await ref.update({ name: undefined });
} catch (e) {
// Assert
assert.ok(true);
}
});
});
});
QUnit.module('DocumentSnapshot', () => {
QUnit.module('getter/setter: exists', () => {
QUnit.test('should return true if data exists', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.exists;
// Assert
assert.equal(result, true);
});
QUnit.test('should return false if data does not exists', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_100').get();
// Act
const result = snapshot.exists;
// Assert
assert.equal(result, false);
});
});
QUnit.module('getter/setter: id', () => {
QUnit.test('should return the identifier', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.id;
// Assert
assert.equal(result, 'user_a');
});
});
QUnit.module('getter/setter: ref', () => {
QUnit.test('should return the DocumentReference', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.ref;
// Assert
assert.ok(result instanceof DocumentReference);
});
});
QUnit.module('function: get', () => {
QUnit.test('should return the specific field', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.get('age');
// Assert
assert.equal(result, 15);
});
QUnit.test('should return the reference type field', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db
.collection('users')
.doc('user_a')
.collection('friends')
.doc('user_b')
.get();
// Act
const reference = snapshot.get('reference');
// Assert
const referenceSnapshot = await reference.get();
const { age, createdOn, username } = referenceSnapshot.data();
assert.equal(age, 10);
assert.deepEqual(createdOn.toDate(), new Date('2017-01-01'));
assert.equal(username, 'user_b');
});
QUnit.test('should return the specific field using dot notation', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.get('address.home');
// Assert
assert.equal(result, 'San Francisco');
});
QUnit.test('should return undefined when field does not exist', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const result = snapshot.get('foobar');
// Assert
assert.equal(result, undefined);
});
});
QUnit.module('function: data', () => {
QUnit.test('should return the data', async (assert) => {
assert.expect(4);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_a').get();
// Act
const {
address,
age,
createdOn,
username,
} = snapshot.data();
// Assert
assert.deepEqual(address, { home: 'San Francisco', work: 'Silicon Valley' });
assert.equal(age, 15);
assert.deepEqual(createdOn.toDate(), new Date('2017-01-01'));
assert.equal(username, 'user_a');
});
QUnit.test('should return the data and match any reference type field appropriately', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db
.collection('users')
.doc('user_a')
.collection('friends')
.doc('user_b')
.get();
// Act
const { reference } = snapshot.data();
// Assert
const referenceSnapshot = await reference.get();
const { age, createdOn, username } = referenceSnapshot.data();
assert.equal(age, 10);
assert.deepEqual(createdOn.toDate(), new Date('2017-01-01'));
assert.equal(username, 'user_b');
});
QUnit.test('should return undefined when data does not exist', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').doc('user_100').get();
// Act
const result = snapshot.data();
// Assert
assert.equal(result, undefined);
});
});
});
QUnit.module('FieldValue', () => {
QUnit.module('function: arrayUnion', () => {
QUnit.test('should return an array union representation', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue.arrayUnion('foo', 'bar');
// Assert
assert.deepEqual(result, {
_methodName: 'FieldValue.arrayUnion',
_elements: ['foo', 'bar'],
});
});
});
QUnit.module('function: arrayRemove', () => {
QUnit.test('should return an array union representation', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue.arrayRemove('foo', 'bar');
// Assert
assert.deepEqual(result, {
_methodName: 'FieldValue.arrayRemove',
_elements: ['foo', 'bar'],
});
});
});
QUnit.module('function: delete', () => {
QUnit.test('should return a delete field representation', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue.delete();
// Assert
assert.deepEqual(result, { _methodName: 'FieldValue.delete' });
});
});
QUnit.module('function: serverTimestamp', () => {
QUnit.test('should return a server timestamp representation', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue.serverTimestamp();
// Assert
assert.deepEqual(result, { _methodName: 'FieldValue.serverTimestamp' });
});
});
QUnit.module('function: increment', () => {
QUnit.test('should return an increment operation representation', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue.increment(1);
// Assert
assert.deepEqual(result, { _methodName: 'FieldValue.increment', _operand: 1 });
});
});
});
QUnit.module('Firestore', () => {
QUnit.module('static getter/setter: FieldValue', () => {
QUnit.test('should return an instance of FieldValue', (assert) => {
assert.expect(1);
// Act
const result = mockFirebase.firestore.FieldValue;
// Assert
assert.ok(result instanceof FieldValue);
});
});
QUnit.module('function: collection', () => {
QUnit.test('should return the collection reference using a path', (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users/user_a/friends');
// Assert
assert.ok(result instanceof CollectionReference);
assert.equal(result.id, 'friends');
});
QUnit.test('should throw an error when getting collection reference on an even number of segment', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
db.collection('users/user_a');
} catch (error) {
// Assert
assert.equal(error.message, 'Invalid collection reference. Collection references must have an odd number of segments, but users/user_a has 2.');
}
});
});
QUnit.module('function: getCollections', () => {
QUnit.test('should return all the subcollection references of the document', async (assert) => {
assert.expect(6);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = await db.doc('users/user_a').getCollections();
// Assert
assert.ok(result instanceof Array);
assert.equal(result.length, 2);
assert.ok(result[0] instanceof CollectionReference);
assert.equal(result[0].id, 'friends');
assert.ok(result[1] instanceof CollectionReference);
assert.equal(result[1].id, 'enemies');
});
QUnit.test('should not throw when document doesn\'t exist', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = await db.doc('users/user_unknown').getCollections();
// Assert
assert.deepEqual(result, []);
});
});
QUnit.module('function: doc', () => {
QUnit.test('should return the document reference using a path', (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.doc('users/user_a');
// Assert
assert.ok(result instanceof DocumentReference);
assert.equal(result.id, 'user_a');
});
QUnit.test('should throw an error when getting doc reference on an even number of segment', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
db.doc('users/user_a/friends');
} catch (error) {
// Assert
assert.equal(error.message, 'Invalid document reference. Document references must have an even number of segments, but users/user_a/friends has 3.');
}
});
});
});
QUnit.module('QuerySnapshot', () => {
QUnit.module('getter/setter: docs', () => {
QUnit.test('should return the documents for the query snapshot', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').get();
// Act
const result = snapshot.docs;
// Assert
assert.equal(result[0].id, 'user_a');
assert.equal(result[1].id, 'user_b');
assert.equal(result[2].id, 'user_c');
});
});
QUnit.module('getter/setter: empty', () => {
QUnit.test('should return true when there are no documents', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('foobar').get();
// Act
const result = snapshot.empty;
// Assert
assert.equal(result, true);
});
QUnit.test('should return false when there are documents', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').get();
// Act
const result = snapshot.empty;
// Assert
assert.equal(result, false);
});
});
QUnit.module('getter/setter: size', () => {
QUnit.test('should return the number of documents for the query snapshot', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').get();
// Act
const result = snapshot.size;
// Assert
assert.equal(result, 3);
});
});
QUnit.module('function: forEach', () => {
QUnit.test('should fire callback per each data', async (assert) => {
assert.expect(1);
// Arrange
const stub = sinon.stub();
const db = mockFirebase.firestore();
const snapshot = await db.collection('users').get();
// Act
snapshot.forEach(stub);
// Assert
assert.ok(stub.calledThrice);
});
});
});
QUnit.module('Query', () => {
QUnit.module('getter/setter: firestore', () => {
QUnit.test('should return the firestore the query is in', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').limit(1).firestore;
// Assert
assert.ok(result instanceof Firestore);
});
});
QUnit.module('function: endAt', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').orderBy('age').endAt(15).get();
// Assert
assert.equal(snapshot.docs.length, 2);
assert.equal(snapshot.docs[0].id, 'user_b');
assert.equal(snapshot.docs[1].id, 'user_a');
});
QUnit.test('should error when not doing orderBy()', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
await db.collection('users').endAt(15).get();
} catch (e) {
// Assert
assert.ok(true);
}
});
});
QUnit.module('function: endBefore', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').orderBy('age').endBefore(15).get();
// Assert
assert.equal(snapshot.docs.length, 1);
assert.equal(snapshot.docs[0].id, 'user_b');
});
QUnit.test('should error when not doing orderBy()', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
await db.collection('users').endBefore(15).get();
} catch (e) {
// Assert
assert.ok(true);
}
});
});
QUnit.module('function: limit', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').limit(2).get();
// Assert
assert.equal(snapshot.docs.length, 2);
assert.equal(snapshot.docs[0].id, 'user_a');
assert.equal(snapshot.docs[1].id, 'user_b');
});
});
QUnit.module('function: onSnapshot', () => {
QUnit.test('should return a function for unsubscribing', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const result = db.collection('users').orderBy('age').onSnapshot(() => {});
// Assert
assert.ok(typeof result === 'function');
});
QUnit.test('should listen for changes in the data', (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const snapshots = [];
// Act
const snapshotDone = assert.async();
const unsubscribe = db.collection('users').orderBy('age').onSnapshot((snapshot) => {
snapshots.push(snapshot.docs.map(doc => [doc.data().age, doc.data().username]));
if (snapshots.length === 2) {
assert.deepEqual(snapshots, [
[[10, 'user_b'], [15, 'user_a'], [20, 'user_c']],
[[15, 'user_a'], [16, 'user_b'], [20, 'user_c']],
]);
snapshotDone();
}
if (snapshots.length > 2) {
assert.ok(false, 'Should not be called more than twice');
}
});
setTimeout(() => {
const unsubscribeDone = assert.async();
db.collection('users').doc('user_b').update({
age: 16,
});
unsubscribe();
setTimeout(() => {
db.collection('users').doc('user_b').update({
age: 2,
});
unsubscribeDone();
}, 100);
}, 100);
});
QUnit.test('should fire callback', (assert) => {
assert.expect(1);
// Arrange
const done = assert.async();
const db = mockFirebase.firestore();
// Act
db.collection('users').orderBy('age').onSnapshot((snapshot) => {
// Assert
assert.ok(snapshot instanceof QuerySnapshot);
done();
});
});
});
QUnit.module('function: orderBy', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').orderBy('age').get();
// Assert
assert.equal(snapshot.docs[0].id, 'user_b');
assert.equal(snapshot.docs[1].id, 'user_a');
assert.equal(snapshot.docs[2].id, 'user_c');
});
QUnit.test('should return empty array with empty collection', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('unknown').orderBy('age').get();
// Assert
assert.equal(snapshot.docs.length, 0);
});
});
QUnit.module('function: startAfter', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').orderBy('age').startAfter(15).get();
// Assert
assert.equal(snapshot.docs.length, 1);
assert.equal(snapshot.docs[0].id, 'user_c');
});
QUnit.test('should error when not doing orderBy()', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
await db.collection('users').startAfter(15).get();
} catch (e) {
// Assert
assert.ok(true);
}
});
});
QUnit.module('function: startAt', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(3);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').orderBy('age').startAt(15).get();
// Assert
assert.equal(snapshot.docs.length, 2);
assert.equal(snapshot.docs[0].id, 'user_a');
assert.equal(snapshot.docs[1].id, 'user_c');
});
QUnit.test('should error when not doing orderBy()', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
try {
// Act
await db.collection('users').startAt(15).get();
} catch (e) {
// Assert
assert.ok(true);
}
});
});
QUnit.module('function: where', () => {
QUnit.test('should return documents satisfying the query', async (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
// Act
const snapshot = await db.collection('users').where('age', '==', 10).limit(1).get();
// Assert
assert.equal(snapshot.docs.length, 1);
assert.equal(snapshot.docs[0].id, 'user_b');
});
});
});
QUnit.module('WriteBatch', () => {
QUnit.module('function: commit', () => {
QUnit.test('should commit all of the writes in the write batch', async (assert) => {
assert.expect(7);
// Arrange
const db = mockFirebase.firestore();
const batch = db.batch();
const ref1 = db.collection('users').doc();
const ref2 = db.collection('users').doc('user_a');
const ref3 = db.collection('users').doc('user_b');
const ref4 = db.collection('users').doc('user_100');
batch.set(ref1, { username: 'new_user' });
batch.delete(ref2);
batch.update(ref3, { name: 'user-b' });
batch.set(ref4, { username: 'user_100' });
// Act
await batch.commit();
// Assert
const snapshot1 = await ref1.get();
const snapshot2 = await ref2.get();
const snapshot3 = await ref3.get();
const snapshot4 = await ref4.get();
assert.deepEqual(snapshot1.data(), { username: 'new_user' });
assert.equal(snapshot2.exists, false);
const {
age: snapshot3Age,
createdOn: snapshot3CreatedOn,
name: snapshot3Name,
username: snapshot3Username,
} = snapshot3.data();
assert.equal(snapshot3Age, 10);
assert.deepEqual(snapshot3CreatedOn.toDate(), new Date('2017-01-01'));
assert.equal(snapshot3Name, 'user-b');
assert.equal(snapshot3Username, 'user_b');
assert.deepEqual(snapshot4.data(), { username: 'user_100' });
});
QUnit.test('should commit all of the writes in order', async (assert) => {
assert.expect(2);
// Arrange
const db = mockFirebase.firestore();
const batch = db.batch();
const ref1 = db.collection('users').doc();
const ref2 = db.collection('users').doc('user_a');
batch.set(ref1, { username: 'new_user' });
batch.delete(ref1);
batch.delete(ref2);
batch.set(ref2, { username: 'new_user_2' });
batch.update(ref2, { username: 'new_user_3' });
// Act
await batch.commit();
// Assert
const snapshot1 = await ref1.get();
const snapshot2 = await ref2.get();
assert.equal(snapshot1.data(), undefined);
assert.deepEqual(snapshot2.data(), { username: 'new_user_3' });
});
});
});
QUnit.module('Transactions', () => {
QUnit.test('transaction.get: should be able to get references', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
await ref.set({ username: 'new_user' });
// Act
let user = null;
await db.runTransaction(async (tran) => {
user = await tran.get(ref);
});
// Assert
assert.deepEqual(user.data(), { username: 'new_user' });
});
QUnit.test('transaction.set: should be able to set references', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
await ref.set({ username: 'new_user' });
// Act
await db.runTransaction(async (tran) => {
await tran.set(ref, { username: 'new_user2' });
});
// Assert
const user = await db.collection('users').doc('user_a').get();
assert.deepEqual(user.data(), { username: 'new_user2' });
});
QUnit.test('transaction.update: should be able to update references', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
await ref.set({ username: 'new_user' });
// Act
await db.runTransaction(async (tran) => {
await tran.update(ref, { username: 'new_user2' });
});
// Assert
const user = await db.collection('users').doc('user_a').get();
assert.deepEqual(user.data(), { username: 'new_user2' });
});
QUnit.test('transaction.delete: should be able to delete references', async (assert) => {
assert.expect(1);
// Arrange
const db = mockFirebase.firestore();
const ref = db.collection('users').doc('user_a');
await ref.set({ username: 'new_user' });
// Act
await db.runTransaction(async (tran) => {
await tran.delete(ref);
});
// Assert
const user = await db.collection('users').doc('user_a').get();
assert.deepEqual(user.data(), undefined);
});
});
});