How do I properly test the same promise response which can be in different type ?
For example, when fetching a collection of items from Cloud Firestore database, response is in a type of an array, but there is a way to interact with a response as it was in a type of an object. Here is the code:
// ...
await Database.collection('products').select('published').get().then(snapshot => {
snapshot.forEach(doc => { // <---- HERE snapshot IS AN ARRAY
if (doc.data().published) {
// ...
}
})
console.log(snapshot.docs.length) // <---- HERE snapshot IS AN OBJECT. HOW ?
console.log(snapshot.size) // IT'S THE SAME AS snapshot.docs.length
})
// ...
I'm trying to test it by returning a value differently after each call, but it's now working, I'm getting an error: TypeError: Cannot read property 'length' of undefined:
jest.doMock('@google-cloud/firestore', () => class {
constructor () {
this.collection = jest.fn().mockImplementation((collectionName) => {
if (collectionName === 'products') {
return {
select: () => ({
get: jest.fn().mockResolvedValueOnce([ // <--- AN ARRAY
{
data: () => {
return {
published: false
}
}
}
]).mockResolvedValueOnce({ // <---- AN OBJECT
docs: () => []
})
}),
limit: () => ({ get: async () => ({ empty: true }) })
}
}
})
}
})
What's wrong here ? What should I use among all those mockings ?:
mockImplementationmockImplementationOncemockResolvedValuemockResolvedValueOncemockReturnValuemockReturnValueOnce
CodePudding user response:
You don't need to use class to create test doubles. It makes things complicated. Just use the JS plain object data type - Array to make the query snapshot of firestore. Use Object to make the query document snapshot.
You can add custom properties to the JS array such as snapshot.docs and snapshot.size.
E.g.
index.ts:
import { Firestore } from '@google-cloud/firestore';
export async function main() {
const Database = new Firestore();
await Database.collection('products')
.select('published')
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
if (doc.data().published) {
console.log(doc.data());
}
});
console.log(snapshot.docs.length);
console.log(snapshot.size);
});
}
index.test.ts:
describe('71058297', () => {
beforeEach(() => {
jest.resetModules();
});
test('should pass', async () => {
const mDocument1 = { data: jest.fn(() => ({ published: true, name: 'steam deck' })) };
const mQuerySnapshot: any = [mDocument1];
mQuerySnapshot.docs = mQuerySnapshot;
mQuerySnapshot.size = mQuerySnapshot.docs.length;
const mFirestore = {
collection: jest.fn().mockReturnThis(),
select: jest.fn().mockReturnThis(),
get: jest.fn().mockResolvedValueOnce(mQuerySnapshot),
};
const MockFireStore = jest.fn(() => mFirestore);
jest.doMock('@google-cloud/firestore', () => ({ Firestore: MockFireStore }));
const { main } = require('./');
await main();
expect(MockFireStore).toBeCalledTimes(1);
expect(mFirestore.collection).toBeCalledWith('products');
expect(mFirestore.select).toBeCalledWith('published');
expect(mFirestore.get).toBeCalledTimes(1);
expect(mDocument1.data).toBeCalledTimes(2);
});
});
Test result:
PASS stackoverflow/71058297/index.test.ts
71058297
✓ should pass (24 ms)
console.log
{ published: true, name: 'steam deck' }
at stackoverflow/71058297/index.ts:33:17
at Array.forEach (<anonymous>)
console.log
1
at stackoverflow/71058297/index.ts:36:13
console.log
1
at stackoverflow/71058297/index.ts:37:13
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.595 s, estimated 2 s
