custom hook testing: when testing, code that causes React state updates should be wrapped into act(...):

2.8k Views Asked by At

Following this tutorial https://www.richardkotze.com/coding/mocking-react-hooks-unit-testing-jest, but getting this error even though the test passes, why is this error occurring and is there something missing from the test? code copied here for convenience

 PASS  src/use-the-fetch.spec.js
  ● Console

    console.error
      Warning: An update to TestComponent inside a test was not wrapped in act(...).
      
      When testing, code that causes React state updates should be wrapped into act(...):
      
      act(() => {
        /* fire events that update state */
      });
      /* assert on the output */
      
      This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
          at TestComponent (~/Documents/projects/my-app/node_modules/@testing-library/react-hooks/lib/helpers/createTestHarness.js:22:5)
          at Suspense
          at ErrorBoundary (~/Documents/projects/my-app/node_modules/react-error-boundary/dist/react-error-boundary.cjs.js:59:35)

       5 |   async function fetchData() {
       6 |     const data = await getStarWars(path); // being mocked
    >  7 |     setResult({ loading: false, data });
         |     ^
       8 |   }
       9 |   useEffect(() => {
      10 |     fetchData();

      at console.error (node_modules/@testing-library/react-hooks/lib/core/console.js:19:7)
      at printWarning (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:68:30)
      at error (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:44:5)
      at warnIfNotCurrentlyActingUpdatesInDEV (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15034:9)
      at setResult (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7129:9)
      at fetchData (src/use-the-fetch.js:7:5)

use-the-fetch.spec.js

import { renderHook } from "@testing-library/react-hooks";
import { useTheFetch } from "./use-the-fetch";
import { getStarWars } from "./base-fetch";
jest.mock("./base-fetch");

describe("use the fetch", () => {
  it("initial data state is loading and data empty", () => {
    const { result } = renderHook(() => useTheFetch("people"));

    expect(result.current).toStrictEqual({ loading: true, data: null });
  });

  it("data is fetched and loading is complete", async () => {
    const fakeSWData = { result: [{ name: "Luke Skywalker" }] };
    getStarWars.mockResolvedValue(fakeSWData);

    const { result, waitForNextUpdate } = renderHook(() =>
      useTheFetch("people")
    );

    await waitForNextUpdate();

    expect(getStarWars).toBeCalledWith("people");
    expect(result.current).toStrictEqual({
      loading: false,
      data: fakeSWData,
    });
  });
});

use-the-fetch.js

import { useState, useEffect } from "react";
import { getStarWars } from "./base-fetch";
export function useTheFetch(path) {
  const [result, setResult] = useState({ loading: true, data: null });
  async function fetchData() {
    const data = await getStarWars(path); // being mocked
    setResult({ loading: false, data });
  }
  useEffect(() => {
    fetchData();
  }, []);

  return result;
}

base-fetch.js

const BASE_URL = "https://swapi.co/api/";

export async function baseFetch(url, options = {}) {
  const response = await fetch(url, options);
  return await response.json();
}

export const getStarWars = async (path) => baseFetch(BASE_URL + path);
0

There are 0 best solutions below