使用Date对象的组件在不同的时区生成不同的快照

时间:2016-12-02 15:39:12

标签: javascript reactjs jestjs enzyme

我使用Enzymeenzyme-to-json对我的React组件进行Jest快照测试。我正在测试DateRange组件的浅快照,这些组件呈现具有当前范围的显示字段(例如5/20/2016 - 7/18/2016)和两个允许选择DateInput的{​​{1}}组件值。这意味着我的快照包含Date我在Date道具中传递给组件的DateInput以及它自己解析的文本表示。在我的测试中,我使用new Date(1995, 4, 23)创建了一些固定日期。

当我在不同时区运行测试时,会生成不同的快照,因为Date(year, month, ...)构造函数会在本地时区创建日期。例如。使用new Date()会在本地时区和CI服务器上的运行之间产生快照差异。

- value={1995-05-22T22:00:00.000Z}
+ value={1995-05-23T00:00:00.000Z}

我尝试从日期中删除时区偏移量,但随后快照在显示字段值中有所不同,其中使用了与本地时区相关的表示。

- value={5/20/2016 - 7/18/2016}
+ value={5/19/2016 - 7/17/2016}

如何让我的测试在快照中生成相同的Date,无论他们在哪个时区运行?

6 个答案:

答案 0 :(得分:46)

我挣扎了好几个小时/天,只有这对我有用:

1)在你的测试中:

Date.now = jest.fn(() => new Date(Date.UTC(2017, 7, 9, 8)).valueOf())

2)然后在运行测试之前更改TZ env var。 所以我的package.json中的脚本:

  • Mac&仅限Linux

    "test": "TZ=America/New_York react-scripts test --env=jsdom",
    
  • Windows

    "test": "set TZ=America/New_York && react-scripts test --env=jsdom",
    

答案 1 :(得分:4)

我最终得到了一个由两部分组成的解决方案。

  1. 永远不要以与时区相关的方式在测试中创建Date个对象。如果您不想直接使用时间戳来获得可读的测试代码,请使用Date.UTC,例如

    new Date(Date.UTC(1995, 4, 23))
    
  2. 模拟用于将Date转换为显示值的日期格式化程序,以便返回与时区无关的表示形式,例如:使用Date::toISOString()幸运的是,在我的情况下,这很容易,因为我只需要在我的本地化模块中模拟formatDate函数。如果组件以某种方式将Date转换为字符串,可能会更难。
  3. 在我到达上述解决方案之前,我试图以某种方式更改快照的创建方式。这很丑陋,因为酶到json保存了toISOString()的本地副本,所以我不得不使用_.cloneDeepWith并修改所有Date。无论如何它对我来说都没有用,因为我的测试还包含Date从时间戳创建的情况(组件比我上面描述的要复杂得多)以及那些和我之间的日期之间的相互作用明确地在测试中创建。所以我首先必须确保我的所有日​​期定义都指的是相同的时区,其余时间也是如此。

    更新(2017年11月3日):当我最近检查enzyme-to-json时,我无法找到toISOString()的本地保存,所以可能是&#39 ; s不再是问题而且可以被嘲笑。尽管如此,我还是无法在历史中找到它,所以也许我只是错误地注意到哪个库做了它。自担风险:)

答案 2 :(得分:2)

我通过使用timezone-mock来做到这一点,它在内部替换了全局Date对象,这是我能找到的最简单的解决方案。

该程序包支持一些测试时区。

import timezoneMock from 'timezone-mock';

describe('when in PT timezone', () => {
  beforeAll(() => {
    timezoneMock.register('US/Pacific');
  });

  afterAll(() => {
    timezoneMock.unregister();
  });

  // ...

https://www.npmjs.com/package/timezone-mock

答案 3 :(得分:0)

我最终通过模拟toLocaleString(或者你使用的任何toString方法)原型来解决这个问题。使用sinon我做了:

var toLocaleString;

beforeAll(() => {
    toLocaleString = sinon.stub(Date.prototype, 'toLocaleString', () => 'fake time')
})

afterAll(() => {
    toLocaleString.restore()
})

这样,如果你直接从Date对象生成字符串,那么你仍然可以。

答案 4 :(得分:0)

如果您使用checkresidual(..., df=DF) 构造函数而不是Date。现在,您可以执行以下操作:

new Date()
如果您在这里,

This issue是必游之地。

答案 5 :(得分:0)

TZ=UTC添加到我的.env文件中为我解决了这个问题。