MSW+React-Query+Vitest:前序测试请求在后续测试中失败
解决React Query + MSW测试中的跨测试请求竞态问题
问题核心是测试间状态隔离不足:第一个测试的异步请求在测试结束后未被彻底取消,当第二个测试启动时,这个残留请求仍尝试用旧UUID("fail")发起调用,此时MSW的handler已重置,导致请求失败并产生错误日志。以下是具体解决步骤:
1. 为每个测试创建独立的QueryClient
不要使用全局共享的queryClient,每个测试实例化新的QueryClient,彻底隔离缓存和请求状态:
修改wrappedDetails组件,支持传入自定义QueryClient:
function wrappedDetails(uuid: string, queryClient: QueryClient) { return ( <MemoryRouter initialEntries={["/things/" + uuid]}> <QueryClientProvider client={queryClient}> <GenericToastProvider> <Routes> <Route path="/things/:uuid" element={<ThingDetails />}></Route> </Routes> </GenericToastProvider> </QueryClientProvider> </MemoryRouter> ); }
2. 在测试生命周期中清理请求和缓存
在beforeEach初始化新的QueryClient,在afterEach主动取消所有未完成请求并清空缓存:
describe("Test the view", () => { let queryClient: QueryClient; beforeEach(() => { // 初始化独立的QueryClient,关闭测试环境下的重试避免干扰 queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); server.resetHandlers(); cleanup(); }); afterEach(async () => { // 取消所有未完成的异步请求 await queryClient.cancelQueries(); // 清空缓存,避免残留状态影响下一个测试 queryClient.clear(); }); // 测试用例... });
3. 调整MSW handler和组件渲染的顺序
确保先设置当前测试需要的MSW handler,再渲染组件,避免请求发出时handler未生效:
it("DEBUG Handles when rendered with a malformed uuid", async () => { const uuid = "fail"; consoleErrorSpy.mockImplementation(() => {}); // 先设置对应fail场景的handler server.use(...); // 再渲染组件 render(wrappedDetails(uuid, queryClient)); await waitFor( () => expect(screen.getByText("Encountered an error while fetching")).toBeInTheDocument(), { timeout: 10000 } ); }, 10000); it("DEBUG Displays the details that it is supposed to", async () => { const uuid = faker.datatype.uuid(); // 先设置正常场景的handler server.use(...); render(wrappedDetails(uuid, queryClient)); await waitFor(() => expect(screen.getAllByRole("heading", { level: 3 }).length).toBe(1)); });
原理说明
- 独立QueryClient确保每个测试的React Query状态完全隔离,不会共享缓存或未完成请求。
cancelQueries会主动终止所有未完成的请求,避免它们在测试结束后继续执行并干扰后续测试。- 调整handler顺序保证请求发出时使用的是当前测试的模拟规则,不会被之前测试的handler影响。
内容的提问来源于stack exchange,提问作者pooley1994
相关产品推荐
相关产品推荐

