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

c8ib6hqw  于 2023-01-11  发布在  Java
关注(0)|答案(9)|浏览(114)

我正在使用Enzymeenzyme-to-json对React组件进行Jest快照测试。(例如5/20/2016 - 7/18/2016)和允许选择Date值的两个DateInput分量。这意味着我的快照包含了我传递给组件的Date,它既包含在DateInput属性中,也包含在一个文本表示中,它会自行解析。

当我在不同的时区运行测试时,这会产生不同的快照,因为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,而不管它们在哪个时区运行?

sdnqo3pr

sdnqo3pr1#

我为此挣扎了几个小时/几天,只有这个对我有效:
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",
mi7gmzs6

mi7gmzs62#

我最终得到了一个由两部分组成的解决方案。
1.永远不要在测试中以时区相关的方式创建Date对象。如果你不想直接使用时间戳来获得可读的测试代码,可以使用Date.UTC,例如:

new Date(Date.UTC(1995, 4, 23))

1.模拟用于将Date s转换为显示值的日期格式化程序,使其返回一个与时区无关的表示,例如使用Date::toISOString()。* 幸运的是,这在我的例子中很容易,因为我只需要模拟本地化模块中的formatDate函数。

  • 在我使用上面的解决方案之前,我尝试过改变快照的创建方式。这很难看,因为enzyme-to-json保存了toISOString()的本地副本,所以我不得不使用_.cloneDeepWith并修改所有的Date。因为我的测试还包含了从时间戳创建Date的情况(该组件比我上面描述的要复杂得多)以及这些数据和我在测试中显式创建的日期之间的交互。因此,我首先必须确保我所有的日期定义都指向同一时区,然后才能定义其他日期。
  • 更新日期(2017年11月3日):当我最近检查enzyme-to-json时,我无法找到本地保存的toISOString(),所以这可能不再是一个问题,它可以被嘲笑。我也无法在历史中找到它,所以可能我只是错误地指出了哪个库做了它。测试风险自担:)*
qzlgjiam

qzlgjiam3#

我是通过使用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

ckocjqey

ckocjqey4#

我最后通过模拟toLocaleString(或者您使用的任何toString方法)原型来解决这个问题。

var toLocaleString;

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

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

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

aydmsdu9

aydmsdu95#

适合我的2020年解决方案

beforeEach(() => {
        jest.useFakeTimers('modern');
        jest.setSystemTime(Date.parse(FIXED_SYSTEM_TIME));
});

afterEach(() => {
        jest.useRealTimers();
});
3zwtqj6y

3zwtqj6y6#

如果你使用的是new Date()构造函数而不是Date.now,你可以这样做:

const RealDate = Date;

beforeEach(() => {
  // @ts-ignore
  global.Date = class extends RealDate {
    constructor() {
      super();
      return new RealDate("2016");
    }
  };
})
afterEach(() => {
  global.Date = RealDate;
});

如果你来这里,一定要来This issue

jhkqcmku

jhkqcmku7#

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

i7uaboj4

i7uaboj48#

一个简单的事实可以使它变得容易。
只需用途:

new Date('some string').

这将始终给予一个无效的日期,无论是哪台机器,它将始终是无效的日期。
干杯。

b4wnujal

b4wnujal9#

尝试在调用new Date()时传递一个随机日期,如new Date(1466424490000)

相关问题