使用 Jest 进行测试时如何使用 `import.meta`
Posted
技术标签:
【中文标题】使用 Jest 进行测试时如何使用 `import.meta`【英文标题】:How to Use `import.meta` When Testing With Jest 【发布时间】: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 模块似乎太过分了。 【参考方案1】:我们使用import.meta.url
来使用网络工作者,例如使用native worker support in Webpack 5。这很好用,但在运行 Jest 测试时会失败。
babel-vite-preset
not 会处理这个问题。关于提取和模拟使用import.meta
的代码的最佳答案确实有效,但很笨拙。
我发现目前最好的解决方案是使用babel-plugin-transform-import-meta。这个简单的插件用 Node.js 代码替换了 import.meta.url
语法,以检索当前文件的 URL,因此它在测试中运行良好。请注意,您只希望在运行测试时激活此插件。
【讨论】:
谢谢,正是我的需要!【参考方案2】:解决方案:模块化 ESM 代码并模拟它。
我最近也遇到了这个问题,我最终不得不:
-
导出 ESM 特定问题,例如
import.meta
功能,进入它自己的“utils”文件/函数。
然后在 mocks 目录中创建一个不需要 ESM 特定功能的模拟函数。
在使用该功能的文件中,声明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
]
]
【讨论】:
这对我有用。唯一的问题是,当访问env
或 glob
以外的其他属性时,例如 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.url
和 resolve(__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
以上是关于使用 Jest 进行测试时如何使用 `import.meta`的主要内容,如果未能解决你的问题,请参考以下文章