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

升级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';

解决思路

  1. 调整转译忽略列表适配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/.*))"
    ]
    
  2. 对齐Jest相关依赖版本
    当前babel-jest(26.x)与jest-expo(47.x)版本不匹配,建议将babel-jest升级到29.x版本(Expo SDK 47基于Jest 29),同时更新@babel/core和babel-preset-expo到最新兼容版本,保证转译配置的兼容性。

  3. 添加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', { /* 你的现有配置 */ }]
        ]
      };
    };
    
  4. 修复测试中的Mock问题
    测试里的jest.mock('./Home', () => './Home')会导致循环引用,改为正确的Mock方式:

    jest.mock('./Home', () => ({
      default: jest.fn(() => null)
    }));
    

    同时确保第三方依赖的Mock适配TS类型,比如react-native-paper的Provider在测试中初始化正确。

  5. 清理缓存后重新测试
    执行jest --clearCache清除Jest缓存,避免旧转译代码干扰,再重新运行测试。

内容的提问来源于stack exchange,提问作者Brian Serrano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 13:35:20