Search code examples
reactjsnext.jsjestjsreact-query

how can i write unit test for react query and Next.js route handler


I fetch Hard-code data from the Next.js route handler with react query but my custom hook returns undefined.

my custom hook works fine in my component but in the test file returns undefined.

//route.ts

 export async function GET() {
  const data = [
    {
      title: "product one",
      price: 1200,
    },
    {
      title: "product two",
      price: 1200,
    }
 ];
 return Response.json(data);
}


//page.test.ts

test("isSuccess",  async () => {
  const { result } = renderHook(() => useGetListingDataHook(), {
    wrapper: ReactQueryProvider,
  });
  await waitFor(() => expect(result.current.isSuccess).toBe(true));
 });

Solution

  • Issue: useGetListingDataHook returns undefined in my test, but works fine in the component.

    Problem:

    It seems that your custom React Query hook works correctly in the component but returns undefined in the test. This issue typically happens because the API request made by your hook is not mocked properly in the test environment, and the test is running in isolation without access to the actual API routes.

    Solution:

    To fix this, you can mock the API response in your test. I recommend using msw (Mock Service Worker) for handling API mocking in tests. It works well with React Query and makes it easy to mock HTTP requests

    Steps:

    1. Install msw if you haven't already:

      npm install msw --save-dev
      
    2. Set up the mock API response in your test file:

    Here’s an example of how you can mock your GET request and fix your test using msw:

    // page.test.ts
    import { renderHook } from '@testing-library/react-hooks';
    import { waitFor } from '@testing-library/react';
    import { useGetListingDataHook } from 'path-to-your-hook';  // Adjust the import path
    import { setupServer } from 'msw/node';
    import { rest } from 'msw';
    import ReactQueryProvider from 'path-to-your-provider';  // Import your react-query provider
    
    // Mock the API response
    const server = setupServer(
      rest.get('/api/your-route', (req, res, ctx) => {
        return res(
          ctx.json([
            { title: 'product one', price: 1200 },
            { title: 'product two', price: 1200 },
          ])
        );
      })
    );
    
    // Start the server before all tests and stop it after all tests
    beforeAll(() => server.listen());
    afterEach(() => server.resetHandlers());
    afterAll(() => server.close());
    
    test('isSuccess', async () => {
      const { result } = renderHook(() => useGetListingDataHook(), {
        wrapper: ReactQueryProvider,  // You need to wrap with your react-query provider
      });
    
      await waitFor(() => expect(result.current.isSuccess).toBe(true));
    });
    

    Explanation:

    • Mocking API Requests: You use msw to mock your API. The setupServer function creates a mock server, and rest.get simulates the GET request your hook makes to the /api/your-route endpoint.

    • Test Lifecycle Management: The server is started with beforeAll and stopped after all tests with afterAll. resetHandlers ensures the mock server resets between tests, preventing stale data.

    This setup should allow your custom hook to return the expected data during tests.