单个组件中测试多个useQuery仅触发一个查询的问题排查
问题:React Query多查询在测试中仅触发最后一个的解决方案
问题描述
我使用React Query结合json-server模拟API,测试包含9个普通待办和1个固定待办的首页。通过msw模拟两个接口请求,期望验证首页渲染10个待办,但测试时仅最后监听的查询被触发。单独测试单个查询正常,React Query与React Testing Library配置无问题,需解决如何确保渲染组件前两个查询都被调用的问题。
组件代码
export const HomeToDosList = () => { const { data: todos, isLoading: isLoadingToDos } = useTodos(page); const { data: pinedToDos, isLoading: isLoadingPined } = usePinedTodos(); if (isLoadingToDos) { return <div>loading ...</div>; } if (isLoadingPined) { return <div>loading ...</div>; } return ( <div> {/* 注意:此处变量名存在错误 */} <ToDoItem initiative={pinedToDo.result} /> {todos.result.map((todo: ToDo) => ( <Fragment key={todo.id}> <ToDoItem todo={todo} /> </Fragment> ))} </div> ); };
测试代码
beforeAll(() => { getAllToDos.listen(); getPinedToDos.listen(); }); afterEach(() => { getPinedToDos.resetHandlers(); getAllToDos.resetHandlers(); }); afterAll(() => { getPinedToDos.close(); getAllToDos.close(); }); describe('Home TODOS', () => { test('should render 10 todos', async () => { render(<HomeToDosList />); const todos = await screen.findAllByTestId('todo-card'); expect(todos.length).toBe(10); }); });
解决方案
1. 修正MSW的Handler注册方式
你当前的核心错误是每个MSW Handler单独调用listen(),这会导致后执行的listen()覆盖之前的配置,最终只有最后一个Handler生效。正确做法是创建统一的Server实例,批量注册所有Handler后统一管理:
import { setupServer } from 'msw/node'; import getAllToDos from './path-to-getAllToDos'; import getPinedToDos from './path-to-getPinedToDos'; // 创建统一Server并注册所有Handler const server = setupServer(getAllToDos, getPinedToDos); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); describe('Home TODOS', () => { test('should render 10 todos', async () => { render(<HomeToDosList />); const todos = await screen.findAllByTestId('todo-card'); expect(todos.length).toBe(10); }); });
2. 修复组件变量错误
组件中误用了未定义的pinedToDo变量,正确命名应为pinedToDos(与usePinedTodos返回的data命名一致),否则固定待办无法渲染:
// 错误写法 <ToDoItem initiative={pinedToDo.result} /> // 正确写法 <ToDoItem initiative={pinedToDos.result} />
3. 优化加载状态判断逻辑
当前组件的加载判断是串行的:先判断普通待办加载状态,返回loading;再判断固定待办加载状态。这会导致如果普通待办先加载完成,组件会提前渲染固定待办的loading,可能干扰查询执行时机。建议合并加载状态判断,确保两个查询都完成后再渲染内容:
// 合并加载状态判断 if (isLoadingToDos || isLoadingPined) { return <div>loading ...</div>; }
补充说明
完成以上修改后,两个查询会同时发起,MSW能正确拦截所有请求,组件也会在两个请求都完成后渲染全部10个待办,测试即可通过。
内容的提问来源于stack exchange,提问作者Ozeus
相关产品推荐
相关产品推荐

