Test custom react hooks for promise reject with testing library react hooks

Viewed 18

I have a custom react hook, just to make a GET request with axios, and the file named as: useAxiosGet.ts, and the code is:

import {useMemo, useState} from "react";
import axios, {AxiosResponse} from "axios";

interface ErrorBody {
    code: string,
    message: string
}

export interface ErrorResponse {
    status: number,
    errorBody?: ErrorBody
}

export const useAxiosGet = <TResponse>(
    requestUrl: string,
) => {
    const [data, setData] = useState<TResponse>();
    const [error, setError] = useState<ErrorResponse>();
    const [loading, setLoading] = useState(false);

    const getData = useMemo(() => {
        return () => {
            setLoading(true);
            setError(undefined);

            return axios.get(requestUrl)
                .then((response: AxiosResponse<TResponse>) => {
                    const responseData = response.data;
                    setData(responseData);//update the date
                    return responseData
                })
                .catch(err => {
                    const errorResponse = {status: err.response.status, errorBody: err.response.data}
                    setError(errorResponse); //update the error
                    return Promise.reject(errorResponse) //return a Promise.reject
                }).finally(() => {
                    setLoading(false)
                });
        };
    }, []);

    return {data, getData, setData, loading, error}
};

I made the resolved case test passed, but the reject case does not, and you can see that I am returning the Promise.reject(errorResponse) in the.catch(), and I think this is the key point for the failed test. And my test code looks like below:

import {act, renderHook} from '@testing-library/react-hooks'
import axios from 'axios';
import MockAdapter from "axios-mock-adapter";
import {useAxiosGet} from "./useAxiosGet";

interface TProfile {
    name: string
}

describe('useAxiosGet', () => {
    let mockAxios: MockAdapter;
    beforeAll(() => {
        mockAxios = new MockAdapter(axios);
    })
    afterEach(() => {
        mockAxios.reset()
    })
    afterAll(() => {
        mockAxios.restore()
    })

    //This test passed
    test('should get data for success request', async () => {
        mockAxios.onGet("/id/1").reply(200, {name: 'nana'})
        const {result, waitForNextUpdate} = renderHook(() => useAxiosGet<TProfile>('/id/1',))
        act(() => {
            result.current.getData()
        })
        await waitForNextUpdate()
        expect(result.current.data).toStrictEqual({name: 'nana'})
        expect(result.current.loading).toBeFalsy()
        expect(result.current.error).toBe(undefined)
    });

    //This test not passed
    test('should get error for failed request', async () => {
        const errorBody = {
            'code': 'NOT_FOUND',
            'message': 'id 1 not found',
        };
        //Mock the request with a failed HTTP response
        mockAxios.onGet("/id/1").reply(404, errorBody)

        const {result, waitForValueToChange} = renderHook(() => useAxiosGet<TProfile>('/id/1',))
        await waitForValueToChange(() => result.current.getData());

        let errorResponse = {
            status: 404,
            errorBody: errorBody
        };
        expect(result.current.data).toStrictEqual(undefined);
        expect(result.current.error).toStrictEqual(errorResponse);

    })

})

I would like to test after the API called, the result.current.error should be the errorResponse expected, but I always get undefined : test failed screenshot

I know there are something wrong with the test code, but I do not know the correct way to test the reject case, any one know how to do it?

0 Answers
Related