【问题标题】:How do I set a timezone in my Jest config?如何在我的 Jest 配置中设置时区?
【发布时间】:2019-10-09 05:04:11
【问题描述】:
✗ 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 脚本? config docs 中没有关于此的内容。

我尝试将这两个添加到我的 jest.config.js 中。两者都不起作用:

  TZ: 'utc',

  globals: {
    TZ: 'utc',
  },

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

【问题讨论】:

    标签: reactjs jestjs


    【解决方案1】:

    这不适用于节点 17.0.1 之前的窗口 - 请参阅 https://github.com/nodejs/node/issues/4230


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

    因此,更好的方法是使用实​​际的环境变量,但对于测试,这将起作用:

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

      "jest": {
         ...
         // depending on your paths it can also be './global-setup.js' 
        "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 文件。

    【讨论】:

    • @OliverWatkins,能否通过添加一些控制台日志来验证是否调用了 global-setup.js?
    • 我试过 Jest 24.8.0 。我将控制台放在任何地方,它们都被调用(即也在异步内部 - 行 process.env.TZ = 'UTC';)。我的时区偏移量是 -120,而不是零。
    • @Can 它对我也不起作用。记录process.env.TZ 给了我UTC。你的操作系统是什么?我的是Win10。
    • 此解决方案在我的 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 Expected: 0 Received: -60 ```
    • @Can 看起来已修复“我可以确认此问题已在使用 Windows 10 的节点版本 17.0.1 中得到解决”——该 github 票证中的最后一条评论
    【解决方案2】:

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

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

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

    【讨论】:

    • 如果我在没有 npm 脚本的情况下通过命令行运行,我必须记住每次都这样做——接受的答案更好
    • 是的。虽然我建议转向使用 npm 脚本。更容易跟踪您和其他人应该如何运行和维护您的应用程序。 IE:npm run test 将为我拥有的每个节点项目运行测试。您无需彻底阅读自述文件(希望是最新的)即可了解预期内容或该应用程序有哪些怪癖。
    • 错误的决定。这样,您将依赖于使用自定义脚本命令运行测试。请改用全局设置。
    • 不同意。您应该只使用一个命令运行自动化测试,最好是您和您的 CI 控制的命令,例如 npm 脚本命令。
    • @jcollum 如果您对队友的测试在与您的计算机不同的时区运行感到满意,那就去吧。弄清楚为什么你的测试通过而他们的测试失败了:)如果你有一个特定的组件需要使用本地时区,请在该特定测试中而不是全局模拟它。
    【解决方案3】:

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

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

    process.env.TZ = 'UTC';
    
    module.exports = {
      ...
    };
    

    【讨论】:

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

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

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

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

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


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

    默认情况下,我们使用此处建议的答案之一运行项目中的所有测试,方法是在 npm 脚本中设置 TZ=UTC(例如 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 */);
      });
    });
    

    jest.config.js

    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
    【解决方案5】:

    直到最近,我还使用以下方法来模拟处于不同时区:

      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 的更新似乎不再有效

    【讨论】:

      猜你喜欢
      • 2020-08-06
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 2014-12-08
      • 1970-01-01
      • 2019-05-28
      • 2023-04-07
      • 2021-04-15
      相关资源
      最近更新 更多