Jest 每次都测试不同类型的相同承诺响应

Jest testing the same promise response in different types each time

如何正确测试可以不同类型的相同承诺响应?

例如,当从 Cloud Firestore 数据库中获取项目集合时,响应是一种数组类型,但是有一种方法可以与响应进行交互,就像它是一种对象类型一样。这是代码:

// ...
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
})
// ...

我试图通过在每次调用后返回一个不同的值来测试它,但它现在正在工作,我收到一个错误: 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 }) })
        }
      }
    })
  }
})

这是怎么回事?在所有这些嘲笑中我应该使用什么?:

您不需要使用 class 来创建测试替身。这让事情变得复杂。只需使用 JS 普通对象数据类型 - Array 来制作 firestore 的查询快照。使用Object制作查询文档快照。

您可以将自定义属性添加到 JS 数组,例如 snapshot.docssnapshot.size

例如

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);
  });
});

测试结果:

 PASS  Whosebug/71058297/index.test.ts
  71058297
    ✓ should pass (24 ms)

  console.log
    { published: true, name: 'steam deck' }

      at Whosebug/71058297/index.ts:33:17
          at Array.forEach (<anonymous>)

  console.log
    1

      at Whosebug/71058297/index.ts:36:13

  console.log
    1

      at Whosebug/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