开玩笑的打字稿 - 模拟日期构造函数

Posted

技术标签:

【中文标题】开玩笑的打字稿 - 模拟日期构造函数【英文标题】:jest typescript - Mock Date constructor 【发布时间】:2020-07-09 17:28:45 【问题描述】:

我正在尝试模拟 new Date() 以返回特定日期。以下代码:

const now = new Date()
jest.spyOn(global, 'Date').mockImplementation(() => now)

给出编译错误:Argument of type '() => Date' is not assignable to parameter of type '() => string'. Type 'Date' is not assignable to type 'string'

我认为原因是 jest 认为我试图模拟 Date() 而不是 new Date()。实际上,Date() 返回一个字符串。我该如何解决这个问题?

【问题讨论】:

找到解决方案了吗? 不。我使用了一种解决方法:我只在我的代码中使用new Date(Date.now()) 而从不使用new Date()。这样我就可以模拟Date.now() 【参考方案1】:

一种解决方法是使用mockdate 库,可用于在“现在”时进行更改。

const MockDate = require('mockdate');

test('Mock Date to change when "now" is', () => 
  console.log('Normal:   ', new Date().getTime());

  MockDate.set(new Date(1466424490000));

  console.log('Mocked:   ', new Date().getTime());

  MockDate.reset();

  console.log('Restored: ', new Date().getTime());
);

而测试结果是这样的:

$ npm run test
> jest

 PASS  src/test.ts
  ✓ Mock Date to change when "now" is (8ms)

  console.log src/test.ts:4
    Normal:    1585505136315

  console.log src/test.ts:8
    Mocked:    1466424490000

  console.log src/test.ts:12
    Restored:  1585505136322

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.804s

见the reference project on GitHub。

【讨论】:

谢谢。我认为该库之所以有效,是因为它使用的是 JS,而不是 TypeScript。我怀疑问题出在从 TS 到 JS 的翻译上。我正在寻找 TS 解决方案。 @EllaSharakanski 这个库现在在 TS 中。【参考方案2】:

好吧,我试过这个解决方案,它奏效了..

class MockDate extends Date 
    constructor() 
        super("2020-05-14T11:01:58.135Z"); // add whatever date you'll expect to get
    

在该测试的 beforeEach 中,我添加了:

// @ts-ignore
global.Date = MockDate;

这样,每当我调用一个内部有 new Date() 的函数时,它都会返回我在上面的 MockDate 类的构造函数中添加的日期!

【讨论】:

你可以通过附加到你的类声明as unknown as typeof Date来避免//@ts-ignore Jest 不建议这样做。您应该将 Jest Spies 用于任何全局类。 好主意!但是当调用data.getFullYear() 我得到this is not a Date object.【参考方案3】:

告诉编译器它想听什么:说它是一个转换为未知的字符串,然后是转换为字符串:

const now = new Date() as unknown as string

【讨论】:

这对嘲笑没有帮助 从 Aaron Goldman 的评论中你可以推断出他的意思是 const mockDate = new Date(1466424490000) const spy = jest.spyOn(global, 'Date') .mockImplementation(() => mockDate as unknown as string) 但是 new Date() 现在返回一个字符串以及对 new Date() 的任何调用,例如new Date().getTime() 将不起作用,因为 "string".getTime() 不是函数【参考方案4】:

Daryn 对 Arron 的回答的推理评论在没有额外包的情况下效果很好。

const mockDate = new Date();
jest.spyOn(global, "Date").mockImplementation(() => (mockDate as unknown) as string);
const myDate = new Date();

【讨论】:

终于!这对我有用【参考方案5】:

我在使用 jest typescript 模拟 new Date() 时遇到了同样的问题 当尝试在函数中模拟 Date 时:

export const checkValidTime(): boolean =>  
  const now = new Date();
  const maxAllowTime = new Date('2020-02-02 09:00:00');

  console.log(`currentTime: $now.toLocaleString()`);
  console.log(`maxAllowTime: $maxAllowTime.toLocaleString()`);

  return now > maxAllowTime;

单元测试中的模拟解决方案:

const mockDate = new Date('2021-09-03 08:00:10');
jest
    .spyOn(global, 'Date')
    .mockImplementationOnce(() => (mockDate as unknown) as string);
const valid = checkDateTime();
expect(valid).toEqual(true);

【讨论】:

以上是关于开玩笑的打字稿 - 模拟日期构造函数的主要内容,如果未能解决你的问题,请参考以下文章

使用打字稿在构造函数中动态设置类属性

类装饰器上的打字稿文档-返回“类扩展构造函数”的函数

何时在 Angular2 打字稿中创建构造函数?

打字稿:通过传入命名参数的构造函数创建类?

打字稿接口和承诺返回一个对象/构造函数?

从类创建派生类型,但省略构造函数(打字稿)