【问题标题】:How to Use `import.meta` When Testing With Jest使用 Jest 进行测试时如何使用 `import.meta`
【发布时间】:2021-03-05 18:04:42
【问题描述】:

我正在使用 ESModules 编写 Node.js 代码(在 TypeScript 中),我需要访问 __dirname。为了在 CommonJS 中访问等效于 __dirname 的 ESM,我调用了 dirname(fileURLToPath(import.meta.url))。我还在 Jest 中使用 TypeScript 编写测试。使用this 指南,我设置了 Babel。当我运行jest 命令时,我得到了

const DIRNAME = (0, _path.dirname)((0, _url.fileURLToPath)(import.meta.url));
                                                                      ^^^^
SyntaxError: Cannot use 'import.meta' outside a module

这是我写的文件

someCode.ts:

import { dirname } from "path";
import { fileURLToPath } from "url";

const DIRNAME = dirname(fileURLToPath(import.meta.url));

export const x = 5;

someCode.test.ts:

import { x } from "./someCode";

it("Returns 5 as the result", () => {
    expect(x).toEqual(5);
});

.babelrc.json:

{
    "presets": [
        ["@babel/preset-env", { "targets": { "node": "current" } }],
        "@babel/preset-typescript"
    ]
}

tsconfig.json:

{
    "compilerOptions": {
        "target": "ES2020",
        "module": "ESNext",
        "moduleResolution": "node"
    },
    "include": ["./src/**/*.ts", "./src/**/*.js"]
}

package.json:

{
    "name": "test",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "type": "module",
    "scripts": {
        "test": "jest"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "@babel/core": "^7.12.7",
        "@babel/preset-env": "^7.12.7",
        "@babel/preset-typescript": "^7.12.7",
        "jest": "^26.6.3",
        "typescript": "^4.1.2"
    }
}

环境:

  • 节点:14.1.0
  • 查看package.json 了解模块版本

【问题讨论】:

  • 您正在遵循使用 CommonJS 模块的通用指南。对于原生 ESM,请参阅 jestjs.io/docs/en/ecmascript-modules
  • 我正在寻找相同问题的答案。将 Jest 移至 ESM 模块似乎太过分了。

标签: typescript jestjs babeljs


【解决方案1】:

我们使用import.meta.url 来使用网络工作者,例如使用native worker support in Webpack 5。这很好用,但在运行 Jest 测试时会失败。

据我所知,

babel-vite-presetnot 会处理这个问题。关于提取和模拟使用import.meta 的代码的最佳答案确实有效,但很笨拙。

我发现目前最好的解决方案是使用babel-plugin-transform-import-meta。这个简单的插件用 Node.js 代码替换了 import.meta.url 语法,以检索当前文件的 URL,因此它在测试中运行良好。请注意,您只希望在运行测试时激活此插件。

【讨论】:

  • 谢谢,正是我的需要!
【解决方案2】:

解决方案:模块化 ESM 代码并模拟它。

我最近也遇到了这个问题,我最终不得不:

  1. 导出 ESM 特定问题,例如import.meta 功能,进入它自己的“utils”文件/函数。
  2. 然后在 mocks 目录中创建一个不需要 ESM 特定功能的模拟函数。
  3. 在使用该功能的文件中,声明jest.mock("/path/to/that/file.ts")

该过程将如下所示:

原始文件结构

src/
--/someCode.ts
--/__tests__/
/--/--/someCode.test.ts
// someCode.ts
...
const getApiUrl = () => { 
  ...
  const url = import.meta.env.SOME_ENV_VAR_HERE;
  ...
  return url;
};
...

新的文件结构

标题

src/
--/someCode.ts
--/utils.js
--/__mocks__/
--/--/utils.ts
--/__tests__/
--/--/someCome.test.ts

然后在文件本身中:

// someCode.ts
...
import { getApiUrl } from "./utils.ts";
...

// utils.js
export const getApiUrl = () => {...};

对于测试:

// __mocks__/utils.ts
export const getpiUrl = jest.fn(() => 'some.url');

// __tests__/utils.test.ts
...
jest.mock("src/util.ts");
...
describe(...);

【讨论】:

  • 这就是我的解决方案。唯一的区别是做这样的事情:``` jest.mock('$lib/variables', () => ({ __esModule: true, variables: { apiUrl: 'localhost:2222' } })); ```
  • @TimoHermans 您能否在回答中发布适合您的解决方案
【解决方案3】:

在您的tsconfig.json 内更改为

    {
    "compilerOptions": {
        "target": "ES2020",
        "module": "ES2020",
        "moduleResolution": "node"
    },
    "include": ["./src/**/*.ts", "./src/**/*.js"]
}

【讨论】:

    【解决方案4】:

    babel-vite-preset

    我觉得这个不错。

    非官方的。

    您可以选择仅使用它babel-plugin-transform-vite-meta-env 插件或使用整个预设并设置如下配置

    {
      "presets": [
        [
          "babel-preset-vite",
          {
            "env": true, // defaults to true
            "glob": false // defaults to true
          }
        ]
      ]
    }
    

    【讨论】:

    • 这对我有用。唯一的问题是,当访问 envglob 以外的其他属性时,例如 import.meta.hot,它将无法正常工作
    【解决方案5】:

    我也遇到了这个问题。我能够通过在 babel 处理期间动态插入正确的值来解决这个问题。我没有使用建议的search-and-replace babel 插件,而是使用了codegen macro for babel

    // someCode.ts
    import { dirname } from "path";
    import { fileURLToPath } from "url";
    import codegen from 'codegen.macro';
    
    const DIRNAME = dirname(fileURLToPath(codegen`module.exports = process.env.NODE_ENV === "test" ? "{ADD VALID VALUE FOR TESTS}" : "import.meta.url"`));
    
    export const x = 5;
    

    【讨论】:

      【解决方案6】:

      我遇到了同样的问题,我用 babel 插件解决了它:search-and-replace

      在我的代码中,我将所有 import.meta.url 更改为 import_meta_url

      我将插件添加到 babel config 以在开发和生产中通过 import.meta.urlresolve(__dirname, 'workers') 更改它

      我能够这样做是因为它符合我所有的情况,如果您的 import_meta_url 需要在不同情况下用不同的刺替换,您将需要使用 import_meta_url_1 import_meta_url_2 等例如

      终于是我的babel.config.js

      const { resolve } = require('path');
      
      module.exports = (api) => {
        api.cache.using(() => process.env.NODE_ENV);
      
        if (process.env.NODE_ENV === 'test') {
          return {
            presets: ['next/babel'],
            plugins: [
              [
                'search-and-replace',
                {
                  rules: [
                    {
                      searchTemplateStrings: true,
                      search: 'import_meta_url',
                      replace: resolve(__dirname, 'workers'),
                    },
                  ],
                },
              ],
            ],
          };
        }
      
        return {
          presets: ['next/babel'],
          plugins: [
            [
              'search-and-replace',
              {
                rules: [
                  {
                    searchTemplateStrings: true,
                    search: 'import_meta_url',
                    replace: 'import.meta.url',
                  },
                ],
              },
            ],
          ],
        };
      };
      
      

      GL

      【讨论】:

      • 我在我的 babel.config.js 中使用了相同的配置,但它不起作用。我收到以下错误TypeError: Failed to construct 'URL': Invalid base URL
      猜你喜欢
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 2020-07-03
      • 2020-05-20
      • 1970-01-01
      • 2020-07-04
      • 2023-04-01
      • 2020-07-04
      相关资源
      最近更新 更多