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.