松散匹配 .toHaveBeenCalledWith 中的一个值

问题描述 投票:0回答:5

我有一个分析跟踪器,只会在 1 秒后调用,并且使用一个对象,其中

intervalInMilliseconds
(持续时间)值不是确定性。

如何使用

.toHaveBeenCalledWith
来测试对象?

 test('pageStats - publicationPage (will wait 1000ms)', done => {
  const track = jest.fn()

  const expected = new PayloadTiming({
    category: 'PublicationPage',
    action: 'PublicationPage',
    name: 'n/a',
    label: '7',
    intervalInMilliseconds: 1000 // or around
  })

  mockInstance.viewState.layoutMode = PSPDFKit.LayoutMode.SINGLE
  const sendPageStats = pageStats({
    instance: mockInstance,
    track,
    remoteId: nappConfig.remoteId
  })
      mockInstance.addEventListener('viewState.currentPageIndex.change', sendPageStats)

      setTimeout(() => {
        mockInstance.fire('viewState.currentPageIndex.change', 2)

        expect(track).toHaveBeenCalled()
        expect(track).toHaveBeenCalledWith(expected)

        done()
      }, 1000)

      expect(track).not.toHaveBeenCalled()
    })

expect(track).toHaveBeenCalledWith(expected)
失败并显示:

Expected mock function to have been called with:
      {"action": "PublicationPage", "category": "PublicationPage", "intervalInMilliseconds": 1000, "label": "7", "name": "n/a"}
    as argument 1, but it was called with
      {"action": "PublicationPage", "category": "PublicationPage", "intervalInMilliseconds": 1001, "label": "7", "name": "n/a"}

我已经查看了

jest-extended
,但我没有看到任何对我的用例有用的东西。

jestjs
5个回答
340
投票

这可以通过非对称匹配器来完成(Jest 18 中引入)

expect(track).toHaveBeenCalledWith(
  expect.objectContaining({
   "action": "PublicationPage", 
   "category": "PublicationPage", 
   "label": "7",
   "name": "n/a"
  })
)

如果你使用

jest-extended
你可以做类似的事情

expect(track).toHaveBeenCalledWith(
  expect.objectContaining({
   "action": "PublicationPage", 
   "category": "PublicationPage", 
   "label": "7",
   "name": "n/a",
   "intervalInMilliseconds": expect.toBeWithin(999, 1002)
  })
)

51
投票

您可以使用

track.mock.calls[0][0]
访问预期对象以获得更好的断言(第一个
[0]
是调用编号,第二个
[0]
是参数编号)。然后您可以使用
toMatchObject
来查找部分匹配的对象,避免使用
intervalInMilliseconds
等动态参数。


36
投票

重申 cl0udw4lk3r 的评论,因为我发现这在我的场景中最有用:

如果您有一个接受多个参数(而不是对象)的方法,并且您只想匹配其中一些参数,那么您可以使用

expect

 对象

示例

我想测试的方法:

client.setex(key, ttl, JSON.stringify(obj));
我想确保将正确的值传递到 

key

ttl
 但我不关心传入的对象是什么。所以我设置了一个间谍:

const setexSpy = jest.spyOn(mockClient, "setex");
然后我就可以预料到这种情况:

expect(setexSpy).toHaveBeenCalledWith('test', 99, expect.anything());
您还可以使用 

expect.any

 (expect.any(Number)
) 等来使用更强类型的调用。


22
投票
我最喜欢的方式。您可以使用扩展运算符

...

 来扩展您正在检查的对象,然后覆盖(或添加)一个或多个值。

这里是一个示例,展示如何将“intervalInMilliseconds”预期值覆盖为任何数字

const track = jest.fn() const expected = new PayloadTiming({ category: 'PublicationPage', action: 'PublicationPage', name: 'n/a', label: '7', intervalInMilliseconds: 1000 // or around }) expect(track).toHaveBeenCalledWith( { ...expected, intervalInMilliseconds: expect.any(Number) })
另一个示例展示如何覆盖两个值

expect(track).toHaveBeenCalledWith( { ...expected, intervalInMilliseconds: expect.any(Number), category: expect.any(String) })
    

0
投票
对于后来的人来说,只想匹配对象内部对象的一部分。

就我而言,

收到论据

{ data: { attributes: { address: 'test address', area: 10000, 'area-unit': 'square_feet', industry: 'agricultural', latitude: 30, longitude: 104, name: 'test', timezone: 'Asia/Shanghai', }, relationships: { account: { data: { id: '96', type: 'accounts' } }, users: { data: [ { id: '1180', type: 'users' }, { id: '1281', type: 'users' }, ], }, }, type: 'buildings', }, };
而我要匹配的是

data.attributes

。
所以我可以使用下面的代码来获取被调用函数的参数(
我的函数只有一个参数,如果你想测试第一次调用的第二个参数,它将是mockFn.mock.calls[0][1]

const arg0 = mockFn.mock.calls[0][0]; expect(arg0.data.attributes).toEqual({ address: 'test address', area: 10000, 'area-unit': 'square_feet', industry: 'agricultural', latitude: 30, longitude: 104, name: 'test', timezone: 'Asia/Shanghai', });
我认为在某些情况下它比 

expect.objectContaining(object)

.toMatchObject()
 更灵活。

© www.soinside.com 2019 - 2024. All rights reserved.