1
votes

I have a react functional component where onload of the App I am smoking an API call which I have wrapped in useEffect and when the data is received I am updating the useState variable. While writing a unit test case for the below component using jest and react testing library I am receiving act error and useState variable error. Code:

import React, { useState, useEffect } from "react";
import TextField from "@material-ui/core/TextField";
import Media from "./card";
import Alert from "@material-ui/lab/Alert";
import fetchData from "../API";
const Dashboard = () => {
  const [searchInput, setSearchInput] = useState(null);
  const [receipeNotFound, setReceipeNotFound] = useState(false);

  useEffect(() => {
    fetchData(
      `https://www.themealdb.com/api/json/v1/1/random.php`,
      randomReceipe
    );
  }, []);

  const randomReceipe = (result) => {
    result.meals ? setSearchInput(result.meals[0]) : setSearchInput(null);
  };

  const searchData = (value) => {
    if (value) {
      setSearchInput(null);
      setReceipeNotFound(false);
      fetchData(
        `https://www.themealdb.com/api/json/v1/1/search.php?s=${value}`,
        searchRecepie
      );
    } else {
      setSearchInput(null);
    }
  };

  const notFound = (status) => {
    setReceipeNotFound(status);
    setSearchInput(null);
  };

  const searchRecepie = (result) => {
    result.meals ? setSearchInput(result.meals[0]) : notFound(true);
  };

  return (
    <div>
      <TextField
        data-testid="searchInput"
        id="standard-basic"
        label="Search"
        onBlur={(event) => searchData(event.currentTarget.value)}
      />
      {receipeNotFound ? (
        <Alert data-testid="alert" severity="error">
          Receipe not found!
        </Alert>
      ) : null}
      {Boolean(searchInput) ? (
        <Media data-testid="mediaLoading" loading={false} data={searchInput} />
      ) : (
        <Media data-testid="Media" loading={true} data={{}} />
      )}
    </div>
  );
};

export default Dashboard;

Test:

import React from "react";
import Dashboard from "./dashboard";
import ReactDOM from "react-dom";
import {
  render,
  screen,
  act,
  waitFor,
  fireEvent,
} from "@testing-library/react";
import { randomMockWithOutVideo, randomMockWithVideo } from "./API.mock";
global.fetch = jest.fn();
let container;

describe("Card ", () => {
  test("Should renders data when API request is called with meals data", async (done) => {
    jest.spyOn(global, "fetch").mockResolvedValue({
      json: jest.fn().mockResolvedValue({ meals: [randomMockWithVideo] }),
    });
    const { getByTestId, container } = render(<Dashboard />);
    expect(global.fetch).toHaveBeenCalledTimes(1);
    expect(global.fetch).toHaveBeenCalledWith(
      `https://www.themealdb.com/api/json/v1/1/random.php`
    );
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });
});

error: Warning: An update to Dashboard 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 */

19 | result.meals ? setSearchInput(result.meals[0]) : setSearchInput(null); | ^

1
What is the error throwing at line no.19 ?Sarun UK
What version of RTL are you using?Drew Reese

1 Answers

0
votes

This warning indicates that an update has been made to your component (through useState) after it was tear down. You can read a full explanation by Kent C. Dodds here : https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning/.

I would try this syntax to get rid of the warning :

await act(() => {
  expect(global.fetch).toHaveBeenCalledTimes(1);
  expect(global.fetch).toHaveBeenCalledWith(`https://www.themealdb.com/api/json/v1/1/random.php`);
});