升级Expo SDK 47后Jest-expo所有测试套件失败求助
Expo SDK 47升级后测试套件全部失败的解决思路
升级Expo项目至SDK 47前,所有测试套件均正常运行,但现在出现无法解决的错误:
注意到相关包现在改用TypeScript编写,推测错误可能与此有关。是否需要调整配置以适配TS编写的包?
使用的依赖版本
"devDependencies": { "@babel/core": "^7.19.3", "@babel/plugin-proposal-optional-chaining": "^7.16.7", "@types/react-native": "~0.70.6", "babel-eslint": "^10.1.0", "babel-jest": "^26.6.3", "babel-plugin-module-resolver": "^4.1.0", "babel-preset-expo": "~9.2.1", "concurrently": "^7.2.2", "deprecated-react-native-prop-types": "^2.3.0", "eslint": "^7.32.0", "eslint-plugin-jest": "^24.7.0", "eslint-plugin-react": "^7.29.4", "husky": "^6.0.0", "jest-expo": "^47.0.1", "jest-json": "^1.1.1", "postcss": "^8.4.14", "react-native-jest-mocks": "^1.5.0", "tailwindcss": "^3.1.4" }
Jest配置
"jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|unimodules-permissions-interface|react-clone-referenced-element|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|sentry-expo|native-base|@codler/react-native-keyboard-aware-scroll-view|react-native-paper|react-native-paper/.*|expo-modules-core|expo-modules-core/.*|)" ], "setupFiles": [ "./jest-setup.js" ], "setupFilesAfterEnv": [ "jest-json" ] }
更新内容:测试示例与相关代码
测试示例代码
import Home from './Home'; import React from 'react'; import { cleanup, render, } from '@testing-library/react-native'; import axios from 'axios'; import { Alert } from 'react-native'; import { MockedNavigator, waitFor } from '../../../helpers/testing'; jest.mock('axios'); jest.mock('./Home', () => './Home'); const mockedNavigate = jest.fn(); jest.mock("@react-navigation/native", () => { const actualNav = jest.requireActual("@react-navigation/native"); return { ...actualNav, useNavigation: () => ({ navigate: mockedNavigate, dispatch: jest.fn(), addListener: jest.fn(), removeListener: jest.fn(), }), }; }); beforeAll(() => { // Home使用fetch重新加载用户,所以mock返回假用户数据 global.fetch = jest.fn().mockResolvedValue({ status: 200, ok: true, json: () => Promise.resolve({ data: { user: {} } }), }); }); afterEach(cleanup); const setup = async () => { return render( <MockedNavigator routes={[ { name: 'Home', component: Home }, ]} /> ); }; describe('API', () => { test('请求失败时显示错误提示', async () => { axios.get.mockRejectedValue({ response: { data: undefined, status: 500 }, }); // Mock Alert组件 Alert.alert = jest.fn(); await setup(); await waitFor(() => { expect(Alert.alert).toHaveBeenCalledWith('Error', expect.any(String)); }); }); });
MockedNavigator代码
export const MockedNavigator = ({ routes }) => { const { Screen, Navigator } = createStackNavigator(); return ( <NavigationContainer> <Providers> <ReservationProvider> <Navigator> {routes.map((props, index) => ( <Screen key={index} {...props} /> ))} </Navigator> </ReservationProvider> </Providers> </NavigationContainer> ); };
Providers组件代码
export const Providers = ({ children }) => ( <NotificationProvider> <GeolocationProvider> <SettingsProvider> <OAuthProvider> <TailwindProvider> <ThemeProvider> <PortalProvider> <CalendarProvider> <ForegroundNotification /> {children} </CalendarProvider> </PortalProvider> </ThemeProvider> </TailwindProvider> </OAuthProvider> </SettingsProvider> </GeolocationProvider> </NotificationProvider> );
ThemeProvider组件代码
export const ThemeProvider = ({ children }) => { const [themeWithFont, setThemeWithFont] = useState(theme); useEffect(() => { const loadFonts = async () => { setThemeWithFont({ ...theme, fonts: { ...theme.fonts, medium: { fontFamily: C.fontFamilyDefault }, } }); }; loadFonts(); }, []); return <PaperProvider theme={themeWithFont}>{children}</PaperProvider>};
PaperProvider引入代码
import { Provider as PaperProvider } from 'react-native-paper';
解决思路
调整转译忽略列表适配TS包
检查transformIgnorePatterns,确保所有TS编写的第三方包(如react-native-paper等)都在白名单内,让Jest能转译这些包的代码。可以简化为更兼容的写法:"transformIgnorePatterns": [ "node_modules/(?!((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@unimodules/.*|sentry-expo|native-base|react-native-paper|@react-navigation/.*))" ]对齐Jest相关依赖版本
当前babel-jest(26.x)与jest-expo(47.x)版本不匹配,建议将babel-jest升级到29.x版本(Expo SDK 47基于Jest 29),同时更新@babel/core和babel-preset-expo到最新兼容版本,保证转译配置的兼容性。添加TypeScript转译支持
安装@babel/preset-typescript依赖,并在babel.config.js中添加该预设:module.exports = function(api) { api.cache(true); return { presets: ['babel-preset-expo', '@babel/preset-typescript'], plugins: [ '@babel/plugin-proposal-optional-chaining', ['babel-plugin-module-resolver', { /* 你的现有配置 */ }] ] }; };修复测试中的Mock问题
测试里的jest.mock('./Home', () => './Home')会导致循环引用,改为正确的Mock方式:jest.mock('./Home', () => ({ default: jest.fn(() => null) }));同时确保第三方依赖的Mock适配TS类型,比如
react-native-paper的Provider在测试中初始化正确。清理缓存后重新测试
执行jest --clearCache清除Jest缓存,避免旧转译代码干扰,再重新运行测试。
内容的提问来源于stack exchange,提问作者Brian Serrano
相关产品推荐
相关产品推荐

