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

MUI5配合Jest运行报SyntaxError: Cannot use import statement outside a module怎么解决

问题描述

可复现仓库地址:https://github.com/hutber/cannotusestatement
将上述仓库导入CodeSandbox(地址:https://codesandbox.io/s/vigilant-bartik-bmz8x)时测试可以正常通过,但本地拉取该仓库运行测试就会失败。问题根源是Jest没有编译运行测试所需的node_modules依赖,期望实现本地测试正常运行。

相关代码&报错

测试用例代码

import React from 'react'
import { renderWithThemeProvider, screen } from 'test-utils'
import { Select } from './Select'

it('renders correctly', () => {
  const tree = renderWithThemeProvider(<Select id="testSelect"></Select>)
  expect(tree).toMatchSnapshot()
})

原有jest.config.js配置

module.exports = {
  roots: ['<rootDir>', './src'],
  moduleDirectories: ['<rootDir>', 'node_modules/', './src'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  testEnvironment: 'jsdom',
  testMatch: ['**/*.test.(ts|tsx)', '**/__tests__/*.(ts|tsx)'],
  moduleNameMapper: {
    // 测试运行时mock以下格式的文件
    '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'identity-obj-proxy',
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
    'app-config': '<rootDir>/app-config/default',
    '^@components(.*)$': '<rootDir>/src/components$1',
    '^@themes(.*)$': '<rootDir>/src/themes$1',
  },
  coverageThreshold: {
    global: {
      statements: 50,
    },
  },
}

原有babel.config.js配置

module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react'],
  env: {
    test: {
      presets: ['@babel/preset-env', '@babel/preset-react'],
      plugins: [
        [
        'babel-plugin-transform-imports',
        '@babel/plugin-proposal-class-properties',
        'transform-es2015-modules-commonjs',
        'babel-plugin-dynamic-import-node',
        'babel-plugin-styled-components',
      ],
    },
  },
}

package.json测试命令

"test": "jest --watchAll=false",

运行报错信息

(base) hutber@hutber:/var/www/target/component-library$ yarn test src/components/Select/Select.test.tsx
yarn run v1.22.17
$ jest --watchAll=false src/components/Select/Select.test.tsx
 测试未通过  src/components/Select/Select.test.tsx
  ● 测试套件运行失败

    Jest遇到了无法识别的字符
    Jest解析文件失败。出现该问题通常是因为你的代码或依赖使用了非标准JavaScript语法,或是Jest没有配置对应的语法支持。

    Jest默认支持Babel,会根据你的Babel配置把文件转换为合法的JS格式。
    默认情况下transform转换器会忽略"node_modules"文件夹。

    可尝试以下解决方案:
     • 如果要使用ECMAScript Modules,可在Jest配置中开启对应支持
     • 如果要使用TypeScript,可参考Jest官方的TypeScript接入指南
     • 如果需要转换部分"node_modules"中的文件,可在配置中自定义"transformIgnorePatterns"规则
     • 如果需要自定义转换逻辑,可在配置中指定"transform"参数
     • 如果只是需要mock非JS模块(比如二进制资源),可通过"moduleNameMapper"配置项做替换

    详细信息:

    /var/www/target/component-library/node_modules/@mui/material/styles/styled.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { createStyled, shouldForwardProp } from '@mui/system';
                                                                                      ^^^^^^

    语法错误:无法在模块外部使用import语句

      1 | import React from 'react'
    > 2 | import styled from '@mui/material/styles/styled'
        | ^
      3 |
      4 | import MuiSelect, { SelectProps as MuiSelectProps } from '@mui/material/Select'
      5 | import InputLabel from '@mui/material/InputLabel'

      位置:Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
      触发位置:src/components/Select/Select.tsx:2:1

测试套件:1个失败,共1个
测试用例:共0个
快照:共0个
耗时:3.272 s

Select组件代码

import React from 'react'
import styled from '@mui/material/styles/styled'

import MuiSelect, { SelectProps as MuiSelectProps } from '@mui/material/Select'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import MuiFormControl from '@mui/material/FormControl'

interface ISelect extends MuiSelectProps {
  id: string
  label?: string
  options?: { text: string; option: string }[]
}
const FormControl = styled(MuiFormControl)`
  color: #fff;
  border-radius: 30px;
  width: 180px;
`

export const Select: React.FC<ISelect> = ({ label, id, children, options, ...props }) => {
  return (
    // @ts-ignore
    <FormControl fullWidth hiddenLabel>
      {label && (
        <InputLabel id={`input_${id}`} shrink={false}>
          {label}
        </InputLabel>
      )}
      <MuiSelect id={id} {...props}>
        {options && options.map(({ text, option }: { text: string; option: string }) => <MenuItem value={option}>{text}</MenuItem>)}
        {children && children}
      </MuiSelect>
    </FormControl>
  )
}

export default Select

解决方案

错误原因

Jest默认不会编译node_modules目录下的所有依赖,而你用到的@mui/material采用ES模块规范发布,未提供CommonJS兼容版本,所以Jest读取文件时识别不了import语法,直接抛出语法错误。CodeSandbox默认内置了ES模块依赖的转换规则,所以在线运行不会报错。

调整步骤

1. 修改jest.config.js配置

补充js/jsx文件的转换规则,同时添加transformIgnorePatterns配置,将@mui相关依赖排除在转换忽略列表之外:

module.exports = {
  roots: ['<rootDir>', './src'],
  moduleDirectories: ['<rootDir>', 'node_modules/', './src'],
  transform: {
    '^.+\\.(ts|tsx|js|jsx)$': 'ts-jest',
  },
  testEnvironment: 'jsdom',
  testMatch: ['**/*.test.(ts|tsx)', '**/__tests__/*.(ts|tsx)'],
  transformIgnorePatterns: ['node_modules/(?!(@mui|@babel/runtime))/'],
  moduleNameMapper: {
    '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'identity-obj-proxy',
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
    'app-config': '<rootDir>/app-config/default',
    '^@components(.*)$': '<rootDir>/src/components$1',
    '^@themes(.*)$': '<rootDir>/src/themes$1',
  },
  globals: {
    'ts-jest': {
      tsconfig: '<rootDir>/tsconfig.json',
      allowJs: true
    }
  },
  coverageThreshold: {
    global: {
      statements: 50,
    },
  },
}

2. 修正babel.config.js配置

原有配置中plugins数组开头多写了一个多余的[,属于语法错误,同时补充TypeScript编译预设:

module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'],
  env: {
    test: {
      presets: [
        ['@babel/preset-env', { targets: { node: 'current' } }],
        '@babel/preset-react',
        '@babel/preset-typescript'
      ],
      plugins: [
        '@babel/plugin-proposal-class-properties',
        'transform-es2015-modules-commonjs',
        'babel-plugin-dynamic-import-node',
        'babel-plugin-styled-components',
      ],
    },
  },
}

如果本地没有安装@babel/preset-typescript,先执行yarn add @babel/preset-typescript -D安装依赖。

3. 执行测试

修改配置后重新运行yarn test,测试即可正常执行。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:24:02