1

Im learning react testing and i have this hook i want to test but i have no idea how

import { useState, useCallback } from 'react';
import axios from 'axios';

export const useFetch = () => {
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  const fetchData = useCallback(async (url: string) => {
    setLoading(true);
    try {
      const response = await axios.get(url);
      const data = await response.data.data;
      setLoading(false);
      return data;
    } catch (error: any) {
      if (error.name !== 'AbortError') {
        setLoading(false);
        setError(error.message);
      }
    }
  }, []);

  return { error, loading, fetchData };


};

what i got so far but this is just me trying stuff cuzz there is no much help online that is good for my case

import { useFetch } from '../../hooks/useFetch';
import mockAxios from 'jest-mock-axios';
import axios from 'axios';
import { renderHook } from '@testing-library/react-hooks';

jest.mock('axios');

describe('useFetch', () => {
  afterEach(() => {
    mockAxios.reset();
  });
  it('fetches successfully data from an API', async () => {
    const { result,waitFor  } = renderHook(() => useFetch());
    let responseObj = { data: 'test response' };
    
    mockAxios.mockResponseFor({ url: '/get' }, responseObj);
    expect(result.current.error).toBe(null);
    await expect(result.current.fetchData('react')).resolves.toBe(responseObj);
  });
});

1 Answer 1

0

When you try to call setState mutate the state. We need to use act() function to

make sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.

Since your fetchData returns a promise, we need to use async act(...), you need React version at least v16.9.0-alpha.0. For more info about act() function, see react-act-example.

react-hook-testing-library re-export act() function from chosen renderer.

Besides, I just use jest.spyOn(axios, 'get').mockResolvedValueOnce() to mock axios.get() method without installing any extra package.

Note: I return response.data, not await response.data.data.

Now, the working unit test should be:

useFetch.ts:

import { useState, useCallback } from 'react';
import axios from 'axios';

export const useFetch = () => {
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  const fetchData = useCallback(async (url: string) => {
    setLoading(true);
    try {
      const response = await axios.get(url);
      const data = response.data;
      setLoading(false);
      return data;
    } catch (error: any) {
      if (error.name !== 'AbortError') {
        setLoading(false);
        setError(error.message);
      }
    }
  }, []);

  return { error, loading, fetchData };
};

useFetch.test.ts:

import { useFetch } from './useFetch';
import axios from 'axios';
import { renderHook, act } from '@testing-library/react-hooks';

describe('useFetch', () => {
  it('fetches successfully data from an API', async () => {
    const mockData = { data: 'test response' };
    const axiosGetSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: mockData })
    const { result } = renderHook(() => useFetch());

    expect(result.current.error).toBe(null);

    await act(async () => {
      await expect(result.current.fetchData('react')).resolves.toEqual(mockData);
    })

    axiosGetSpy.mockRestore();
  });
});

Test result:

 PASS  stackoverflow/74063562/useFetch.test.ts (17.219 s)
  useFetch
    ✓ fetches successfully data from an API (16 ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |   83.33 |        0 |     100 |   81.25 |                   
 useFetch.ts |   83.33 |        0 |     100 |   81.25 | 16-18             
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        21.31 s

package versions:

"@testing-library/react-hooks": "^8.0.1",
"jest": "^26.6.3",
"react": "^16.14.0",
"react-dom": "^16.14.0",
Sign up to request clarification or add additional context in comments.

3 Comments

this gives me the error " Cannot spy the get property because it is not a function; undefined given instead"
@ludinj Double check, make sure you don't have a __mocks__/axios and other things may affect the test
if i delete the __mocks__/axios.ts then i get this error " ENOENT: no such file or directory, open 'C:\Users\ludin\Desktop\Training Program\week-9-project\src__mocks__\axios.ts'" this is really hard to configure

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.