测试使用RTK Query API的React组件时遇绝对URL错误
解决RTK Query测试中相对URL报错问题
问题背景
测试使用RTK Query的React组件时,API配置了相对路径的baseQuery:
export const listApi = createApi({ baseQuery: graphqlRequestBaseQuery({ url: 'graphql', }), reducerPath: 'listApi', endpoints: (builder) => ({...}), });
测试中调用useLoadListDataQuery时出现错误:TypeError: Only absolute URLs are supported,即使配置了jest的testEnvironmentOptions.url也无效,需要在不修改原API代码的前提下解决。
可行解决方案
方案1:拦截并重写全局fetch(最通用)
在测试的前置钩子中重写global.fetch,自动将相对路径补全为绝对URL:
describe("List", () => { beforeAll(() => { // 保存原始fetch方法 const originalFetch = global.fetch; // 重写fetch,自动拼接绝对URL global.fetch = async (url, options) => { if (typeof url === 'string' && !url.startsWith('http')) { url = new URL(url, 'http://someAdress.test').href; } return originalFetch(url, options); }; server.listen(); }); afterEach(() => { server.resetHandlers(); }); afterAll(() => { // 恢复原始fetch global.fetch = jest.requireActual('node-fetch'); server.close(); }); it('should render successfully', () => { const { baseElement } = render(<ApiProvider api={listApi}><SomeComponent/></ApiProvider>); // 可添加断言逻辑 }); });
方案2:Mock graphqlRequestBaseQuery(针对性强)
通过jest.mock拦截graphqlRequestBaseQuery的导入,返回带绝对URL的配置:
// 先mock导入的graphqlRequestBaseQuery jest.mock('@reduxjs/toolkit/query/graphql', () => { const originalModule = jest.requireActual('@reduxjs/toolkit/query/graphql'); return { ...originalModule, graphqlRequestBaseQuery: (options) => { // 拼接绝对URL,避免重复斜杠 const absoluteUrl = `http://someAdress.test/${options.url}`.replace(/\/+/g, '/'); return originalModule.graphqlRequestBaseQuery({ ...options, url: absoluteUrl, }); }, }; }); describe("List", () => { beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); it('should render successfully', () => { const { baseElement } = render(<ApiProvider api={listApi}><SomeComponent/></ApiProvider>); }); });
方案3:动态修改RTK Query的baseQuery
利用RTK Query的工具方法,在测试中动态更新baseQuery的URL配置:
import { listApi } from '../path/to/your/listApi'; describe("List", () => { beforeAll(() => { // 更新baseQuery,添加绝对URL前缀 listApi.util.updateBaseQuery((originalBaseQuery) => async (args, api, extraOptions) => { // 处理不同的请求参数格式 if (typeof args === 'string') { args = new URL(args, 'http://someAdress.test').href; } else if (args?.url) { args.url = new URL(args.url, 'http://someAdress.test').href; } return originalBaseQuery(args, api, extraOptions); }); server.listen(); }); afterEach(() => { server.resetHandlers(); }); afterAll(() => server.close()); it('should render successfully', () => { const { baseElement } = render(<ApiProvider api={listApi}><SomeComponent/></ApiProvider>); }); });
说明
jest的testEnvironmentOptions.url未生效的原因是:RTK Query的graphqlRequestBaseQuery并未依赖window.location拼接URL,而是直接将配置的相对路径传给fetch,导致Node.js环境下的fetch(或msw拦截逻辑)要求绝对URL。上述方案均无需修改原API代码,仅在测试环境中注入绝对URL逻辑。
内容的提问来源于stack exchange,提问作者Łukasz Plaskacz
相关产品推荐
相关产品推荐

