Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test custom async/await hook with react-hooks-testing-library

Tags:

I created a custom react hook that is supposed to handle all less important api requests, which i don't want to store in the redux state. Hook works fine but I have trouble testing it. My test setup is jest and enzyme, but I decided to give a try react-hooks-testing-library here as well.

What I have tried so far is to first mock fetch request with a fetch-mock library, what works fine. Next, i render hook with renderHook method, which comes from react-hooks-testing-library. Unfortunately, looks like I do not quite understand the waitForNextUpdate method.

This is how my hook looks like.

useApi hook

export function useApi<R, B = undefined>(
    path: string,
    body: B | undefined = undefined,
    method: HttpMethod = HttpMethod.GET
): ResponseStatus<R> {
    const [response, setResponse] = useState();
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [error, setError] = useState<string | boolean>(false);

    useEffect(() => {
        const fetchData = async (): Promise<void> => {
            setError(false);
            setIsLoading(true);
            try {
                const result = await callApi(method, path, body);
                setResponse(result);
            } catch (errorResponse) {
                setError(errorResponse);
            }

            setIsLoading(false);
        };

        fetchData();
    }, [path, body, method]);

    return { response, isLoading, error };
}

Hook can take 3 different state combinations that I would like to test. Unfortunately, I have no idea how.

Loading data:

{ response: undefined, isLoading: true, error: false }

Loaded data:

{ response: R, isLoading: false, error: false }

Error:

{ response: undefined, isLoading: false, error: true }

This is how my test looks like at this moment:

import fetchMock from 'fetch-mock';
import { useApi } from './hooks';
import { renderHook } from '@testing-library/react-hooks';

test('', async () => {
    fetchMock.mock('*', {
        returnedData: 'foo'
    });

    const { result, waitForNextUpdate } = renderHook(() => useApi('/data-owners'));

    console.log(result.current);

    await waitForNextUpdate();

    console.log(result.current);
});

callApi func

/**
 * Method to call api.
 *
 * @param {HttpMethod} method - Request type.
 * @param {string} path - Restful endpoint route.
 * @param {any} body - Request body data.
 */
export const callApi = async (method: HttpMethod, path: string, body: any = null) => {
    // Sends api request
    const response = await sendRequest(method, path, body);
    // Checks response and parse to the object
    const resJson = response ? await response.json() : '';

    if (resJson.error) {
        // If message contains error, it will throw new Error with code passed in status property (e.g. 401)
        throw new Error(resJson.status);
    } else {
        // Else returns response
        return resJson;
    }
};
like image 326
Dan Zawadzki Avatar asked Aug 14 '19 13:08

Dan Zawadzki


People also ask

How do you test custom Hooks with React testing library?

1st case: unit testing simple custom hooks First, we need to create a test using describe. Then, we render a hook to use it for testing. Common way of doing it is to use the renderHook method from the React Hooks Testing Library. The next step is to figure out which cases we need to check.

How do you write a test case for custom Hooks?

import { renderHook, act } from '@testing-library/react-hooks'; import useCounter from '../hooks/useCounter'; describe('useCounter', () => { test(`Default value of `count` will be zero`, () => { const { result } = renderHook(() => useCounter()); expect(result. current. count). toBe(0); }); });

How do you test a hook in React?

If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote. To reduce the boilerplate, we recommend using React Testing Library which is designed to encourage writing tests that use your components as the end users do.

Can we call Hooks from custom Hooks in React?

No. Custom Hooks are a mechanism to reuse stateful logic (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.


1 Answers

It's all right that you did. Now, you need use expect for test.

const value = {...}
expect(result.current).toEqual(value)
like image 99
Leandro Budau Avatar answered Sep 17 '22 17:09

Leandro Budau