React Native测试报错:Cannot use import statement outside a module及后续问题
React Native测试脚本运行报错及解决方案
问题1:无法在模块外使用import语句
运行React Native测试脚本时触发如下错误:
node_modules/react-native/Libraries/polyfills/babelHelpers.js:3 import _typeof from "@babel/runtime/helpers/typeof"; ^^^^^^ SyntaxError: 不能在模块外使用import语句 在 ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17) 在 ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25) 在 Object.<anonymous> (node_modules/react-native/jest/setup.js:70:6)
问题2:添加"type": "module"后的ESM加载错误
尝试在package.json中添加"type": "module"后,出现新的模块加载错误:
Error [ERR_REQUIRE_ESM]: 必须使用import加载ES模块: /Users/{user_name}/{project_name}/babel.config.js 不支持使用require()加载ES模块。 从/Users/{user_name}/{project_name}/node_modules/babel-jest/build/index.js中require()加载/Users/{user_name}/{project_name}/babel.config.js属于ES模块文件,因为它是.js文件,且最近的父级package.json包含"type": "module",该配置将此包范围内的所有.js文件定义为ES模块。 请将babel.config.js重命名为.cjs后缀,修改调用代码使用import(),或者从/Users/{user_name}/{project_name}/package.json中移除"type": "module"。
相关配置文件
package.json(devDependencies及jest配置)
"devDependencies": { "@babel/core": "^7.15.0", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-json-strings": "^7.2.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-import-meta": "^7.2.0", "@babel/plugin-transform-classes": "^7.14.9", "@babel/preset-env": "^7.15.0", "@babel/preset-typescript": "^7.7.4", "@testing-library/react-native": "9.0.0", "@types/jest": "^24.0.23", "@types/react": "^16.9.14", "@types/react-navigation": "1.5.9", "@types/react-test-renderer": "^16.9.1", "@typescript-eslint/eslint-plugin": "^4.20.0", "@typescript-eslint/experimental-utils": "^4.20.0", "@typescript-eslint/parser": "^4.20.0", "babel-core": "7.0.0-bridge.0", "babel-eslint": "^10.1.0", "babel-jest": "^23.6.0", "babel-plugin-transform-remove-console": "^6.8.5", "babel-preset-react-native": "^5.0.1", "enzyme": "^3.6.0", "enzyme-adapter-react-16": "^1.5.0", "eslint": "^7.23.0", "eslint-config-prettier": "^8.1.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-json": "^2.1.2", "eslint-plugin-jsx-a11y": "6.4.1", "eslint-plugin-react": "^7.23.1", "husky": "^1.0.0-rc.14", "jest": "^24.9.0", "jest-fetch-mock": "^2.1.2", "jest-serializer-enzyme": "^1.0.0", "metro-react-native-babel-preset": "0.66.2", "prettier": "^2.2.1", "react": ">=16.8.6", "react-dom": "^16.8.3", "react-native": "0.59.10", "react-native-gesture-handler": "^1.10.3", "react-native-render-html": "4.1.1", "react-navigation": "2.18.2", "react-test-renderer": "16.8.6", "typescript": "^4.3.2" }, ... "jest": { "preset": "react-native", "testEnvironment": "node", "transformIgnorePatterns": [ "node_modules/(?!react-native|native-base|react-navigation|react-native-fabric|static-container|@shoutem|lottie-react-native)", "/@babel/runtime/", "//core-js/" ], "automock": false, "bail": true, "verbose": true, "coverageThreshold": { "global": { "statements": 0, "branches": 0, "lines": 0, "functions": 0 } }, "coverageReporters": [ "html", "text" ], "collectCoverageFrom": [ "./app/**/*.{js,jsx,ts,tsx}" ], "coverageDirectory": "./__tests__/config/coverage", "cacheDirectory": "./__tests__/config/cache", "testPathIgnorePatterns": [ "/__tests__/config", "/__tests__/config/*", "/__tests__/__mocks__", "/__tests__/__mocksResponse__", "/__tests__/__constants__", "node_modules", ".history" ], "transform": { "^.+\\.test.js$": "babel-jest", "^.+\\.jsx$": "babel-jest", "^.+\\.js$": "babel-jest", "^.+\\.(ts|tsx)$": "babel-jest" }, "setupFiles": [ "./__tests__/config/setup.js" ], "setupFilesAfterEnv": [ "./__tests__/config/setup.js" ] },
babel.config.js
module.exports = { presets: ['module:metro-react-native-babel-preset'], env: { production: { plugins: ['transform-remove-console'], }, test: { presets: ['@babel/preset-env', 'react-native', '@babel/preset-typescript'], plugins: [ '@babel/plugin-syntax-dynamic-import', '@babel/plugin-syntax-import-meta', '@babel/plugin-transform-flow-strip-types', '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-json-strings', '@babel/plugin-transform-classes', '@babel/syntax-class-properties', ], }, }, plugins: ['@babel/plugin-proposal-nullish-coalescing-operator'], };
解决方案
1. 移除package.json中的"type": "module"
当前版本的babel-jest不支持通过require()加载ES模块格式的babel配置文件,添加该配置会导致模块加载冲突,直接移除即可。
2. 调整Jest的transformIgnorePatterns配置
第一个错误的核心是@babel/runtime未被babel-jest转译,导致import语法无法识别。修改jest配置中的transformIgnorePatterns,将@babel/runtime加入需要转译的白名单:
"transformIgnorePatterns": [ "node_modules/(?!react-native|native-base|react-navigation|react-native-fabric|static-container|@shoutem|lottie-react-native|@babel/runtime)", "//core-js/" ]
3. 优化babel测试环境配置
修改babel.config.js中的test配置,移除重复的react-native预设,改用和主配置一致的module:metro-react-native-babel-preset,同时删除重复的语法插件:
test: { presets: ['@babel/preset-env', 'module:metro-react-native-babel-preset', '@babel/preset-typescript'], plugins: [ '@babel/plugin-syntax-dynamic-import', '@babel/plugin-syntax-import-meta', '@babel/plugin-transform-flow-strip-types', '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-json-strings', '@babel/plugin-transform-classes' ], },
4. 统一babel-jest和jest版本
当前项目中jest为24.9.0,babel-jest为23.6.0,版本差距较大易引发兼容性问题,建议将babel-jest升级到24.x版本,比如执行:
npm install babel-jest@^24.9.0 --save-dev
内容的提问来源于stack exchange,提问作者Byron Kamal
相关产品推荐
相关产品推荐

