You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:03:36