Home > Software design >  Jest testing the same promise response in different types each time
Jest testing the same promise response in different types each time

Time:02-10

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
  • Related