The below is a simple custom hook that fetches data from a GET request and returns it.
import { useState, useEffect } from "react";
export const useData = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
};
I am trying to test this custom hook but while testing the actual response I get is an array with a null element [null]
.
This is my test file.
import { renderHook, waitFor } from "@testing-library/react";
import { useData } from "./useData";
test("fetching the jsonarray", async () => {
const { result } = renderHook(() =>
useData("https://jsonplaceholder.typicode.com/todos?_limit=1")
);
let actualResponse;
await waitFor(() => {
actualResponse = result.current;
});
expect(actualResponse).toEqual([
{
userId: 1,
id: 1,
title: "delectus aut autem",
completed: false,
},
]);
});
I get the below. As you can see below, in my test case, the actual response is [null]
. How do I make the the test case wait until the async fetch call is completed?
Expected - 6
+ Received + 1
Array [
- Object {
- "completed": false,
- "id": 1,
- "title": "delectus aut autem",
- "userId": 1,
- },
+ null,
]
The waitFor
function works as expected. You should use result.current[0]
, not result.current
in the callback of the waitFor
function since you return the data as [data]
.
result.current
is an array []
, which is a truthy value, the waitFor
function will not retry to call the callback.
Returning a falsy condition is not sufficient to trigger a retry, the callback must throw an error in order to retry the condition
That's why we should use expect(result.current[0]).toBeTruthy()
, this assertion may throw an error to trigger a retry when result.current[0]
is null
.
The title
of the todo data may be random, that's why I use expect.any(String)
.
import { renderHook, waitFor } from '@testing-library/react';
import { useData } from './useData';
test('fetching the jsonarray', async () => {
const { result } = renderHook(() => useData('https://jsonplaceholder.typicode.com/todos?_limit=1'));
await waitFor(() => expect(result.current[0]).toBeTruthy());
expect(result.current[0]).toEqual(
expect.arrayContaining([
expect.objectContaining({
userId: 1,
id: 1,
title: expect.any(String),
completed: false,
}),
]),
);
});
Test result:
PASS stackoverflow/77863992/useData.test.ts
√ fetching the jsonarray (957 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.829 s, estimated 2 s
Ran all test suites related to changed files.
package versions:
"@testing-library/react": "^14.1.2",
"react": "^18.2.0",
"jest": "^29.7.0",
jest.setup.js
:
import 'whatwg-fetch';
jest.config.js
:
module.exports = {
testEnvironment: 'jsdom',
setupFiles: ['<rootDir>/jest.setup.js'],
};