首页 文章

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

提问于
浏览
22

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

When I run my test in different timezones, this produces different snapshots ,因为 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}

How can I make my tests produce the same Dates in snapshots regardless of the timezone they're run in?

3 回答

  • 32

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

    • 永远不要以与时区相关的方式在测试中创建 Date 对象 . 如果您不想直接使用时间戳来获得可读的测试代码,请使用 Date.UTC ,例如
    new Date(Date.UTC(1995, 4, 23))
    
    • 模拟用于将 Date s转换为显示值的日期格式化程序,以便它返回与时区无关的表示形式,例如使用 Date::toISOString() . 幸运的是,在我的情况下,这很简单,因为我只需要在我的本地化模块中模拟 formatDate 函数 . 如果组件以某种方式将 Date s单独转换为字符串可能会更难 .

    在我到达上述解决方案之前,我试图以某种方式更改快照的创建方式 . 它很难看,因为酶到json保存了 toISOString() 的本地副本,所以我不得不使用 _.cloneDeepWith 并修改所有的 Date . 无论如何它对我来说都没有用,因为我的测试还包含从时间戳创建 Date 的情况(该组件比我上面描述的要复杂得多)以及这些与我在测试中明确创建的日期之间的交互 . 所以我首先必须确保我的所有日期定义都指的是相同的时区,其余的都是如此 .


    更新(11/3/2017):当我最近检查 enzyme-to-json 时,我无法找到 toISOString() 的本地保存,所以也许_312292已经能够在历史记录中找到它,所以也许我只是错误地注意到了哪个图书馆做到了 . 测试你自己的危险:)

  • 4

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

    1)在你的测试中:

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

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

    • Mac & Linux only
    "test": "TZ=America/New_York react-scripts test --env=jsdom",
    
    • Windows
    "test": "set TZ=America/New_York && react-scripts test --env=jsdom",
    
  • 0

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

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

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

相关问题