A project uses react-router v6 and in some components I call useLoaderData()
. For instance:
const routes = [
{ path: "widgets",
loader: () => fetchAndGetJSON("/api/widgets"),
element: <ListWidgets/> }
];
function ListWidgets() {
const widgets = useLoaderData();
return <>
<p>Here is a list of {widgets.length} widgets:
<...>
</>;
}
When testing I do not want to execute the fetch
, I want to supply the list of widgets in the test.
How can I create a unit test for ListWidgets
that uses data that I supply in the test?
CodePudding user response:
I haven't used React Router's data APIs myself, but as I understand it, there are three main alternatives.
- Use Jest's standard mocking functionality to mock
fetch
, mockfetchAndGetJSON
, or similar.global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve(FAKE_TEST_DATA), }) ); beforeEach(() => fetch.mockClear());
- Use
createMemoryRouter
with a testing version of your route that renders<ListWidgets/>
with a customloader
that returns the test data that you want.test(ListWidgets, async () => { const routes = [{ path: "widgets", element: <ListWidgets />, loader: () => FAKE_TEST_DATA, }]; const router = createMemoryRouter(routes, { initialEntries: ["widgets"] }); render(<RouterProvider router={router} />); // ...testing... }
- Use Mock Service Worker (msw.js) to create a mock back-end. Functionally, this is pretty similar to mocking
fetch
yourself, but MSW is very good at streamlining and consolidating things.const worker = setupWorker( rest.get('/api/widgets', async (req, res, ctx) => { const { username } = await req.json(); return res(ctx.json(FAKE_TEST_DATA)) }), ); worker.start();
I'm a big fan of msw.js, but any of the options should work. (It's something of a trade-off: overriding loader
results in more narrowly target unit tests, while msw.js lets you write less invasive tests closer to the integration testing end of the spectrum.)