React Native项目中Jest与TypeScript配置失败求助
React Native + Jest + TypeScript 配置故障排查
我正在给React Native项目配置Jest和TypeScript,但一直无法正常运行。已经按照jest/ts-jest官方文档配置,但修改配置文件后会出现两种错误:
错误1:Unexpected token '<'
\Development\stories\__tests__\App.test.tsx:14 (0, react_native_1.render)(<App_1.default />); ^ SyntaxError: Unexpected token '<' at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1678:14)
错误2:Cannot use import statement outside a module
SyntaxError: Cannot use import statement outside a module > 1 | import { getStorybookUI } from '@storybook/react-native'; | ^ 2 | 3 | import './storybook.requires'; 4 |
项目配置文件
package.json
{ "name": "stories", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "start": "react-native start", "test": "jest", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "update-stories": "sb-rn-get-stories --config-path .storybook/.ondevice", "prestart": "yarn update-stories", "storybook-watcher": "sb-rn-watcher --config-path .storybook/.ondevice", "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" }, "dependencies": { "@react-native-async-storage/async-storage": "^1.17.10", "@react-native-community/datetimepicker": "^6.5.0", "@react-native-community/slider": "^4.3.2", "react": "18.1.0", "react-native": "0.70.2" }, "devDependencies": { "@babel/core": "^7.12.9", "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^2.0.0", "@storybook/addon-actions": "^6.5.12", "@storybook/addon-controls": "^6.5.12", "@storybook/addon-essentials": "^6.5.12", "@storybook/addon-links": "^6.5.12", "@storybook/addon-ondevice-actions": "^6.0.1-beta.8", "@storybook/addon-ondevice-backgrounds": "^6.0.1-beta.8", "@storybook/addon-ondevice-controls": "^6.0.1-beta.8", "@storybook/addon-ondevice-notes": "^6.0.1-beta.8", "@storybook/addon-react-native-web": "^0.0.18", "@storybook/react": "6.3", "@storybook/react-native": "^6.0.1-beta.8", "@storybook/testing-library": "^0.0.13", "@testing-library/jest-native": "^5.0.0", "@testing-library/react-native": "^11.2.0", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^29.1.1", "@types/react-native": "^0.70.4", "@types/react-test-renderer": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.37.0", "@typescript-eslint/parser": "^5.37.0", "babel-jest": "^29.1.2", "babel-loader": "^8.2.5", "babel-plugin-react-native-web": "^0.18.9", "eslint": "^7.32.0", "jest": "^29.1.2", "metro-react-native-babel-preset": "0.72.3", "react-dom": "18.2.0", "react-native-safe-area-context": "^4.4.1", "react-native-web": "^0.18.9", "react-test-renderer": "18.1.0", "ts-jest": "^29.0.3", "typescript": "^4.8.3" }, "resolutions": { "@types/react": "^17" } }
tsconfig.json
// prettier-ignore { "extends": "@tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */ "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Completeness */ "skipLibCheck": true, /* Skip type checking all .d.ts files. */ "allowSyntheticDefaultImports": true, } }
tsconfig.spec.json
// tsconfig.spec.json { "extends": "./tsconfig.json", "compilerOptions": { "jsx": "react-native", // Switching to "react" throws "SyntaxError: Cannot use import statement outside a module" } }
jest.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { preset: 'react-native', transform: { '^.+\\.jsx$': 'babel-jest', '^.+\\.tsx?$': [ 'ts-jest', { tsconfig: 'tsconfig.spec.json', }, ], }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], transformIgnorePatterns: [ 'node_modules/(?!(jest-)?@react-native|react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base)', ], setupFilesAfterEnv: [ '@testing-library/jest-native/extend-expect', '<rootDir>/__mocks__/globalMock.js', ], };
babel.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { presets: ['module:metro-react-native-babel-preset'], };
App.test.tsx
/** * @format */ import 'react-native'; import React from 'react'; import App from '../App'; import { render } from '@testing-library/react-native'; test('renders correctly', () => { render(<App />); });
解决方案
修复「Unexpected token '<'」错误
该错误是TSX文件的JSX语法未被正确转译,调整以下配置:
- 修改
tsconfig.spec.json的jsx选项为react-jsx(适配React 18自动JSX转换):
// tsconfig.spec.json { "extends": "./tsconfig.json", "compilerOptions": { "jsx": "react-jsx" } }
- 简化
jest.config.js的transform规则,确保TS/TSX文件被ts-jest正确处理:
/** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { preset: 'react-native', transform: { '^.+\\.(js|jsx)$': 'babel-jest', '^.+\\.(ts|tsx)$': 'ts-jest' }, // 其余配置保持不变 };
修复「Cannot use import statement outside a module」错误
该错误是Storybook相关文件未被Jest转译,将@storybook/react-native加入transformIgnorePatterns白名单:
transformIgnorePatterns: [ 'node_modules/(?!(jest-)?@react-native|react-native|react-clone-referenced-element|@react-native-community|@storybook/react-native|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base)', ],
额外优化
- 修正
babel.config.js的错误注释(它不是Jest配置文件):
module.exports = { presets: ['module:metro-react-native-babel-preset'], };
- 清除Jest缓存,避免旧配置残留:
jest --clearCache
- 确认
App.tsx(若为TSX文件)导出默认组件,保证测试导入路径正确。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

