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

使用RTK Query与MSW测试时出现FETCH_ERROR无效URL问题求助

RTK Query 结合 MSW 搭建测试环境请求报错排查

环境信息

名称版本
msw1.2.1
react18
redux toolkit1.9.3
vitest0.29.3
cross-fetch3.1.5
typescript5
NodeJS18(已尝试19.3)
OSWindows

Mock 服务器与请求处理器

import { rest } from 'msw';
import { setupServer } from 'msw/node';

export const handlers = [
  rest.get('http://localhost:5173/api/search/photos', (req, res, ctx) => {
    return res(ctx.status(200), ctx.json(resList));
  }),
  rest.get('http://localhost:5173/api/photos/ZJIwrGrQb2Y', (req, res, ctx) => {
    return res(ctx.status(200), ctx.json(resPhoto));
  }),
];

export const server = setupServer(...handlers);

在 setupTests.ts 中启动 Mock 服务器:

import { beforeAll, afterEach, afterAll } from 'vitest';
import { setupStore } from '../redux/store';
import { apiSlice } from '../redux/api';

const store = setupStore({});

beforeAll(() =>
  server.listen({
    onUnhandledRequest: 'error',
  })
);

afterEach(() => {
  server.resetHandlers();
  store.dispatch(apiSlice.util.resetApiState());
});

afterAll(() => server.close());

RTK Query 请求配置

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const apiSlice = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({
    baseUrl: BASE_URL,
    prepareHeaders(headers) {
      headers.set('Accept', 'application/json');
      headers.set('Accept-Version', 'v1');
      headers.set('Authorization', `Client-ID ${API_ACCESS_TOKEN}`);
      return headers;
    },
  }),
  endpoints: (builder) => {
    return {
      getPhotoList: builder.query<TransformedApiResponse, RequestParams>({
        query: (params: RequestParams) => {
          const { query } = params;
          return `/search/photos?query=${query}`;
        },
        transformResponse: (response: ApiResponse): TransformedApiResponse => ({
          total: response.total,
          totalPages: response.total_pages,
          cards: response.results.map((item: PhotoDTO): CardData => {
            return {
              id: item.id,
              imgSrc: item.urls.small,
              alt: item.alt_description,
              likes: item.likes,
            };
          }),
        }),
      }),
      getOnePhoto: builder.query<FullPhotoDTO, string>({
        query: (id: string) => {
          return `/photos/${id}`;
        },
      }),
    };
  },
});

export const { useGetPhotoListQuery, useGetOnePhotoQuery } = apiSlice;

Vite 配置

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import eslint from 'vite-plugin-eslint';

export default defineConfig({
  plugins: [react(), eslint()],
  test: {
    globals: true,
    environment: 'happy-dom',
    coverage: {
      provider: 'istanbul',
      all: true,
    },
    setupFiles: ['./src/test/setupTests.ts'],
  },
  server: {
    proxy: {
      '/api': {
        target: 'https://api.unsplash.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
});

测试代码

describe('App test', () => {
  test('Should render home page', async () => {
    renderWithProviders(
      <MemoryRouter initialEntries={['/']}>
        <App />
      </MemoryRouter>
    );

    expect(screen.getByText(/Home Page/i)).toBeDefined();

    expect(screen.getByRole('loader')).toBeDefined();

    await waitForElementToBeRemoved(() => screen.getByRole('loader'));

    expect(screen.getByText('1113')).toBeDefined();
  });
});

当前问题

主应用本地运行时请求正常,但测试中所有请求均报错:FETCH_ERROR "TypeError [ERR_INVALID_URL]: Invalid URL",页面显示网络错误,无法确认 MSW Mock 服务器是否正常运行。

已尝试的方案

  • 从 cross-fetch 导入 fetch 并挂载到全局
    import { fetch, Headers, Request, Response } from 'cross-fetch'
    
    global.fetch = fetch
    global.Headers = Headers
    global.Request = Request
    global.Response = Response
    
  • 尝试使用 whatwg-fetch、isomorphic-fetch 替代库
  • 移除 Vite 代理服务器配置
  • 将 server.listen() 移至单个测试文件
  • 在 Home 组件中添加日志获取错误详情
    const { query } = useAppSelector((state) => state.home);
    
    const { data, isFetching, error } = useGetPhotoListQuery({ query: query });
    console.table({ data, isFetching, error });
    

内容的提问来源于stack exchange,提问作者naXa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:02:46