使用Jest与MSW测试RTK Query Hook时请求拦截失败问题
测试RTK Query的useGetTaxSystemQuery Hook时,MSW无法正确拦截请求,组件未渲染预期复选框,反而显示错误文本“Ошибка”,测试报错Unable to find an element by: [data-testid="test1"]。单独用fetch请求${process.env.API_URL}/dict/taxSystem能拿到模拟数据,但RTK Query Hook无法获取数据,导致组件进入错误分支。
核心问题排查
1. RTK Query响应结构不匹配
RTK Query的getTaxSystem配置中,transformResponse期望接收IFullResponse<ITaxSystem[]>类型的响应(即包含response字段的对象),但当前MSW直接返回了数组mockTaxSystem,导致transformResponse处理后返回undefined,最终taxSystemData为undefined,组件触发错误分支。
2. 请求路径匹配问题
RTK Query的API实例(app/api)可能配置了baseURL,如果实际请求路径是${baseURL}/dict/taxSystem,而MSW的handler仅匹配/dict/taxSystem,会导致请求未被拦截,返回真实接口的错误响应。
解决方案
修复MSW响应结构
修改dictionariesHandlers,返回符合IFullResponse结构的数据:
// handlers.ts export const dictionariesHandlers = [ rest.get(`/dict/taxSystem`, (_, res, ctx) => res(ctx.status(200), ctx.json({ response: mockTaxSystem })) ), ];
确保请求路径匹配
- 检查
app/api中的baseURL配置,若测试环境baseURL不为/,则修改MSW handler的路径为完整匹配:// 假设process.env.API_URL在测试环境为'/api' rest.get(`${process.env.API_URL}/dict/taxSystem`, (_, res, ctx) => res(ctx.status(200), ctx.json({ response: mockTaxSystem })) ), - 或在测试环境配置
baseURL为/,确保请求路径与MSW handler匹配。
优化测试用例
使用异步查询方法findByTestId替代getByTestId,避免同步查询导致的错误:
it('should display taxation system', async () => { const { findByTestId, queryByText } = renderTestApp(<TestComponent />); expect(queryByText(/loading.../i)).toBeInTheDocument(); // 异步等待元素出现 const test1Checkbox = await findByTestId('test1'); expect(test1Checkbox).toBeInTheDocument(); expect(queryByText(/loading.../i)).not.toBeInTheDocument(); });
可选:完善组件错误状态处理
组件当前仅判断taxSystemData?.length,可添加isError状态判断,更清晰区分加载、成功、错误状态:
const TestComponent = () => { const { data: taxSystemData, isLoading, isError } = useGetTaxSystemQuery(); if (isLoading) { return <div>Loading...</div>; } if (isError) { return <div data-testid="error">Ошибка</div>; } return ( <div data-testid="TaxationSystems"> {taxSystemData?.length ? ( <div> {taxSystemData.map((item) => ( <FormCheckbox data-testid={item.value} key={item.id} label={item.name} name={item.value} /> ))} </div> ) : ( <div data-testid="empty">Нет данных</div> )} </div> ); };
内容的提问来源于stack exchange,提问作者IT Punisher

