You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest配置忽略node_modules仍报import语句模块外使用错误

Jest 单元测试报 ESM 语法错误问题

问题现象

  • 使用 Jest 进行单元测试时,抛出 SyntaxError: Cannot use import statement outside a module 报错,溯源后发现错误来自 jsdom-worker 包依赖引入的 node-fetch 包,初步怀疑问题与 node-fetch 包相关,但无法完全确认。
  • 已经在 jest.config.js 中配置了忽略 node_modules 路径,仍出现该问题,不清楚具体原因。

当前 jest.config.js 配置文件内容如下:

const ignores = ['/node_modules/', '/__fixtures__/', '/fixtures/', '/__tests__/helpers/', '/__tests__/utils/', '__mocks__'];

module.exports = {
    preset: 'ts-jest',
    roots: ['<rootDir>'],
    modulePaths: [
        "<rootDir>/src"
    ],
    moduleDirectories: [
        "node_modules"
    ],
    transformIgnorePatterns: [...ignores],
    transform: {
        '^.+\\.(ts|tsx|js|jsx)?$': 'ts-jest',
        '^.+\\.(gif|svg|ico)$': '<rootDir>/svgTransform.js',
    },
    testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.js?$',
    moduleFileExtensions: ['tsx', 'js', 'json', 'node', 'ts'],
    moduleNameMapper: {
        "\\.(css|less|scss|sass)$": "identity-obj-proxy"
      },
    clearMocks: true,
    // collectCoverage: true, // todo
    // coverageDirectory: "coverage",  // todo
    testEnvironment: 'jsdom',
    setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect', 'jsdom-worker'],
}
// }

问题更新

将 node-fetch 版本降级至 2.4 后,上述报错消失,但其他包又出现了完全相同的语法错误,问题反复出现。

代码报错追踪截图:
代码报错截图

已尝试的配置

当前使用的 babel.config.js

配置逻辑为测试环境下将模块转为 CommonJS 格式,方便 Jest 识别,具体内容如下:

// 测试环境下需要将模块转为CommonJS格式,Jest才可正常识别
const isTest = String(process.env.NODE_ENV) === 'test'
const isProd = String(process.env.NODE_ENV) === 'production'

module.exports = {
    // 用于转换TSX及其他React相关Babel插件
    presets: [
        // 根据目标环境智能完成转译
        ['@babel/preset-env', { modules: isTest ? 'commonjs' : false }],
        // 让Babel支持TypeScript语法
        '@babel/preset-typescript',
    ],
}

尝试过的第三方Babel配置

曾尝试使用kcd-scripts内置的Babel配置,对应代码如下:

"use strict";

const browserslist = require('browserslist');
const semver = require('semver');
const {
  ifDep,
  ifAnyDep,
  ifTypescript,
  parseEnv,
  appDirectory,
  pkg
} = require('../utils');

const {
  BABEL_ENV,
  NODE_ENV,
  BUILD_FORMAT
} = process.env;
const isTest = (BABEL_ENV || NODE_ENV) === 'test';
const isPreact = parseEnv('BUILD_PREACT', false);
const isRollup = parseEnv('BUILD_ROLLUP', false);
const isUMD = BUILD_FORMAT === 'umd';
const isCJS = BUILD_FORMAT === 'cjs';
const isWebpack = parseEnv('BUILD_WEBPACK', false);
const isMinify = parseEnv('BUILD_MINIFY', false);
const treeshake = parseEnv('BUILD_TREESHAKE', isRollup || isWebpack);
const alias = parseEnv('BUILD_ALIAS', isPreact ? {
  react: 'preact'
} : null);
const hasBabelRuntimeDep = Boolean(pkg.dependencies && pkg.dependencies['@babel/runtime']);
const RUNTIME_HELPERS_WARN = '你应当将@babel/runtime添加为项目依赖,这样可以直接复用node_modules中的babel helper代码,避免在每个文件中重复打包helper副本';

if (!treeshake && !hasBabelRuntimeDep && !isTest) {
  throw new Error(RUNTIME_HELPERS_WARN);
} else if (treeshake && !isUMD && !hasBabelRuntimeDep) {
  console.warn(RUNTIME_HELPERS_WARN);
}

/**
 * 按照browserslist声明的策略加载浏览器配置,未找到自定义配置时回退到默认配置
 */
const browsersConfig = browserslist.loadConfig({
  path: appDirectory
}) || ['defaults'];
const envTargets = isTest ? {
  node: 'current'
} : isWebpack || isRollup ? {
  browsers: browsersConfig
} : {
  node: getNodeVersion(pkg)
};
const envOptions = {
  modules: false,
  loose: true,
  targets: envTargets
};

module.exports = () => ({
  presets: [[require.resolve('@babel/preset-env'), envOptions], ifAnyDep(['react', 'preact'], [require.resolve('@babel/preset-react'), {
    pragma: isPreact ? ifDep('react', 'React.h', 'h') : undefined
  }]), ifTypescript([require.resolve('@babel/preset-typescript')])].filter(Boolean),
  plugins: [[require.resolve('@babel/plugin-transform-runtime'), {
    useESModules: treeshake && !isCJS
  }], require.resolve('babel-plugin-macros'), alias ? [require.resolve('babel-plugin-module-resolver'), {
    root: ['./src'],
    alias
  }] : null, ifAnyDep(['react', 'preact'], [require.resolve('babel-plugin-transform-react-remove-prop-types'), isPreact ? {
    removeImport: true
  } : {
    mode: 'unsafe-wrap'
  }]), isUMD ? require.resolve('babel-plugin-transform-inline-environment-variables') : null, [require.resolve('@babel/plugin-proposal-class-properties'), {
    loose: true
  }], isMinify ? require.resolve('babel-plugin-minify-dead-code-elimination') : null, treeshake ? null : require.resolve('@babel/plugin-transform-modules-commonjs')].filter(Boolean)
});

function getNodeVersion({
  engines: {
    node: nodeVersion = '10.13'
  } = {}
}) {
  const oldestVersion = semver.validRange(nodeVersion).replace(/[>=<|]/g, ' ').split(' ').filter(Boolean).sort(semver.compare)[0];

  if (!oldestVersion) {
    throw new Error(`无法从package.json的engines.node字段配置的"${nodeVersion}"范围中确定最低支持的Node版本,请调整版本范围配置避免歧义。`);
  }

  return oldestVersion;
}

内容的提问来源于stack exchange,提问作者AAMCODE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 00:36:20