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

IT技术 reactjs jestjs
2021-04-10 08:58:09
✗ 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 脚本?配置文档中没有关于此的任何内容。

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

  TZ: 'utc',

  globals: {
    TZ: 'utc',
  },

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

5个回答

这在节点 17.0.1 之前的 Windows 上不起作用- 请参阅https://github.com/nodejs/node/issues/4230


问题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"
  }
}

2.将这个文件之外的package.jsonglobal-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 文件。

@OliverWatkins,您能否通过添加一些控制台日志来验证是否调用了 global-setup.js?
2021-05-24 08:58:09
@Can 看起来已修复“我可以确认此问题已在使用 Windows 10 的节点版本 17.0.1 中解决”——该 github 票证中的最后一条评论
2021-05-29 08:58:09
我试过 Jest 24.8.0 。我把控制台放在任何地方,它们都被调用(即也在异步内部 - 行 process.env.TZ = 'UTC';)。我的 timezoneoffset 是 -120,而不是零。
2021-06-03 08:58:09
此解决方案在我的 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('IN TEST TZ' + process.env.TZ); 期望(新日期()。getTimezoneOffset())。toBe(0);``` 输出是 ` JEST SETUP TZ OFFSET: 0 IN TEST TZ OFFSET-60 IN TEST TZ UTC 预期:0 收到:-60 ```
2021-06-06 08:58:09
@Can 它对我也不起作用。日志记录process.env.TZ给了我UTC你的操作系统是什么?我的是Win10。
2021-06-16 08:58:09

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

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

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

如果我在没有 npm 脚本的情况下通过命令行运行,我必须记住每次都这样做——接受的答案更好
2021-05-31 08:58:09
错误的决定。这样,您将依赖于使用自定义脚本命令运行测试。请改用全局设置。
2021-06-01 08:58:09
@jcollum 如果您对在与计算机不同的时区上运行的队友测试感到满意,请继续。找出为什么您的测试通过而他们的失败的原因很有趣:) 如果您有一个需要使用本地时区的特定组件,请在该特定测试中模拟它而不是全局。
2021-06-13 08:58:09
真的。虽然我建议转向使用 npm 脚本。跟踪您和其他人应该如何运行和维护您的应用程序会更容易。IE:npm run test将为我拥有的每个节点项目运行测试。您不必仔细阅读自述文件(希望是最新的)即可了解预期内容。或该应用程序有哪些怪癖。
2021-06-18 08:58:09
不同意。您应该只使用一个命令运行自动化测试,最好是您和您的 CI 控制的命令,例如 npm 脚本命令。
2021-06-19 08:58:09

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

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

process.env.TZ = 'UTC';

module.exports = {
  ...
};
这应该是公认的答案。特别是对于我们这些使用 monorepos 的人来说,这是迄今为止最简单的解决方案
2021-05-29 08:58:09
@CanK。这很奇怪......我刚刚更新到 angular 8 并更改了一些依赖项,现在我的测试不再工作......如果我找到另一个解决方案,我会告诉你。
2021-06-02 08:58:09
@thegnuu 是的,我做了,由于内容,我会将其放入答案中。
2021-06-04 08:58:09
这是可悲的错误。请参阅github.com/nodejs/node/issues/3449 “关闭,设置 process.env.TZ 不是设置默认时区的正确方法。” 使用 `expect(new Date().getTimezoneOffset()).toBe(0);` 验证
2021-06-05 08:58:09
@CanK。我意识到在我的情况下,这只是因为我的解决方案停止工作的配置路径发生了变化,但您的解决方案也能正常工作,所以我切换到了这个,似乎是设置时区的更好方法!谢谢!
2021-06-08 08:58:09

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

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

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

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


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

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

然后,我们利用testEnvironment可以使用 JSDoc 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);
  }
};

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 */);
  });
});

开玩笑的配置文件

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

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

资料来源:

实际上,跟进(我编辑了答案)。这会在正常运行 Jest 时产生非确定性行为(即并行运行多个套件)。问题是process.env.TZ测试流血,因为它不是沙箱的一部分。看起来 Node.js 在运行时不支持动态 TZ :( github.com/nodejs/node-v0.x-archive/issues/3286
2021-06-17 08:58:09

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

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

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