React Testing Library测试React Query时Promise未解决导致超时问题
React 18 + React Query 3.3 测试超时问题修复与调试方案
一、先从核心配置排查
1. 核对React Query测试实例配置
React Query 3.x在测试环境下的Suspense模式必须明确配置,别漏了这几点:
- 测试用的
QueryClient一定要把defaultOptions.queries.suspense设为true,同时关掉重试(retry: false),不然重试机制会让请求一直pending - 示例配置:
const queryClient = new QueryClient({ defaultOptions: { queries: { suspense: true, retry: false, }, }, });
2. 确认请求模拟完全匹配
不管用msw还是其他mock工具,务必保证:
- 请求的URL、HTTP方法、查询参数和组件里
useQuery调用的完全一致,差一个字符都会导致请求挂起 - mock的响应不能抛错,返回的格式要和组件预期的结构匹配
- 举个msw的正确示例:
rest.get('/api/user/list', (req, res, ctx) => { return res(ctx.json([{ id: 1, name: 'test' }])); });
3. 检查RTL的渲染逻辑
- 每个测试用例都要新建独立的
QueryClient实例,别复用,避免缓存污染 - 组件必须同时被
QueryClientProvider和Suspense包裹,渲染顺序别搞反 - 别在渲染前就调用
waitFor,先渲染组件,再等目标内容出现:
render( <QueryClientProvider client={queryClient}> <Suspense fallback={<div>Loading...</div>}> <YourTargetComponent /> </Suspense> </QueryClientProvider> ); await waitFor(() => screen.getByText('加载完成后的内容'));
二、深度调试技巧
1. 打印QueryClient的查询状态
在测试里加日志,直接看查询的缓存和状态:
console.log('data1缓存:', queryClient.getQueryData('data1-key')); console.log('data1状态:', queryClient.getQueryState('data1-key')); // 能看到是pending/error还是success
2. 给useQuery加回调跟踪
在组件的useQuery里加onSuccess和onError,确认请求到底有没有触发:
const { data } = useQuery('data1-key', fetchData1, { onSuccess: () => console.log('data1请求成功了'), onError: (err) => console.log('data1请求炸了:', err), });
3. 临时禁用缓存排查问题
测试里把缓存时间和过期时间都设为0,强制触发请求,排除缓存导致的异常:
const queryClient = new QueryClient({ defaultOptions: { queries: { suspense: true, retry: false, cacheTime: 0, staleTime: 0, }, }, });
4. 核对库版本兼容性
React 18的Suspense对测试库要求较高,确认RTL 14.0.0完全适配React 18的并发特性,另外React Query 3.3版本有点老,建议升级到3.x的最新稳定版,说不定是旧版的兼容bug
三、容易踩的坑
- 请求Key不匹配:组件里
useQuery的key是['user', 123],测试模拟时用了'user'当key,导致查询匹配失败,一直pending - 漏加Suspense包裹:虽然
QueryClient开了suspense: true,但组件没被Suspense包起来,测试时直接报错或挂起 - Mock工具没正确启动:比如msw的
server.listen()没在测试前调用,或者server.resetHandlers()没清理旧mock,导致请求没被拦截
内容的提问来源于stack exchange,提问作者Pszemko
相关产品推荐
相关产品推荐

