首页 > 解决方案 > Jest 中针对模拟调用 argumnets 的模糊浮点检查

问题描述

给定一个带有签名的函数

interface Position {
  x: number, y: number
}

function f(position: Position): void { … }

我想在测试中模拟它

// given
const f = jest.fn()

// when
// exercise SUT

// then
expect(f).toHaveBeenCalledWith<Position>({x: 1.0, y: 1.0});

但不幸的是,我正在处理浮点数,所以我需要检查以留出一些余地。现在,我可以

expect(f.mock.calls[0][0].x).toBeCloseTo(1, 1);
expect(f.mock.calls[0][0].y).toBeCloseTo(1, 1);

但这很快就会变老。有一张 Jest 维护者似乎不认为值得包含在 Jest 中的票和一个匹配使用expect的包,但它并没有做我想做的事情!类似于:

expect(f).toHaveBeenCalledWith(
  expect.objectContaining({
    x: expect.numberCloseTo(1), 
    y: expect.numberCloseTo(1)
   });

有类似的东西还是我必须自己动手?

标签: javascripttypescriptjestjs

解决方案


正如 Aleksey 已经暗示的那样,我需要编写自己的自定义匹配器。所以,这里是:

declare global {
  namespace jest {
    interface Expect {
      numberCloseTo(expected: number, precision?: number): any;
    }
  }
}

expect.extend({
  numberCloseTo(actual: number, expected: number, precision: number = 2) {
    expect(actual).toBeCloseTo(expected, precision);
    return { message: () => "This shouldn't happen.", pass: true };
  },
});

这是我使用它的方式:

expect(f).toHaveBeenCalledWith(
  expect.objectContaining<Position>({
    x: expect.numberCloseTo(1, 1),
    y: expect.numberCloseTo(1, 1),
  })
);

在 Jest 中扩展已经存在的匹配器是非常尴尬的,我猜这是设计使然。所以我们需要包含一个虚拟消息。

declare global如果您使用的是 Flow 或纯 JS,则可以删除仅 TS等。


推荐阅读