0

I have the following test file:

import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactPressProvider } from './ReactPressProvider';
import usePost from './usePost';
import { server } from './test/server'; // Update the path if necessary

const queryClient = new QueryClient();

const wrapper = ({ children }) => (
    <QueryClientProvider client={queryClient}>
        <ReactPressProvider
            apiConfig={{ apiUrl: 'https://your-wordpress-site.com' }}
        >
            {children}
        </ReactPressProvider>
    </QueryClientProvider>
);

describe('usePost', () => {
    beforeAll(() => {
        server.listen();
    });

    afterEach(() => {
        queryClient.clear();
        server.resetHandlers();
    });

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

    it('should fetch a post by ID', async () => {
        const postId = 1;

        const { result } = renderHook(() => usePost(postId), {
            wrapper,
        });

        await waitFor(() => {
            console.log(result.current);
            return expect(result.current.isSuccess).toBeTruthy();
        });

        expect(result.current.data).toHaveProperty('id', postId);
    });

    it('should handle fetch errors', async () => {
        const postId = 'nonexistent-post';

        const { result } = renderHook(() => usePost(postId), {
            wrapper,
        });

        await waitFor(() => {
            console.log(result.current);
            expect(result.current.isLoading).toBeFalsy(); // <--- FAILS!
            expect(result.current.isError).toBeTruthy();
        });

        expect(result.current.error).toBeInstanceOf(Error);
    });
});

and while the first test works, the second one does not.

This is my handler:

import { rest } from 'msw';

const apiUrl = 'https://your-wordpress-site.com/wp-json/wp/v2';

const handlers = [
    rest.get(`${apiUrl}/posts/:id`, (req, res, ctx) => {
        const { id } = req.params;
        if (id === '1')
            return res(
                ctx.status(200),
                ctx.json({ id: 1, title: 'Test Post' })
            );

        return res(ctx.status(404), ctx.json({ message: 'Post not found' }));
    }),
];

export { handlers };

If the return code is a 404, it gets stuck indefinitely in "isLoading".

Why could this be happening?

ivanatias
  • 3,105
  • 2
  • 14
  • 25
Enrique Moreno Tent
  • 24,127
  • 34
  • 104
  • 189
  • I assume `usePost` is using react-query's `useQuery` under the hood. By default, react-query will retry the query 3 times. `waitFor`'s default timeout is 1 second, so I think it's reaching the timeout before all the 3 retries are done, that's why `isLoading` is never changing to `false`. Disable the retries on the `QueryClient`'s default options. – ivanatias Mar 22 '23 at 00:37
  • did you ever figure this out? if so, what was the issue that solved it for you? – asus Jul 26 '23 at 22:26

1 Answers1

0

When a request fails, React Query's default behavior is to throw the error and retry the request, up to a certain number of times by default. Your query is stuck in an isLoading state until all of those retires have passed and they may take some time. Seeing you are creating a new queryClient for your test you are not disabling those retires. What you need to do is:

const queryCache = new QueryCache({
    defaultOptions: {
        queries: {
            retry: false
        },
    },
})
Loretta
  • 1,781
  • 9
  • 17