I'm trying to test a component in React that uses RTK Query + MSW + Vitest. It works fine on the browser but while testing RTK Query with vitest it throws this error:
{ status: 'FETCH_ERROR', error: 'TypeError: fetch failed' }
I've setup a public repo with the configuration i'm using to replicate the error.
Another error RTK Query throws only while testing is:
TypeError: Failed to parse URL from /api/test?page=1&limit=10
This happens when i setup the fetchBaseQuery - baseUrl as empty or as a relative URL. I have to specify 'http://localhost...' or it wont work. But, it works in the browser.
Followed some articles on the matter with no success Searched Stackoverflow and found Searched RTK query repo issues and found a similar issue but with jest instead of vitest I've tried clearing query cache between tests - no success.
App.jsx
import { useTestQuery } from "./services/test";
export const App = () => {
const { data } = useTestQuery({ page: 1, limit: 10 });
console.log(data);
return (
<>
<h1>{data ? data.data.map((i) => i) : "loading"}</h1>
</>
);
};
redux/index.js
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { testApi } from "../services/test";
const store = configureStore({
reducer: {
[testApi.reducerPath]: testApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat([testApi.middleware]),
});
setupListeners(store.dispatch);
export default store;
services/apiSetup.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
export const emptyApi = createApi({
baseQuery: fetchBaseQuery({
baseUrl:"http://localhost:3000"
}),
tagTypes: ["test"],
endpoints: () => ({}),
});
services/test.js
import { emptyApi } from "./apiSetup";
export const testApi = emptyApi.injectEndpoints({
endpoints: (build) => ({
test: build.query({
query: ({ page = 1, limit = 10 }) => {
return { url: `test?page=${page}&limit=${limit}` };
},
providesTags: ["test"],
transformErrorResponse: (result) => console.log(result),
}),
}),
overrideExisting: false,
});
export const { useTestQuery,usePrefetch } =
testApi;
mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
mocks/handler.js
import { test } from "./handlers/test";
export const handlers = [...test];
mocks/handlers/test.js
import { rest } from "msw";
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
export const test = [
rest.get("http://localhost:3000/test", (req, res, ctx) => {
console.log(req)
return res(
ctx.delay(randomIntFromInterval(100, 1000)),
ctx.status(200),
ctx.json({ data: [1, 2, 3, 4, 5], total: 5 })
);
}),
];
testSetup.js
import { expect, afterEach, vi } from "vitest";
import { server } from "../mocks/server";
import { cleanup } from "@testing-library/react";
import matchers from "@testing-library/jest-dom";
// extends Vitest's expect method with methods from react-testing-library
expect.extend(matchers);
beforeAll(() => server.listen({ onUnhandledRequest: "bypass", cors: true }));
afterEach(() => {
server.resetHandlers();
cleanup();
});
afterAll(() => server.close());
App.test.jsx
import React from "react";
import { describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import store from "../../redux";
import App from "./";
const wrapper = (children) => {
return <Provider store={store}>{children}</Provider>;
};
function setup(jsx) {
return {
...render(wrapper(jsx)),
};
}
describe("App test", () => {
test("Should test", async () => {
setup(<App />);
await screen.findByText(/12345/);
screen.debug(undefined, 50000);
});
});