我有一个分析跟踪器,只会在 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
,但我没有看到任何对我的用例有用的东西。
这可以通过非对称匹配器来完成(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)
})
)
您可以使用
track.mock.calls[0][0]
访问预期对象以获得更好的断言(第一个 [0]
是调用编号,第二个 [0]
是参数编号)。然后您可以使用 toMatchObject
来查找部分匹配的对象,避免使用 intervalInMilliseconds
等动态参数。
重申 cl0udw4lk3r 的评论,因为我发现这在我的场景中最有用:
如果您有一个接受多个参数(而不是对象)的方法,并且您只想匹配其中一些参数,那么您可以使用对象。
示例
我想测试的方法:
client.setex(key, ttl, JSON.stringify(obj));
我想确保将正确的值传递到 key
和
ttl
但我不关心传入的对象是什么。所以我设置了一个间谍:
const setexSpy = jest.spyOn(mockClient, "setex");
然后我就可以预料到这种情况:
expect(setexSpy).toHaveBeenCalledWith('test', 99, expect.anything());
您还可以使用 (expect.any(Number)
) 等来使用更强类型的调用。
...
来扩展您正在检查的对象,然后覆盖(或添加)一个或多个值。这里是一个示例,展示如何将“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)
})
就我而言,
收到论据
{
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()
更灵活。