如何在Jest配置中设置时区?

时间:2019-05-22 16:33:10

标签: reactjs jestjs

✗ npx jest --version
24.5.0

获得了一组对时区敏感的玩笑测试。我们通常使用npm脚本运行它们:"jest": "TZ=utc jest"

将TZ设置为utc时,我会在快照中获得如下所示的值:

modificationDate="2019-01-08T00:00:00.000Z" 

没有它我得到:

modificationDate="2019-01-08T08:00:00.000Z"

有没有一种方法可以在我的jest配置中进行设置,以便我可以在命令行中运行npx jest而不用通过NPM脚本? {{3}中没有任何内容}。

我尝试将这两个添加到我的jest.config.js中。没有人起作用:

  TZ: 'utc',

  globals: {
    TZ: 'utc',
  },

当然,解决这个问题似乎微不足道,但令我感到惊讶的是,Jest没有办法配置它进行测试。

5 个答案:

答案 0 :(得分:5)

process.env.TZ = 'UTC';的问题在于,如果某行在此行之前运行并使用Date,则该值将被缓存在Date中。因此,process.env通常不适合设置时区。参见https://github.com/nodejs/node/issues/3449

因此,更好的方法是使用实​​际的env变量,但是对于测试而言,它将起作用:

1。将此添加到您的package.json

  "jest": {
     ...
    "globalSetup": "../global-setup.js"
  }
}

2。将此文件放在package.json 之外,作为global-setup.js

module.exports = async () => {
    process.env.TZ = 'UTC';
};

3。可选:添加一个测试以确保UTC执行

describe('Timezones', () => {
    it('should always be UTC', () => {
        expect(new Date().getTimezoneOffset()).toBe(0);
    });
});

正常的setupFiles对我不起作用,因为它们运行得太晚了(开玩笑:^ 23.5.0)。因此,使用globalSetup文件是强制性

答案 1 :(得分:5)

如果您正在使用npm脚本(即npm run test)运行测试,则可以像这样传递时区:

  "scripts": {
    "test": "TZ=UTC jest"
  },

我个人还认为,在远程CI服务器上调试问题时,此方法(与process.env方法相比)更干净,更容易识别时区。

答案 2 :(得分:4)

更新:这不会产生确定性结果如果您想动态更改 TZ,但如果您只想要一个 TZ,它会起作用。这可能是在脚本级别指定的替代方法,但我认为这将是更好的答案。

问题在于,通过在运行时设置 process.env.TZ,它会在常规 Jest 测试运行期间跨测试产生不确定性行为(副作用)。如果您使用连续运行测试的 --runInBand,它可能工作,但我不会指望它。

我还在 Node 中发现了一个关于动态时区的旧存档问题,它看起来像 dynamically adjusting it won't work in general

相反,我可能最终会得到多个脚本,每个脚本在启动 TZ 之前都设置了 jest


对于我的用例,我实际上想在不同时区下针对特定的基于日期的边缘情况运行测试。有时用户会遇到基于时区的错误,我们希望在我们的测试套件中轻松解决这个问题。

默认情况下,我们使用此处建议的答案之一运行项目中的所有测试,方法是在 TZ=UTC 脚本中设置 npm(例如 TZ=UTC npm run jest。这将在 UTC 下运行所有​​测试时区。

然后,我们利用可以使用 JSDoc pragma testEnvironment 在测试套件级别设置的 @jest-environment 配置。使用此自定义测试环境,然后我们可以使用“自定义文档块编译指示”(如 @timezone)读取套件所需的时区。这使每个测试套件的时区自定义成为可能,这虽然不如每个测试理想,但足以满足我们的目的。

jsdom-with-timezone.js

const JSDOMEnvironment = require('jest-environment-jsdom');

/**
 * Timezone-aware jsdom Jest environment. Supports `@timezone` JSDoc 
 * pragma within test suites to set timezone.
 *
 * You'd make another copy of this extending the Node environment, 
 * if needed for Node server environment-based tests.
 */
module.exports = class TimezoneAwareJSDOMEnvironment extends JSDOMEnvironment 
{
  constructor(config, context) {

    // Allow test suites to change timezone, even if TZ is passed in a script.
    // Falls back to existing TZ environment variable or UTC if no timezone is specified.
    // IMPORTANT: This must happen before super(config) is called, otherwise
    // it doesn't work.
    process.env.TZ = context.docblockPragmas.timezone || process.env.TZ || 'UTC';

    super(config);
  }
};

tz-eastern.test.js

/**
 * @timezone America/New_York
 */

describe('timezone: eastern', () => {
  it('should be America/New_York timezone', () => {
    expect(process.env.TZ).toBe('America/New_York');
    expect(new Date().getTimezoneOffset()).toBe(300 /* 5 hours */);
  });
});

jest.config.js

module.exports = {
  "testEnvironment": "<rootDir>/jsdom-with-timezone.js"
}

将此方法与 jest.useFakeTimers('modern');jest.setSystemTime() 结合使用足以进行更强大的日期测试,因此我想我会与其他人分享这种方法以从中受益!由于 pragma 处理是自定义的,因此您可以根据自己的用例以任何喜欢的方式对其进行自定义。

来源:

答案 3 :(得分:1)

直到最近,我使用以下内容来模拟处于不同的时区:

  beforeEach(() => {
    // Temporarily allow us to alter timezone calculation for testing
    /*eslint no-extend-native: "off"*/
    Date.prototype.getTimezoneOffset = jest.fn(() => 73);
  });

  afterEach(() => {
    jest.resetAllMocks();
  });

这并没有将测试代码放在特定的时区,而是确保任何时区偏移计算都正确进行。例如:

new Date("2010-10-01") 将比 new Date("2010-10-01T00:00:00") 早 73 分钟,前者相当于 new Date("2010-10-01T00:00:00Z")(UTC 时区),后者在“本地时区”中

我说“直到最近”是因为最近对 date-fns 的更新似乎不再有效

答案 4 :(得分:0)

我遇到了同样的问题,我可以通过将process.env.TZ = 'your/timezone';添加到我的jest.config.js中来解决此问题。

也许这对您也有帮助:)

process.env.TZ = 'UTC';

module.exports = {
  ...
};