Babel.js 如何在使用Jest进行测试时使用'import. meta'

wztqucjr  于 2022-12-08  发布在  Babel
关注(0)|答案(9)|浏览(413)

我正在使用ESModules编写Node.js代码(在TypeScript中),我需要访问__dirname。为了访问CommonJS中__dirname的ESM等效项,我调用了dirname(fileURLToPath(import.meta.url))。我还在使用TypeScript编写Jest测试。使用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"
    ]
}
  • 一米七三 *
{
    "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 *
b1payxdu

b1payxdu1#

解决方案:模块化ESM代码并对其进行模拟。

我最近也遇到了这个问题,最后我不得不:
1.将ESM特定问题(例如import.meta功能)导出到其自身的“utils”文件/函数中。
1.然后在mocks目录中创建一个不需要ESM特定功能的模拟函数。
1.在使用该功能的文件中,声明jest.mock("/path/to/that/file.ts")
该过程类似于:

原始文件结构

第一个
新的文件结构

标题

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(...);
c2e8gylq

c2e8gylq2#

我们正在使用import.meta.url来利用web worker,例如使用native worker support in Webpack 5。这工作得很好,但是在运行Jest测试时失败了。
就我所知,babel-vite-preset * 没有 * 处理这个问题。关于提取和模拟使用import.meta的代码的首要答案确实有效,但很笨拙。
我发现目前最好的解决方案是使用babel-plugin-transform-import-meta。这个简单的插件用Node.js代码替换了import.meta.url语法来检索当前文件的URL,所以它在测试中工作得很好。注意,你只想在运行测试时激活这个插件。

pwuypxnk

pwuypxnk3#

我有同样的问题,我用一个巴别塔插件修复它:search-and-replace
在我的代码中,我将所有的import.meta.url更改为import_meta_url
我还在babel config中添加了插件,在开发和生产中通过import.meta.urlresolve(__dirname, 'workers')对其进行更改
我之所以能够这样做,是因为它与我的所有用例都匹配,例如,如果在不同的场景中需要将import_meta_url替换为不同的字符串,则需要使用import_meta_url_1import_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语言

57hvy0tb

57hvy0tb4#

我也遇到了这个问题。我能够通过在Babel处理过程中动态插入一个正确的值来解决这个问题。我使用了codegen macro for babel而不是建议的search-and-replace 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;
e5nszbig

e5nszbig5#

babel-vite-preset
我觉得这个很棒。
非官方。
你可以选择只使用它babel-plugin-transform-vite-meta-env插件或使用整个预设和设置配置如下

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

ny6fqffe6#

我发现了一个解决方案,它是如此荒谬,我甚至不相信当它工作:
创建一个commonjs文件,比如“currentPath.cjs”,在里面放一些东西:

module.exports = __dirname;

在模块中用途:

import * as currentPath from "./currentPath.cjs";
console.log(currentPath.default);

并观看魔术发生。PS:在对任何对象使用path.normalize()之前,请先使用它。

mu0hgdu0

mu0hgdu07#

在您的tsconfig.json中更改为

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

xuo3flqw8#

我在Node.js,Express,TypeScript,Jest,ts-jext项目中遇到了这个问题。对我来说,问题是正确配置jest.config.json。
我把我的档案发出去了也许能帮到什么人。

包.JSON

{
  "name": "express-react",
  "version": "0.0.0",
  "private": true,
  "main": "dist/index.js",
  "type": "module",
  "engines": {
    "node": ">=14.0.0"
  },
  "scripts": {
    "start:dev": "npm run build && npm run dev",
    "build": "npm run format && npm run lint && npm run tsc",
    "start:prod": "npm run build && node --experimental-specifier-resolution=node dist/index.js",
    "start": "npm run start:prod",
    "dev": "cross-env-shell DEBUG=express:* node --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts",
    "format": "prettier --write \"**/*.ts\"",
    "lint": "eslint . --ext 'ts,json'",
    "tsc": "tsc",

    "test": "cross-env-shell TS_JEST_LOG=ts-jest.jog NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --verbose --testTimeout 20000 --coverage=true --reporters=default --json --debug --outputFile=./test/log.json",
    "test:list": "jest --detectOpenHandles --coverage=true --listTests --debug"

  },
  "dependencies": {

    "cookie-parser": "~1.4.4",
    "cors": "^2.8.5",
    "debug": "~2.6.9",
    "dotenv": "^16.0.0",
    "express": "~4.16.1",
    "express-fileupload": "^1.3.1",
    "http-errors": "^1.6.3",
    "into-stream": "^7.0.0",
    "jest": "^28.1.0",
    "morgan": "~1.9.1",
    "multer": "^1.4.4",
    "save-dev": "0.0.1-security",
    "sharp": "^0.30.4",
    "supertest": "^6.2.3",
    "ts-jest": "^28.0.2",
    "ts-node": "^10.7.0",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@types/jest": "^27.5.1",
    "@types/supertest": "^2.0.12",
    "@azure/storage-blob": "^12.9.0",
    "@types/cookie-parser": "^1.4.3",
    "@types/cors": "^2.8.12",
    "@types/debug": "^4.1.7",
    "@types/express": "^4.16.1",
    "@types/express-fileupload": "^1.2.2",
    "@types/http-errors": "^1.8.2",
    "@types/into-stream": "^3.1.1",
    "@types/morgan": "^1.9.3",
    "@types/multer": "^1.4.7",
    "@types/node": "^17.0.31",
    "@types/sharp": "^0.30.2",
    "@types/uuid": "^8.3.4",
    "@typescript-eslint/eslint-plugin": "^5.22.0",
    "@typescript-eslint/parser": "^5.22.0",
    "cross-env": "^7.0.3",
    "eslint": "^8.15.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-node": "^11.1.0",
    "nodemon": "^2.0.16",
    "prettier": "^2.6.2",
    "tslib": "^2.4.0",
    "typescript": "^4.6.4"
  }
}

服务器配置JSON

{
  "name": "express-react",
  "version": "0.0.0",
  "private": true,
  "main": "dist/index.js",
  "type": "module",
  "engines": {
    "node": ">=14.0.0"
  },
  "scripts": {
    "start:dev": "npm run build && npm run dev",
    "build": "npm run format && npm run lint && npm run tsc",
    "start:prod": "npm run build && node --experimental-specifier-resolution=node dist/index.js",
    "start": "npm run start:prod",
    "dev": "cross-env-shell DEBUG=express:* node --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts",
    "format": "prettier --write \"**/*.ts\"",
    "lint": "eslint . --ext 'ts,json'",
    "tsc": "tsc",

    "test": "cross-env-shell TS_JEST_LOG=ts-jest.jog NODE_OPTIONS=--experimental-vm-modules jest --detectOpenHandles --verbose --testTimeout 20000 --coverage=true --reporters=default --json --debug --outputFile=./test/log.json",
    "test:list": "jest --detectOpenHandles --coverage=true --listTests --debug"

  },
  "dependencies": {

    "cookie-parser": "~1.4.4",
    "cors": "^2.8.5",
    "debug": "~2.6.9",
    "dotenv": "^16.0.0",
    "express": "~4.16.1",
    "express-fileupload": "^1.3.1",
    "http-errors": "^1.6.3",
    "into-stream": "^7.0.0",
    "jest": "^28.1.0",
    "morgan": "~1.9.1",
    "multer": "^1.4.4",
    "save-dev": "0.0.1-security",
    "sharp": "^0.30.4",
    "supertest": "^6.2.3",
    "ts-jest": "^28.0.2",
    "ts-node": "^10.7.0",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@types/jest": "^27.5.1",
    "@types/supertest": "^2.0.12",
    "@azure/storage-blob": "^12.9.0",
    "@types/cookie-parser": "^1.4.3",
    "@types/cors": "^2.8.12",
    "@types/debug": "^4.1.7",
    "@types/express": "^4.16.1",
    "@types/express-fileupload": "^1.2.2",
    "@types/http-errors": "^1.8.2",
    "@types/into-stream": "^3.1.1",
    "@types/morgan": "^1.9.3",
    "@types/multer": "^1.4.7",
    "@types/node": "^17.0.31",
    "@types/sharp": "^0.30.2",
    "@types/uuid": "^8.3.4",
    "@typescript-eslint/eslint-plugin": "^5.22.0",
    "@typescript-eslint/parser": "^5.22.0",
    "cross-env": "^7.0.3",
    "eslint": "^8.15.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-node": "^11.1.0",
    "nodemon": "^2.0.16",
    "prettier": "^2.6.2",
    "tslib": "^2.4.0",
    "typescript": "^4.6.4"
  }
}

简易配置JS

/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
  clearMocks: true,
  moduleFileExtensions: ["js", "ts", "json", "node"],
  roots: ["./"],
  testMatch: ["./**/*.test.ts"],
  preset: "ts-jest",
  testEnvironment: "node",
  transform: {
    "^.+\\.ts?$": "ts-jest",
  },
  transformIgnorePatterns: [
    "./node_modules/",
    "./dist/",
    "./files/",
    "./public/",
  ],
  extensionsToTreatAsEsm: ['.ts'],
  globals: {
    "ts-jest": {
      tsconfig: './tsconfig.json',
      useESM: true
    }
  }
};
bqjvbblv

bqjvbblv9#

1.用下面命令更改tsconfig

compilerOptions": {
       "module": "esnext",
       //... remaining options 
     }

2.在jest.config中添加以下内容

globals: {
     "ts-jest": {
      tsconfig: false,
       useESM: true,
      babelConfig: true,
       plugins: ["babel-plugin-transform-vite-meta-env"],
     },
    },
   transform: {
      "^.+\\.(js|jsx|ts)$": "babel-jest",
    }
`

3.现在它将开始给出错误无法使用import. meta要解决此问题,请在Babel配置中添加以下内容:`

module.exports = function (api) {
 
 api.cache(true);
  const presets = [
   ["@babel/preset-env", { targets: { node: "current" } }],
  "@babel/preset-typescript",
  "@babel/preset-react",
];

return {
  presets,
  plugins: [
    "@babel/plugin-transform-runtime",
    "babel-plugin-transform-import-meta",
    "babel-plugin-transform-vite-meta-env",
   ],
  };
 };`

@babel/plugin-transform-runtime,babel-plugin-transform-import- meta这些插件将帮助您解决这个问题

相关问题