Here is a complete example on how I use sinon to mock away Firestore.
In the function-under-test getAssets I pass firestore as its first argument. You can also choose just replace a global firestore variable using rewire or proxyquire or any other way, that would be out of scope for this answer.
In the test, there is an example AssetData[] that represents a collection. And the call to setupAssets turns this into a mocked firestore that would return this collection when queried.
The function setupAssets returns all the intermediate mocks it creates as well, these can be inspected for their call arguments and number of calls in your test.
Example test with mocked firestore:
it('gets existing assets', async () => {
const userId = 'user-id'
const assetName = 'asset-name'
const assets: AssetData[] = [{ asset: assetName, amount: 1, avgPrice: '1.00' }]
const { firestore } = setupAssets(assetName, userId, assets)
const result = await assetFuncs.getAssets(firestore, userId, assetName)
t.deepEqual(result.docs, assets)
})
The actual code that gets the assets:
async function getAssets (firestore: firestore.Firestore, userId: string, asset: string) {
const colRef = firestore.collection(`users/${userId}/assets`)
const query = colRef.where('asset', '==', asset)
return query.get()
}
And finally the sinon mocking function that sets up a fake Firestore:
function setupAssets (assetName: string, userId: string, assets: AssetData[]) {
const firestore = sinon.createStubInstance(firestore.Firestore)
const collectionRef = sinon.createStubInstance(firestore.CollectionReference)
const query = sinon.createStubInstance(firestore.Query)
const querySnapshot = sinon.createStubInstance(firestore.QuerySnapshot)
const docSnapshots = assets.map(asset => {
const docSnapshot = sinon.createStubInstance(firestore.DocumentSnapshot)
Object.defineProperty(docSnapshot, 'id', { value: crypto.randomUUID() })
docSnapshot.data.returns(asset)
return docSnapshot
})
Object.defineProperty(querySnapshot, 'docs', { value: docSnapshots })
query.get.resolves(querySnapshot)
collectionRef.where.withArgs('asset', '==', assetName).returns(query)
firestore.collection.withArgs(`users/${userId}/assets`).returns(collectionRef)
return { firestore, collectionRef, query, querySnapshot, docSnapshots }
}