Expo+Firebase项目Jest测试报错:Unexpected token 'export'
问题:Expo + Firebase 应用 Jest 测试报错:Unexpected token 'export'
环境信息
- Node.js 版本:20.15.0
- 操作系统:Arch Linux
- 技术栈:Expo 51.0.22、Firebase 10.12.4、Jest 29.7.0、jest-expo 51.0.3
配置文件与代码
package.json
{ "name": "test", "version": "1.0.0", "main": "expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "test": "jest" }, "dependencies": { "expo": "~51.0.22", "expo-status-bar": "~1.12.1", "firebase": "^10.12.4", "react": "18.2.0", "react-native": "0.74.3" }, "devDependencies": { "@types/jest": "^29.5.12", "@types/react": "~18.2.45", "jest": "^29.7.0", "jest-expo": "^51.0.3", "typescript": "^5.1.3" }, "private": true, "packageManager": "pnpm@9.5.0+sha512.140036830124618d624a2187b50d04289d5a087f326c9edfc0ccd733d76c4f52c3a313d4fc148794a2a9d81553016004e6742e8cf850670268a7387fc220c903", "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)" ] } }
tsconfig.json
{ "extends": "expo/tsconfig.base", "compilerOptions": { "strict": true } }
babel.config.json
module.exports = function (api) { api.cache(true); return { presets: ["babel-preset-expo"] }; };
index.tsx
import { StatusBar } from "expo-status-bar"; import { createUserWithEmailAndPassword } from "firebase/auth"; import { StyleSheet, Text, View } from "react-native"; import { auth } from "./config/firebase"; export default () => { return ( <View style={styles.container} onTouchStart={() => createUserWithEmailAndPassword( auth, "test@provider.com", "strong password" ) } > <Text>Open up App.tsx to start working on your app!</Text> <StatusBar style="auto" /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center", }, });
app.test.tsx
import App from ".."; describe("<App />", () => { it("has 1 child", () => { expect(App).toBeDefined(); }); });
firebase.ts
import { FirebaseOptions, initializeApp } from "firebase/app"; import { connectAuthEmulator, initializeAuth } from "firebase/auth"; import { connectFirestoreEmulator, getFirestore } from "firebase/firestore"; export const firebaseConfig: FirebaseOptions = { apiKey: "FIREBASE_API_KEY", authDomain: "FIREBASE_AUTH_DOMAIN", projectId: "FIREBASE_PROJECT_ID", storageBucket: "FIREBASE_STORAGE_BUCKET", messagingSenderId: "FIREBASE_MESSAGING_SENDER_ID", appId: "FIREBASE_APP_ID", }; const app = initializeApp(firebaseConfig); export const auth = initializeAuth(app, {}); export const store = getFirestore(app); connectAuthEmulator(auth, "http://127.0.0.1:9099"); connectFirestoreEmulator(store, "http://127.0.0.1", 8080);
错误日志
运行 npm test 后出现以下错误:
> test@1.0.0 test > jest FAIL __tests__/index.test.tsx ● Test suite failed to run Jest encountered an unexpected token Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax. Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration. By default "node_modules" folder is ignored by transformers. Here's what you can do: • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it. • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config. • If you need a custom transformation specify a "transform" option in your config. • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option. You'll find more details and examples of these config options in the docs: https://jestjs.io/docs/configuration For information about custom transformations, see: https://jestjs.io/docs/code-transformation Details: /home/rshedy/Desktop/test/node_modules/firebase/auth/dist/esm/index.esm.js:1 ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export * from '@firebase/auth'; ^^^^^^ SyntaxError: Unexpected token 'export' 1 | import { StatusBar } from "expo-status-bar"; > 2 | import { createUserWithEmailAndPassword } from "firebase/auth"; | ^ 3 | import { StyleSheet, Text, View } from "react-native"; 4 | import { auth } from "./config/firebase"; 5 | at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14) at Object.require (app.tsx:2:1) at Object.require (__tests__/index.test.tsx:2:1) Test Suites: 1 failed, 1 total Tests: 0 total Snapshots: 0 total Time: 1.474 s Ran all test suites.
解决方案
问题根源是Jest默认忽略node_modules目录下的文件转译,而Firebase v9+使用ESM模块格式,未被纳入转译白名单导致解析失败。
步骤1:更新Jest配置
修改package.json中的jest.transformIgnorePatterns,将firebase和@firebase相关模块加入白名单:
"jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|firebase|@firebase)" ] }
步骤2:可选优化测试速度
为避免测试中实际连接Firebase模拟器,可在测试文件顶部添加模块模拟:
jest.mock('../config/firebase', () => ({ auth: {}, store: {} })); jest.mock('firebase/auth', () => ({ createUserWithEmailAndPassword: jest.fn() }));
完成以上修改后,Jest会正确转译Firebase的ESM模块,解决Unexpected token 'export'错误。
内容的提问来源于stack exchange,提问作者Mhmd Al-Rshedy
相关产品推荐
相关产品推荐

