1

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

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

4

2 回答 2

4

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

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

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

然后,当您需要创建一个dayjs对象时,请从该对象开始(dayjs()相当于dayjs(new Date())每个文档):

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更改破坏了您对它的使用,您的测试将失败并告诉您同样多的信息。或者,如果您切换到不同的时间库(这里是使用 Moment 的示例),您不必重写所有测试,因此您可以确信您已正确切换。

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

于 2020-12-03T17:17:37.083 回答
-1

像你希望的那样模拟 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();

于 2020-12-03T17:14:52.937 回答