UNPKG

mock-cloud-firestore

Version:
1,624 lines (1,257 loc) 48.4 kB
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); }); }); });