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 ?:
mockImplementation
mockImplementationOnce
mockResolvedValue
mockResolvedValueOnce
mockReturnValue
mockReturnValueOnce
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