node.js - 为什么多次调用 jest mockResolvedValueOnce 返回相同的值?

标签 node.js unit-testing jestjs

我有一个类方法,可以多次触发 @google-cloud/firestore 。我想多次模拟对同一个 .get() 方法的调用。 多次使用 mockResolvedValueOnce 并返回不同的值,第二个值将被忽略。

    jest.doMock('@google-cloud/firestore', () => class {
      collection () {
        return {
          get: jest.fn().mockResolvedValue({
            docs: []
          }),
          doc: () => {
            return {
              set: jest.fn(),
              get: jest.fn().mockResolvedValueOnce({})
            }
          },
          limit: () => {
            return {
              get: jest.fn().mockResolvedValue({ empty: true })
            }
          },
          onSnapshot: jest.fn(),
          select: () => {
            return {
              get: jest.fn() // <------------ MULTIPLE CALLS CHAINED BELOW
                .mockResolvedValueOnce({
                  size: 1
                }).mockResolvedValueOnce({
                  size: 2
                })
            }
          }
        }
      }
    })

当我 console.log(snapshot.size) 时,两次调用都会返回相同的值“1”两次。

if (isEmptyModels || isStatsEmptyModels) {
  // ...
  console.log('📊 [STATS][MODELS] - Fulfilling the counters')
  await Database.collection('models').select('id').get().then(snapshot => {
    console.log(snapshot.size) // <--------- 1st call
    this.fields.models.count = snapshot.size
    this.fields.models.linked = snapshot.size
  })
  // ...
}

if (isEmptyProducts1P || isStatsEmptyProducts1P) {
  // ...
  console.log('📊 [STATS][PRODUCTS1P] - Fulfilling the counters')
  await Database.collection('products1P').select('isMaintained').get().then(snapshot => {
    console.log(snapshot.size) // <--------- 2nd call
    snapshot.forEach(doc => {
      if (doc.data().isMaintained) {
        // ...
      }
    })
    // ...
  })
  // ...
}

这是为什么,这里做错了什么?

错误消息是:

  console.log
    📊 [STATS][MODELS] - Fulfilling the counters

      at Statistics.fulfillProductsCount (app/services/statistics/index.js:95:15)

  console.log
    1

      at app/services/statistics/index.js:97:17

  console.log
    📊 [STATS][PRODUCTS1P] - Fulfilling the counters

      at Statistics.fulfillProductsCount (app/services/statistics/index.js:106:15)

  console.log
    1

      at app/services/statistics/index.js:108:17


    TypeError: snapshot.forEach is not a function

      117 |       await Database.collection('products1P').select('isMaintained').get().then(snapshot => {
      118 |         console.log(snapshot.size)
    > 119 |         snapshot.forEach(doc => {
          |                  ^
      120 |           if (doc.data().isMaintained) {
      121 |             this.fields.products1P.maintained += 1
      122 |           } else {

      at app/services/statistics/index.js:119:18

最佳答案

发生这种情况是因为每次调用Database.collection()时,它都会创建一个新对象,并且作为一个新对象,这是第一次调用它的属性。它对于集合内的其他函数也有效。

我的意思是 Database.collection 是一个返回一个对象的函数,该对象包含其他函数,这些函数返回包含模拟属性的对象。通过这种方式模拟,您将永远无法使用模拟...ValueOnce。但是,我看到有两种方法可以“绕过”这个问题:

1 - 简短但矛盾的方式

您可以使用.mockReturnThis()来避免进入深层模拟对象/函数,但在处理具有多次相同方法名称的“胖”类时可能会很快发生冲突。在模拟可链接方法时也很有帮助(例如:使用 .find().filter().sort()... 进行 ORM 查询。

jest.doMock('@google-cloud/firestore', () => class {
  collection = jest.fn().mockReturnThis();
  select = jest.fn().mockReturnThis();
  get = jest.fn().mockResolvedValueOnce({ size: 1 }).mockResolvedValueOnce({ size: 2 });
})

2 - 漫长但有效的方法

模拟整个集合方法一次,而不是仅模拟 collection().select().get()

Database.collection.prototype.mockReturnValueOnce({
  select: () => {
    get: () => ({ size: 1 })
  }
}).mockReturnValueOnce({
  select: () => {
    get: () => ({ size: 2 })
  }
})

--> 您将需要访问模拟的类并模拟原型(prototype)的方法“集合”(collection = jest.fn())。

关于node.js - 为什么多次调用 jest mockResolvedValueOnce 返回相同的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71049272/

相关文章:

javascript - 如何使用 node.js 生成唯一 ID

javascript - 有没有办法在将控制权移交给 Meteor.js 之前访问 Node.js,以便为某些请求提供静态站点?

java - java.util.Date 的可模拟帮助器类

javascript - 如何使用 ES6 对象传播来更新数组中的对象?

node.js - 无法在 Gulp 下运行项目

node.js - 'npm install' 和 'npm rebuild' 有什么区别?

unit-testing - 在 Vue Test Utils 中模拟退格键

javascript - 使用 jasmine 模拟函数调用

javascript - 如何将 Jest 测试移动到/test 文件夹并让它们运行?

javascript - 开 Jest | Enzyme 如何测试 onClick 事件期间是否调用组件内的函数?