使用RTK Query与MSW测试时出现FETCH_ERROR无效URL问题求助
RTK Query 结合 MSW 搭建测试环境请求报错排查
环境信息
| 名称 | 版本 |
|---|---|
| msw | 1.2.1 |
| react | 18 |
| redux toolkit | 1.9.3 |
| vitest | 0.29.3 |
| cross-fetch | 3.1.5 |
| typescript | 5 |
| NodeJS | 18(已尝试19.3) |
| OS | Windows |
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
相关产品推荐
相关产品推荐

