UNPKG

firestore-vitest

Version:

Vitest helper for mocking Google Cloud Firestore

377 lines (315 loc) 12.4 kB
describe.each([ { library: '@google-cloud/firestore', mockFunction: 'mockGoogleCloudFirestore' }, { library: '@react-native-firebase/firestore', mockFunction: 'mockReactNativeFirestore' }, ])('mocking $library with $mockFunction', ({ library, mockFunction }) => { let mockGet; let mockSelect; let mockAdd; let mockSet; let mockUpdate; let mockWhere; let mockCollectionGroup; let mockBatch; let mockBatchCommit; let mockBatchDelete; let mockBatchUpdate; let mockBatchSet; let mockSettings; let mockOnSnapShot; let mockListCollections; let mockTimestampNow; let FirestoreMock; let Timestamp; const flushPromises = () => new Promise(setImmediate); beforeAll(async () => { FirestoreMock = await import('../index'); Timestamp = (await import('../mocks/timestamp')).Timestamp; const fs = await import('../mocks/firestore'); mockGet = fs.mockGet; mockSelect = fs.mockSelect; mockAdd = fs.mockAdd; mockSet = fs.mockSet; mockUpdate = fs.mockUpdate; mockWhere = fs.mockWhere; mockCollectionGroup = fs.mockCollectionGroup; mockBatch = fs.mockBatch; mockBatchCommit = fs.mockBatchCommit; mockBatchDelete = fs.mockBatchDelete; mockBatchUpdate = fs.mockBatchUpdate; mockBatchSet = fs.mockBatchSet; mockSettings = fs.mockSettings; mockOnSnapShot = fs.mockOnSnapShot; mockListCollections = fs.mockListCollections; mockTimestampNow = fs.mockTimestampNow; }); describe('we can start a firestore application', () => { beforeEach(async () => { FirestoreMock[mockFunction]({ database: { users: [ { id: 'abc123', first: 'Bob', last: 'builder', born: 1998 }, { id: '123abc', first: 'Blues', last: 'builder', born: 1996, _collections: { cities: [ { id: 'LA', name: 'Los Angeles', state: 'CA', country: 'USA', visited: true }, ], }, }, ], cities: [ { id: 'LA', name: 'Los Angeles', state: 'CA', country: 'USA' }, { id: 'DC', name: 'Disctric of Columbia', state: 'DC', country: 'USA' }, ], }, }); this.Firestore = (await import(library)).Firestore; }); afterEach(() => mockTimestampNow.mockClear()); test('We can start an application', async () => { const firestore = new this.Firestore(); firestore.settings({ ignoreUndefinedProperties: true }); expect(mockSettings).toHaveBeenCalledWith({ ignoreUndefinedProperties: true }); }); describe('Examples from documentation', () => { test('add a user', () => { const firestore = new this.Firestore(); return firestore .collection('users') .add({ first: 'Ada', last: 'Lovelace', born: 1815, }) .then(function(docRef) { expect(mockAdd).toHaveBeenCalled(); expect(docRef).toHaveProperty('id'); }); }); test('get all users', () => { const firestore = new this.Firestore(); return firestore .collection('users') .get() .then(querySnapshot => { expect(querySnapshot.forEach).toBeTruthy(); expect(querySnapshot.docs.length).toBe(2); expect(querySnapshot.size).toBe(querySnapshot.docs.length); querySnapshot.forEach(doc => { expect(doc.exists).toBe(true); expect(doc.data()).toBeTruthy(); }); }); }); test('select specific fields only', () => { const firestore = new this.Firestore(); return firestore .collection('users') .select('first', 'last') .get() .then(querySnapshot => { expect(mockSelect).toHaveBeenCalledWith('first', 'last'); const data = querySnapshot.docs[0].data(); expect(Object.keys(data).length).toBe(2); expect(data.first).toBe('Bob'); expect(data.last).toBe('builder'); }); }); test('select refs only', () => { const firestore = new this.Firestore(); return firestore .collection('users') .select() .get() .then(querySnapshot => { expect(mockSelect).toHaveBeenCalledWith(); const data = querySnapshot.docs[0].data(); expect(Object.keys(data).length).toBe(0); }); }); test('collectionGroup at root', () => { const firestore = new this.Firestore(); return firestore .collectionGroup('users') .where('last', '==', 'builder') .get() .then(querySnapshot => { expect(mockCollectionGroup).toHaveBeenCalledWith('users'); expect(mockGet).toHaveBeenCalled(); expect(mockWhere).toHaveBeenCalledWith('last', '==', 'builder'); expect(querySnapshot.forEach).toBeTruthy(); expect(querySnapshot.docs.length).toBe(2); expect(querySnapshot.size).toBe(querySnapshot.docs.length); querySnapshot.forEach(doc => { expect(doc.exists).toBe(true); expect(doc.data()).toBeTruthy(); }); }); }); test('collectionGroup with subcollections', () => { vi.clearAllMocks(); const firestore = new this.Firestore(); return firestore .collectionGroup('cities') .where('country', '==', 'USA') .get() .then(querySnapshot => { expect(mockCollectionGroup).toHaveBeenCalledWith('cities'); expect(mockGet).toHaveBeenCalledTimes(1); expect(mockWhere).toHaveBeenCalledWith('country', '==', 'USA'); expect(querySnapshot.forEach).toBeTruthy(); expect(querySnapshot.docs.length).toBe(3); expect(querySnapshot.size).toBe(querySnapshot.docs.length); querySnapshot.forEach(doc => { expect(doc.exists).toBe(true); expect(doc.data()).toBeTruthy(); }); }); }); test('set a city', () => { const firestore = new this.Firestore(); return firestore .collection('cities') .doc('LA') .set({ name: 'Los Angeles', state: 'CA', country: 'USA', }) .then(function() { expect(mockSet).toHaveBeenCalledWith({ name: 'Los Angeles', state: 'CA', country: 'USA', }); }); }); test('updating a city', () => { const firestore = new this.Firestore(); const now = Timestamp._fromMillis(new Date().getTime()); const washingtonRef = firestore.collection('cities').doc('DC'); mockTimestampNow.mockReturnValue(now); return washingtonRef .update({ capital: true, }) .then(function(value) { expect(value.updateTime).toStrictEqual(now); expect(mockUpdate).toHaveBeenCalledWith({ capital: true }); }); }); test('batch writes', () => { const firestore = new this.Firestore(); // Get a new write batch const batch = firestore.batch(); // Set the value of 'NYC' const nycRef = firestore.collection('cities').doc('NYC'); batch.set(nycRef, { name: 'New York City' }); // Update the population of 'SF' const sfRef = firestore.collection('cities').doc('SF'); batch.update(sfRef, { population: 1000000 }); // Delete the city 'LA' const laRef = firestore.collection('cities').doc('LA'); batch.delete(laRef); // Commit the batch return batch.commit().then(function() { expect(mockBatch).toHaveBeenCalled(); expect(mockBatchDelete).toHaveBeenCalledWith(laRef); expect(mockBatchUpdate).toHaveBeenCalledWith(sfRef, { population: 1000000 }); expect(mockBatchSet).toHaveBeenCalledWith(nycRef, { name: 'New York City' }); expect(mockBatchCommit).toHaveBeenCalled(); }); }); test('listCollections returns a promise', async () => { const firestore = new this.Firestore(); const listCollectionsPromise = firestore.collection('cities').doc('LA').listCollections(); expect(listCollectionsPromise).toEqual(expect.any(Promise)); }); test('listCollections resolves with child collections', async () => { const firestore = new this.Firestore(); const result = await firestore.collection('users').doc('123abc').listCollections(); expect(result).toEqual(expect.any(Array)); expect(result).toHaveLength(1); expect(result[0]).toEqual(expect.any(this.Firestore.CollectionReference)); expect(result[0].id).toBe('cities'); }); test('listCollections resolves with empty array if there are no collections in document', async () => { const firestore = new this.Firestore(); const result = await firestore.collection('users').doc('abc123').listCollections(); expect(result).toEqual(expect.any(Array)); expect(result).toHaveLength(0); }); test('listCollections calls mockListCollections', async () => { const firestore = new this.Firestore(); await firestore.collection('users').doc('abc123').listCollections(); expect(mockListCollections).toHaveBeenCalled(); }); test('onSnapshot single doc', async () => { const firestore = new this.Firestore(); const now = Timestamp._fromMillis(new Date().getTime()); mockTimestampNow.mockReturnValue(now); firestore .collection('cities') .doc('LA') .onSnapshot(doc => { expect(doc).toHaveProperty('createTime'); expect(doc).toHaveProperty('data'); expect(doc.data).toBeInstanceOf(Function); expect(doc).toHaveProperty('metadata'); expect(doc).toHaveProperty('readTime'); expect(doc).toHaveProperty('updateTime'); expect(doc.readTime).toStrictEqual(now); }); await flushPromises(); expect(mockOnSnapShot).toHaveBeenCalled(); }); test('onSnapshot can work with options', async () => { const firestore = new this.Firestore(); const now = Timestamp._fromMillis(new Date().getTime()); mockTimestampNow.mockReturnValue(now); firestore .collection('cities') .doc('LA') .onSnapshot( { // Listen for document metadata changes includeMetadataChanges: true, }, doc => { expect(doc).toHaveProperty('createTime'); expect(doc).toHaveProperty('data'); expect(doc.data).toBeInstanceOf(Function); expect(doc).toHaveProperty('metadata'); expect(doc).toHaveProperty('readTime'); expect(doc).toHaveProperty('updateTime'); expect(doc.readTime).toStrictEqual(now); }, ); await flushPromises(); expect(mockOnSnapShot).toHaveBeenCalled(); }); test('onSnapshot with query', async () => { const firestore = new this.Firestore(); const unsubscribe = firestore .collection('cities') .where('state', '==', 'CA') .onSnapshot(querySnapshot => { expect(querySnapshot).toHaveProperty('forEach', expect.any(Function)); expect(querySnapshot).toHaveProperty('docChanges'); expect(querySnapshot).toHaveProperty('docs', expect.any(Array)); expect(querySnapshot.forEach).toBeInstanceOf(Function); expect(querySnapshot.docChanges).toBeInstanceOf(Function); expect(querySnapshot.docs).toBeInstanceOf(Array); expect(querySnapshot.docChanges()).toBeInstanceOf(Array); }); await flushPromises(); expect(unsubscribe).toBeInstanceOf(Function); expect(mockWhere).toHaveBeenCalled(); expect(mockOnSnapShot).toHaveBeenCalled(); }); }); }); });