Trying to run testcase on custom fetch hooks but not working

24 Views Asked by At

Hi I have a custom hook component which perform fetch operation here is my custom hook code

import { useState } from 'react';

export interface IFetchHook {
    path: string;
    options?: Record<string, any>;
    resHandler?: (param: any) => void;
    errorHandler?: (obj: Record<string, any>) => void;
}

const getOptions = (params: any) => {
    const defaults = {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        }
    };
    const newObj = {
        ...defaults,
        ...params
    };
    // header is object, all other fields are plain values, recursive merge
    if (params?.headers) {
        newObj.headers = { ...defaults.headers, ...params.headers };
    }
    return newObj;
}; 

const useFetchHook = ({ path = '', options = {}, resHandler, errorHandler }: IFetchHook) => {
    const [apiState, setApiState] = useState({ loading: false, data: null, error: null });
    const fetchOptions = getOptions(options);
    const fireAPI = async () => {
        if (typeof fetch == 'undefined') { throw new Error('fetch not defined'); }
        try {
            setApiState({ loading: true, data: null, error: null });
            const res = await fetch(path, fetchOptions);
            if (resHandler) {
                resHandler(res); setApiState({ loading: false, data: null, error: null });
            } else {
                const parsedRes = await res.json();
                setApiState({ loading: false, data: parsedRes, error: null });
            }
        } catch (error: any) {
            setApiState({
                loading: false, data: null, error
            }); if (errorHandler) {
                errorHandler({ path, fetchOptions, error });
            }
        }
    }
    return [fireAPI, apiState];
}
export default useFetchHook;

Below is my test case


// Import the required modules
import { act, renderHook } from '@testing-library/react-hooks';
import useFetchHook from ' ./index';

// Mock the fetch function
global.fetch = jest.fn();
// Define some test data
const mockTodo = {
    id: 1,
    title: 'Test todo',
    completed: false
};
const mockPath = 'https://jsonplaceholder.typicode.com/todos/1';
const mockOptions = {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json'
    }
};
// Define a helper function to wait for next tick
const waitForNextTick = () => new Promise((resolve) => setTimeout(resolve));
// Define a mock response handler function
const mockResHandler = jest.fn();
// Define a mock error handler function
const mockErrorHandler = jest.fn();

describe('useFetchHook', () => {
    let originalFetch: any;
    beforeEach(() => {
        originalFetch = global.fetch;
    });
    afterEach(() => {
        global.fetch = originalFetch;
    });
    beforeEach(() => {
        mockResHandler.mockClear();
        mockErrorHandler.mockClear();
    });
    // Test the successful fetch scenario
    it.only('should fetch data and update state accordingly', async () => {
        (fetch as jest.Mock).mockResolvedValueOnce({
            ok: true,
            json: async () => mockTodo
        });
        const { result } = renderHook(() => useFetchHook({ path: mockPath, options: mockOptions }));
        const [fireAPI, apiState] = result.current as [() => Promise<void>, { loading: boolean; data: null | unknown, error: null | unknown }];
        act(() => {
            fireAPI();
        });
        expect(apiState).toEqual({ loading: true, data: null, error: null });
        await waitForNextTick();
        expect(apiState).toEqual({ loading: false, data: mockTodo, error: null });
    })
})

when I run the testcase it's failing I am not sure what is wrong in my code or in my approach, The setAPIState is not getting update as a result it's failing.

I tried using await in act and waitFor.

0

There are 0 best solutions below