【问题标题】:Test process.env with Jest用 Jest 测试 process.env
【发布时间】:2018-06-10 13:23:17
【问题描述】:

我有一个依赖于环境变量的应用程序,例如:

const APP_PORT = process.env.APP_PORT || 8080;

我想测试一下,例如:

  • APP_PORT 可以由 Node.js 环境变量设置。
  • Express.js 应用程序正在使用process.env.APP_PORT 设置的端口上运行

如何使用 Jest 实现这一目标?我可以在每次测试之前设置这些 process.env 变量还是应该以某种方式模拟它?

【问题讨论】:

  • 可以设置环境变量
  • @Deep AFAIK 我只能在 jest config 中设置一次。

标签: node.js testing environment-variables jestjs


【解决方案1】:

我这样做的方式can be found in this Stack Overflow question

重要的是在每次测试之前使用resetModules,然后在测试内部动态导入模块:

describe('environmental variables', () => {
  const OLD_ENV = process.env;

  beforeEach(() => {
    jest.resetModules() // Most important - it clears the cache
    process.env = { ...OLD_ENV }; // Make a copy
  });

  afterAll(() => {
    process.env = OLD_ENV; // Restore old environment
  });

  test('will receive process.env variables', () => {
    // Set the variables
    process.env.NODE_ENV = 'dev';
    process.env.PROXY_PREFIX = '/new-prefix/';
    process.env.API_URL = 'https://new-api.com/';
    process.env.APP_PORT = '7080';
    process.env.USE_PROXY = 'false';

    const testedModule = require('../../config/env').default

    // ... actual testing
  });
});

如果您想在运行 Jest 之前寻找一种加载环境值的方法,请查找 answer below。你应该使用setupFiles

【讨论】:

  • 请提供完整的回复
  • 对我来说效果很好。如果你需要使用默认导出,你可以这样做: const testsModule = require('../../config/env').default;
  • 如果这对您不起作用,请确保当您在实际代码中读取 env 变量时,您是在函数/有限范围内读取它,而不是指向全局变量process.env.YOUR_VARIABLE。
  • @learner 如果我没记错的话delete process.env.NODE_ENV; 只是我的代码的剩余部分,在你的情况下应该无关紧要。重要的是您在测试之前调用jest.resetModules(),之后您恢复初始 process.env 对象(OLD_ENV)
  • @MEMark 您需要创建一个副本以免改变原始对象(稍后您需要恢复)
【解决方案2】:

Jest 的setupFiles 是处理此问题的正确方法,您无需安装dotenv,也无需使用.env 文件即可使其工作。

jest.config.js:

module.exports = {
  setupFiles: ["<rootDir>/.jest/setEnvVars.js"]
};

.jest/setEnvVars.js:

process.env.MY_CUSTOM_TEST_ENV_VAR = 'foo'

就是这样。

【讨论】:

  • 这是处理环境变量最直接的方式,谢谢!
  • 我尝试了这个帖子中提出的大部分解决方案,这是对我有用的解决方案。
  • 这应该是公认的答案。
  • 这是最好的解决方案!对于我的生产应用程序,我也使用它来设置全局模拟。例如,如果您正在处理 momentjs,您可以在此处设置时区,这样您的快照在更改时区时不会失败。
  • 太棒了,这是处理环境变量最简单的方法!
【解决方案3】:

另一种选择是将其添加到jest.config.js 文件中module.exports 定义之后:

process.env = Object.assign(process.env, {
  VAR_NAME: 'varValue',
  VAR_NAME_2: 'varValue2'
});

这样就不需要在每个.spec文件中定义环境变量,并且可以全局调整。

【讨论】:

  • 这是一个绝妙的答案。谢谢。
  • 这是唯一对我有用的答案。谢谢!
【解决方案4】:

./package.json:

"jest": {
  "setupFiles": [
    "<rootDir>/jest/setEnvVars.js"
  ]
}

./jest/setEnvVars.js:

process.env.SOME_VAR = 'value';

【讨论】:

  • 可能是我见过的最简单的方法。无需安装 dotenv 包。
  • 这不适用于 Create-React-App github.com/facebook/create-react-app/issues/5325,需要在 .env.test.local 文件中添加要用于测试的环境变量
  • 这对我来说不适用于 vue-test-utils
  • 这对我不起作用,因为我的环境变量需要在模块加载之前进行初始化。因此,我最终将其拆分为两个单独的文件,并在加载模块之前定义了 var,这样就可以了。不是一个漂亮的方式,但工作。
【解决方案5】:

您可以使用 Jest 配置的setupFiles 功能。作为the documentation said那个,

运行一些代码以进行配置或设置的模块的路径列表 测试环境。 每个 setupFile 将在每次测试时运行一次 由于每个测试都在自己的环境中运行,因此这些脚本将 在执行之前立即在测试环境中执行 测试代码本身。

  1. npm install dotenv dotenv 用于访问环境变量。

  2. 在应用程序的根目录中创建.env 文件,并将这一行添加到其中:

    #.env
    APP_PORT=8080
    
  3. 创建您的自定义模块文件,将其命名为 someModuleForTest.js 并将这一行添加到其中:

    // someModuleForTest.js
    require("dotenv").config()
    
  4. 像这样更新您的jest.config.js 文件:

    module.exports = {
      setupFiles: ["./someModuleForTest"]
    }
    
  5. 您可以访问所有测试块中的环境变量。

    test("Some test name", () => {
      expect(process.env.APP_PORT).toBe("8080")
    })
    

【讨论】:

    【解决方案6】:

    Serhan C.'s answer上扩展一点...

    根据博文How to Setup dotenv with Jest Testing - In-depth Explanation,您可以将"dotenv/config" 直接包含在setupFiles 中,而无需创建和引用调用require("dotenv").config() 的外部脚本。

    即,简单地做

    module.exports = {
        setupFiles: ["dotenv/config"]
    }
    

    【讨论】:

    • 只有这个在我身边运行
    • 这里最好的解决方案!值得一提的是,在jest.config.ts 中,您可以在globalSetup 键而不是setupFiles 键下使用它,如果您希望它在所有测试之前运行一次,而不是在每个测试文件之前重置它们
    【解决方案7】:

    在我看来,如果您将环境变量的检索提取到实用程序中(如果没有设置环境变量,您可能希望包含一个检查以快速失败),然后您可以只是模拟该实用程序。

    // util.js
    exports.getEnv = (key) => {
        const value = process.env[key];
        if (value === undefined) {
          throw new Error(`Missing required environment variable ${key}`);
        }
        return value;
    };
    
    // app.test.js
    const util = require('./util');
    jest.mock('./util');
    
    util.getEnv.mockImplementation(key => `fake-${key}`);
    
    test('test', () => {...});
    

    【讨论】:

    • 太棒了,感谢您的提示!简单但有效。
    • 我觉得这是测试检查的唯一方法,例如:isProd ? /*something*/ : /*something else*/,例如,当您想发送电子邮件时。或者在依赖没有适当测试环境的外部服务时。
    【解决方案8】:

    在测试文件中:

    const APP_PORT = process.env.APP_PORT || 8080;
    

    ./package.json的测试脚本中:

    "scripts": {
       "test": "jest --setupFiles dotenv/config",
     }
    

    ./env:

    APP_PORT=8080
    

    【讨论】:

    • 最简单的答案
    【解决方案9】:

    根据您组织代码的方式,另一种选择是将环境变量放在运行时执行的函数中。

    在此文件中,环境变量在导入时设置,需要动态requires 以测试不同的环境变量(如this answer 中所述):

    const env = process.env.MY_ENV_VAR;
    
    const envMessage = () => `MY_ENV_VAR is set to ${env}!`;
    
    export default myModule;
    

    在此文件中,环境变量设置为envMessage 执行时间,您应该可以直接在测试中修改 process.env:

    const envMessage = () => {
      const env = process.env.MY_VAR;
      return `MY_ENV_VAR is set to ${env}!`;
    }
    
    export default myModule;
    

    玩笑测试:

    const vals = [
      'ONE',
      'TWO',
      'THREE',
    ];
    
    vals.forEach((val) => {
      it(`Returns the correct string for each ${val} value`, () => {
        process.env.MY_VAR = val;
    
        expect(envMessage()).toEqual(...
    

    【讨论】:

      【解决方案10】:

      以@jahler 的回答为基础。

      我使它具有响应性,因此您无需在事情发生变化时保持文件同步。

      把它放在jest.config.js 文件的底部。

      const arr = require('fs')
        .readFileSync('.env', 'utf8')
        .split('\n')
        .reduce((vars, i) => {
          const [variable, value] = i.split('=')
          vars[variable] = value
          return vars
        }, {})
      
      process.env = Object.assign(process.env, arr)
      

      它会读取 .env 文件的内容,拆分每个新行并将其全部还原为一个对象,然后将其分配给 process.env

      只需在 jest.setup.js ?‍♂️ 中使用 dotenv

      【讨论】:

        【解决方案11】:

        我想你也可以试试这个:

        const currentEnv = process.env;
        process.env = { ENV_NODE: 'whatever' };
        
        // test code...
        
        process.env = currentEnv;
        

        这对我有用,你不需要模块的东西

        【讨论】:

        • 问题是,如果你导入另一个使用 process.env 的文件,那么直接更改它不会生效。因此,在每次测试之前,您需要告诉 Jest 类似“嘿,再次导入并执行此文件”。
        【解决方案12】:

        你可以在你的 jest.config.js 中导入它

        require('dotenv').config()
        

        这对我有用

        【讨论】:

          【解决方案13】:

          如果您在 jest.config.js 文件中使用 require("dotenv").config,则上述所有方法都有效,这是一个没有 TypeScript 的 NodeJS 应用程序,例如 Jialx 或 Henry Tipantuna 所建议的。

          但如果您使用的是 ts-jest 并在 jest.config.ts 文件中。

          import dotenv from "dotenv"
          dotenv.config()
          
          /* config options below */
          

          【讨论】:

            猜你喜欢
            • 2019-10-26
            • 1970-01-01
            • 2019-07-23
            • 2023-01-26
            • 2021-03-11
            • 1970-01-01
            • 2019-09-11
            • 2023-04-02
            • 2018-07-26
            相关资源
            最近更新 更多