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

jco*_*lum 11 reactjs jestjs

? npx jest --version
24.5.0
Run Code Online (Sandbox Code Playgroud)

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

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

modificationDate="2019-01-08T00:00:00.000Z" 
Run Code Online (Sandbox Code Playgroud)

没有它,我得到:

modificationDate="2019-01-08T08:00:00.000Z"
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以在我的jest配置中进行设置,这样我就可以npx jest在命令行中运行而不必通过NPM脚本了?配置文档中没有关于此的任何内容。

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

  TZ: 'utc',

  globals: {
    TZ: 'utc',
  },
Run Code Online (Sandbox Code Playgroud)

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

KFu*_*unk 17

如果您使用 npm 脚本运行测试,即:npm run test,您可以像这样传入时区:

  "scripts": {
    "test": "TZ=UTC jest"
  },
Run Code Online (Sandbox Code Playgroud)

我个人也觉得这(与process.env方法相比)在调试远程 CI 服务器上的问题时更清晰,更容易识别时区。

  • 不同意。您应该只使用一个命令运行自动化测试,最好是您和 CI 控制的命令,例如 npm script 命令。 (6认同)
  • 真的。不过我建议转向使用 npm 脚本。更容易跟踪您和其他人应如何运行和维护您的应用程序。IE:“npm run test”将为我拥有的每个节点项目运行测试。您不必彻底阅读自述文件(*希望*是最新的)来了解预期内容或该应用程序有哪些怪癖。 (5认同)
  • 此解决方案不适用于 Windows。[还有另一种方法](https://github.com/Urigo/WhatsApp-Clone-Client-React/issues/1195) 可以,但是你的项目依赖于操作系统。 (2认同)

Shi*_*raz 16

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

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

  afterEach(() => {
    jest.resetAllMocks();
  });
Run Code Online (Sandbox Code Playgroud)

这并未将测试代码放置在特定时区,但确保正确进行任何时区偏移计算。例如:

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

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

  • 我应该补充一点,我现在在特定时区测试代码时使用 https://www.npmjs.com/package/timezone-mock (2认同)

Can*_*Can 13

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

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

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

  "jest": {
     ...
     // depending on your paths it can also be './global-setup.js' 
    "globalSetup": "../global-setup.js"
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Run Code Online (Sandbox Code Playgroud)

3.可选:添加测试以确保UTC执行

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

正常setupFiles不能正常工作对我来说,因为它们运行太晚了(开玩笑:^ 23.5.0)。因此,必须使用globalSetup文件。

  • 我尝试了 Jest 24.8.0 。我把控制台放在各处,它们都被调用(即也在异步内部 - process.env.TZ = 'UTC'; 行)。我的时区偏移量是-120,而不是零。 (3认同)
  • @Can对我也不起作用。记录`process.env.TZ`给我`UTC`。您的操作系统是什么?我的是Win10。 (3认同)
  • @OliverWatkins,您可以通过添加一些控制台日志来验证是否调用了 global-setup.js 吗? (2认同)
  • 该解决方案在我的 Mac 上运行良好,但似乎不适用于我的 Windows 10 计算机。我的 global-setup.js 肯定被调用并且有 ``` process.env.TZ = 'UTC'; console.log('JEST SETUP TZ OFFSET: ' + new Date().getTimezoneOffset()) ``` 我的测试有 ``` console.log('IN TEST TZ OFFSET' + new Date().getTimezoneOffset()) ; console.log('正在测试 TZ' + process.env.TZ); 期望(new Date().getTimezoneOffset()).toBe(0); ``` 其输出为 ` JEST SETUP TZ OFFSET: 0 IN TEST TZ OFFSET-60 IN TEST TZ UTC Expected: 0 Received: -60 ``` (2认同)
  • @JoseSolorzano 你介意测试跨环境是否有效吗?`"test": "cross-env TZ=\"UTC\" npm run jest-task",` (2认同)
  • @我可以使用“cross-env TZ=UTC jest ...”让这个工作吗 (2认同)

the*_*nuu 11

我刚刚遇到了同样的问题,我能够通过添加process.env.TZ = 'your/timezone';到我的jest.config.js.

也许这对您的情况也有帮助:)

process.env.TZ = 'UTC';

module.exports = {
  ...
};
Run Code Online (Sandbox Code Playgroud)

  • 这是可悲的错误。请参阅 https://github.com/nodejs/node/issues/3449“关闭,设置 process.env.TZ 不是设置默认时区的正确方法。” 使用 `expect(new Date().getTimezoneOffset()).toBe(0);` 验证 (2认同)

kam*_*cus 9

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

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

我还发现了一个关于 Node 中动态时区的旧存档问题,看起来动态调整通常不起作用

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


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

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

然后,我们利用可以使用 JSDoc pragma在测试套件级别testEnvironment设置的配置。使用此自定义测试环境,我们可以使用“自定义 docblock pragma”(例如. 这使得每个测试套件都可以进行时区定制,虽然不如每个测试那么理想,但足以满足我们的目的。@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);
  }
};
Run Code Online (Sandbox Code Playgroud)

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 */);
  });
});
Run Code Online (Sandbox Code Playgroud)

笑话配置.js

module.exports = {
  "testEnvironment": "<rootDir>/jsdom-with-timezone.js"
}
Run Code Online (Sandbox Code Playgroud)

jest.useFakeTimers('modern');和 一起使用jest.setSystemTime()就足以进行更强大的日期测试,所以我想我会分享这种方法,让其他人从中受益!由于编译指示处理是自定义的,因此您可以根据您的用例以任何您喜欢的方式进行自定义。

资料来源: