Dada una función con una firma
interface Position { x: number, y: number } function f(position: Position): void { … }Quiero burlarme de eso en una prueba.
// given const f = jest.fn() // when // exercise SUT // then expect(f).toHaveBeenCalledWith<Position>({x: 1.0, y: 1.0});Pero desafortunadamente, estoy tratando con puntos flotantes, por lo que necesito la verificación para permitir un margen de maniobra. Ahora, podría hacer
expect(f.mock.calls[0][0].x).toBeCloseTo(1, 1); expect(f.mock.calls[0][0].y).toBeCloseTo(1, 1); Pero eso envejece muy rápido. Hay un ticket que los mantenedores de Jest no parecen pensar que justifique su inclusión en Jest y un paquete que coincide con el uso de expect , ¡pero no hace lo que me gustaría hacer! Que algo como:
expect(f).toHaveBeenCalledWith( expect.objectContaining({ x: expect.numberCloseTo(1), y: expect.numberCloseTo(1) });¿Hay algo así o tengo que rodar el mío?
Como ya insinuó Aleksey, necesitaba escribir mi propio comparador personalizado. Entonces, aquí va:
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 }; }, });Y así es como lo uso:
expect(f).toHaveBeenCalledWith( expect.objectContaining<Position>({ x: expect.numberCloseTo(1, 1), y: expect.numberCloseTo(1, 1), }) );Ampliar los emparejadores ya existentes es muy incómodo en Jest, y supongo que es por diseño . Así que tenemos que incluir un mensaje ficticio.
El TS solo declare global , etc. se puede eliminar si está utilizando Flow o JS simple.