import { type RenderHookResult, renderHook, waitFor } from '@testing-library/react'; import fetchMock from 'jest-fetch-mock'; import TestQueryProvider from '../TestQueryProvider'; import useFetchQuery, { type UseFetchQueryProps, type UseFetchQueryState } from '.'; const mockedShowErrorMessage = jest.fn(); interface User { email: string; name: string; } const user: User = { email: 'john@doe.com', name: 'John Doe' }; jest.mock('../../Snackbar/useSnackbar', () => ({ __esModule: true, default: jest .fn() .mockImplementation(() => ({ showErrorMessage: mockedShowErrorMessage })) })); const renderFetchQuery = ( params: UseFetchQueryProps ): RenderHookResult, unknown> => renderHook(() => useFetchQuery(params), { wrapper: TestQueryProvider }) as RenderHookResult, unknown>; const mockParams = { headers: { 'Content-Type': 'application/json' } }; describe('useFetchQuery', () => { beforeEach(() => { mockedShowErrorMessage.mockReset(); fetchMock.resetMocks(); }); it('does not show any message via the Snackbar when the error is a cancellation', async () => { fetchMock.mockAbortOnce(); renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'] }); await waitFor(() => { expect(mockedShowErrorMessage).not.toHaveBeenCalled(); }); }); it('retrieves data from an endpoint', async () => { fetchMock.once(JSON.stringify(user), mockParams); const { result } = renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'] }); await waitFor(() => { expect(result.current?.data).toEqual(user); }); }); it("shows an error from the API via the Snackbar and inside the browser's console", async () => { fetchMock.once(JSON.stringify({ code: 2, message: 'custom message' }), { ...mockParams, status: 400 }); const { result } = renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'] }); await waitFor(() => { expect(mockedShowErrorMessage).toHaveBeenCalledWith('custom message'); }); await waitFor(() => { expect(result.current.error).toStrictEqual({ additionalInformation: { code: 2, message: 'custom message' }, message: 'custom message', statusCode: 400 }); }); }); it("shows an error from the API via the Snackbar and inside the browser's console when the API does not respond", async () => { fetchMock.mockReject(new TypeError('error')); renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'] }); await waitFor(() => { expect(mockedShowErrorMessage).toHaveBeenCalledWith('error'); }); }); it('shows a default failure message via the Snackbar as fallback', async () => { fetchMock.once(JSON.stringify({}), { ...mockParams, status: 400 }); const { result } = renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'] }); await waitFor(() => { expect(mockedShowErrorMessage).toHaveBeenCalledWith( 'Something went wrong' ); }); await waitFor(() => { expect(result.current.error).toStrictEqual({ additionalInformation: {}, message: 'Something went wrong', statusCode: 400 }); }); }); it('does not show any message via the Snackbar when the httpCodesBypassErrorSnackbar is passed', async () => { fetchMock.once(JSON.stringify({}), { ...mockParams, status: 400 }); const { result } = renderFetchQuery({ getEndpoint: () => '/endpoint', getQueryKey: () => ['queryKey'], httpCodesBypassErrorSnackbar: [400] }); await waitFor(() => { expect(mockedShowErrorMessage).not.toHaveBeenCalled(); }); await waitFor(() => { expect(result.current.error).toStrictEqual({ additionalInformation: {}, message: 'Something went wrong', statusCode: 400 }); }); }); });