使用Jest测试React Query组件时result返回null的原因排查
为什么测试中result返回null?
我希望测试组件在从查询获取数据后是否正常渲染,但测试时result返回null;用自定义Hook测试时也出现相同错误,推测是数据调用方式有问题。
相关代码
获取函数
const fetchWeather = async (lat: number, lon: number) => { const response = await fetch(`${OW_API_URL}forecast?lat=${lat}&lon=${lon}&${OWApiKey}`); const weather= await response.json(); return weather; };
组件代码
const { data } = useQuery( ['weather'], () => fetchWeather(latitude, longitude), ); return ( <div> {data ? (<p>Data recieved</p>) : (<p>Data's empty</p>)} </div> );
测试代码
const queryClient = new QueryClient(); const componentProps = { latitude: 50, longitude: 50, }; const wrapper = () => ( <QueryClientProvider client={queryClient}> <Weather latitude={componentProps.latitude} longitude={componentProps.latitude} /> </QueryClientProvider> ); const { result } = renderHook(() => fetchNextWeather(componentProps.latitude, componentProps.longitude), { wrapper }); await waitFor(() => result.current); expect(result).toBe(true);
报错信息
- true" + "Object { + "current": null, + }"
自定义Hook代码
function useCustomHook() { return useQuery({ queryKey: ['customHook'], queryFn: () => 'Hi' }); }
自定义Hook测试代码
const { result } = renderHook(() => useCustomHook(), { wrapper }); await waitFor(() => result.current);
问题原因分析
1. 误用renderHook调用普通异步函数
renderHook是用来测试自定义Hook的工具,不是用来执行普通异步函数的。你直接用它调用fetchWeather(测试里的fetchNextWeather是笔误),在测试环境(如Jest)中如果没有Mock真实的fetch请求,会导致请求失败,最终result.current返回null。
2. 测试断言逻辑完全错误
expect(result).toBe(true); 完全不符合逻辑:result是renderHook返回的对象,结构为{ current: ... },不可能等于true。你需要断言的是数据是否正确返回,比如Hook返回的data字段。
3. 自定义Hook的等待逻辑错误
对于useCustomHook的测试,await waitFor(() => result.current); 没有意义——useQuery会立即返回一个对象(result.current一开始就存在),只是对象里的data初始为undefined,直到请求完成。正确的等待应该是判断data是否存在或请求是否成功。
4. 测试代码中的笔误
测试的wrapper里,Weather组件的longitude传成了componentProps.latitude,虽然这不是当前null问题的直接原因,但会导致组件使用错误的经纬度请求数据。
修正后的测试示例
组件测试(正确方式)
用render渲染组件,同时MockfetchWeather避免真实网络请求:
import { render, screen, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import Weather from './Weather'; import { fetchWeather } from './path-to-fetch-function'; // Mock异步请求函数 jest.mock('./path-to-fetch-function', () => ({ fetchWeather: jest.fn().mockResolvedValue({ mockData: 'test' }), })); test('Weather组件获取数据后渲染正确内容', async () => { const queryClient = new QueryClient(); const props = { latitude: 50, longitude: 50 }; render( <QueryClientProvider client={queryClient}> <Weather {...props} /> </QueryClientProvider> ); // 等待数据加载完成,断言渲染的内容 await waitFor(() => { expect(screen.getByText('Data recieved')).toBeInTheDocument(); }); });
自定义Hook测试(正确方式)
import { renderHook, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import useCustomHook from './useCustomHook'; const queryClient = new QueryClient(); const wrapper = ({ children }) => ( <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> ); test('useCustomHook能正确返回数据', async () => { const { result } = renderHook(() => useCustomHook(), { wrapper }); await waitFor(() => { expect(result.current.data).toBe('Hi'); expect(result.current.isSuccess).toBe(true); }); });
内容的提问来源于stack exchange,提问作者strB
相关产品推荐
相关产品推荐

