模拟日扩展

Mocking dayjs extend

在我需要测试的代码中我使用

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);

dayjs().add(15, 'minute')

在我的测试中,我需要模拟 dayjs,以便在比较 jest 中的快照时始终具有相同的日期,所以我做到了

jest.mock('dayjs', () =>
  jest.fn((...args) =>
    jest.requireActual('dayjs')(
      args.filter((arg) => arg).length > 0 ? args : '2020-08-12'
    )
  )
);

它失败了

TypeError: _dayjs.default.extend is not a function

不幸的是,这里的类似问题对我没有帮助。我怎么能同时模拟默认 dayjsextend

随心所欲地模拟 dayjs,不要忘记按如下方式设置静态函数:

import dayjs from "dayjs";

jest.mock('dayjs', () =>
  jest.fn((...args) =>
    jest.requireActual('dayjs')(
      args.filter((arg) => arg).length > 0 ? args : '2020-08-12'
    )
  )
);

dayjs.extend = jest.fn();

可以 dayjs 编写一个更全面的手动模拟,一个具有 extend 方法的模拟,但随后您将测试耦合到第 3 方接口。 “不要模拟你不拥有的东西” - 你最终将不得不在你的模拟中重新创建越来越多的 dayjs 界面,然后如果界面更改您的测试将继续通过,但您的代码将被破坏。或者,如果您决定切换到不同的时间库,则必须重写所有测试以手动模拟新界面。

相反,将时间视为依赖项。在您自己的模块中拥有您自己的功能,它只是将当前时间作为 Date 对象提供:

export const howSoonIsNow = () => new Date();

然后,当您需要创建一个 dayjs 对象时,从那个 开始(dayjs() 相当于 dayjs(new Date()) 每个 the docs):

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';

import { howSoonIsNow } from './path/to/noTimeLikeThePresent';

dayjs.extend(utc);

dayjs(howSoonIsNow()).add(15, 'minute');

现在在你的测试中你可以换掉你实际拥有的东西,而不必干扰 dayjs:

import { howSoonIsNow } from './path/to/noTimeLikeThePresent';

jest.mock('./path/to/noTimeLikeThePresent');

howSoonIsNow.mockReturnValue(new Date(2020, 8, 12));

现在,如果 dayjs 的新版本以某种方式改变了您对它的使用,您的测试将失败并告诉您同样的信息。或者,如果您切换到不同的时间库(here's 使用 Moment 的示例),则不必重写所有测试,因此您可以确信自己已正确切换。

此外,FWIW 我一般不评价快照测试 - 它只是变成了变化检测,因不相关的变化而失败,并鼓励人们忽略测试结果并在任何失败时盲目地重新创建快照。根据您想从组件中看到的行为进行测试。