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

如何用Jest和React Testing Library Mock @react-navigation/native并修复测试问题

React Native Header组件测试中Navigation Mock不生效问题解决

问题描述

开发的React Native Header组件,触发返回按钮的onPress事件时仅打印onPressCalled,未进入if (navigation.canGoBack())分支,测试中的navigation mock未生效,导致断言goBack被调用失败。

组件代码

import {
    ArrowIcon,
    HeaderComponent,
    IconWrapper,
    PageTitle,
    PlaceholderView,
} from './Header.style';
import { Poppins_500Medium, useFonts } from '@expo-google-fonts/poppins';
import { useNavigation } from '@react-navigation/native';

const Header = () => {
    const navigation = useNavigation();
    const [loaded, error] = useFonts({
        Poppins_500Medium,
    });

    if (error || !loaded) {
        return <></>;
    }

    return (
        <HeaderComponent>
            <IconWrapper
                testID="IconWrapper"
                onPress={() => {
                    console.log('onPressCalled');
                    if (navigation.canGoBack()) {
                        console.log('usao1');
                        navigation.goBack();
                    }
                }}
            >
                <ArrowIcon
                    name='left'
                    color='#fff'
                    size={24}
                />
            </IconWrapper>
            <PageTitle>Create account</PageTitle>
            <PlaceholderView />
        </HeaderComponent>
    );
};

export default Header;

测试代码(修正版)

import { fireEvent, render, waitFor } from '../../../test-utils';

describe('Header', () => {
    it.only('should navigate to previous screen when back button is clicked', async () => {
        // 重置模块缓存,确保每次测试加载最新的mock
        jest.resetModules();
        
        const navigation = {
            canGoBack: jest.fn().mockReturnValue(true),
            goBack: jest.fn(),
        };

        // 先mock依赖,再动态导入组件
        jest.doMock('@react-navigation/native', () => ({
            useNavigation: jest.fn().mockReturnValue(navigation),
        }));
        jest.doMock('@expo-google-fonts/poppins', () => ({
            Poppins_500Medium: 'Poppins_500Medium',
            useFonts: jest.fn().mockReturnValue([true, null]),
        }));

        // 动态导入Header组件,确保使用mock后的依赖
        const Header = (await import('./Header.component')).default;

        const { findByTestId } = render(<Header />);

        const iconWrapper = await findByTestId('IconWrapper');
        fireEvent.press(iconWrapper);

        await waitFor(() => {
            expect(navigation.canGoBack).toHaveBeenCalled();
            expect(navigation.goBack).toHaveBeenCalled();
        });
    });
})

核心解决思路

  1. 调整Mock执行顺序
    原测试中jest.doMock在组件导入后执行,此时组件已加载真实的useNavigation依赖,mock无法生效。通过jest.resetModules()重置模块缓存,配合动态导入组件,确保组件加载时使用的是mock后的依赖。

  2. 确保元素可被测试定位
    给IconWrapper添加testID="IconWrapper"属性,保证findByTestId能正确找到交互元素。

  3. 可选方案:使用jest.mock自动提升
    也可以用jest.mock替代jest.doMock,该方法会被自动提升到文件顶部,确保组件导入前就完成mock:

    import { fireEvent, render, waitFor } from '../../../test-utils';
    import { useNavigation } from '@react-navigation/native';
    
    jest.mock('@react-navigation/native', () => ({
        useNavigation: jest.fn(),
    }));
    jest.mock('@expo-google-fonts/poppins', () => ({
        Poppins_500Medium: 'Poppins_500Medium',
        useFonts: jest.fn().mockReturnValue([true, null]),
    }));
    
    import Header from './Header.component';
    
    describe('Header', () => {
        it.only('should navigate to previous screen when back button is clicked', async () => {
            const navigation = {
                canGoBack: jest.fn().mockReturnValue(true),
                goBack: jest.fn(),
            };
            useNavigation.mockReturnValue(navigation);
    
            const { findByTestId } = render(<Header />);
            const iconWrapper = await findByTestId('IconWrapper');
            fireEvent.press(iconWrapper);
    
            await waitFor(() => {
                expect(navigation.canGoBack).toHaveBeenCalled();
                expect(navigation.goBack).toHaveBeenCalled();
            });
        });
    })
    

内容的提问来源于stack exchange,提问作者Andrija Gajic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:19:54