How to unit test axios get request with enzyme in react functional component with useEffect dependencies?

Hi I am trying to test the react functional component which has axios call, my test is successful but I do not see any code coverage . Not sure what am I missing any help is really appreciated.

Below is the code implementation of my useEffect hook with dependency. Thanks

Component code:

const fetchTasks = async () => {
const xsrfToken = window.RequestVerificationToken;
const tasksPath =
  process.env.REACT_APP_BASE_PATH + "task/outstanding-items/list";
const tasksConfig = {
  headers: {
    "Content-Type": "application/json",
    RequestVerificationToken: xsrfToken
  }
};
setIsLoading(true);
const tasksResponse = await axios.get(tasksPath, tasksConfig);

if (checkForTimeOut(tasksResponse)) {
  return;
}

setTasks(tasksResponse.data);
setIsLoading(false);
  };


 useEffect(() => {
    if (!testing && isCompleted) {
      setIsCompleted(false);
      fetchTasks();
      window.addEventListener("resize", handleResize);

  return () => {
    window.removeEventListener("resize", handleResize);
  };
}
}, [isCompleted]);

Unit test implementation

it("should make axios call", async () => {
    let wrapper;

    let response = {
      data: {
        tasks: [
          {
            ClaimId: 12345,
            Url: "/example",
            IsFml: false,
            OutstandingItems: [
              {
                TaskIdentifier: 12345,
                TaskTypeID: "FSTHSPBG",
                TaskName: "Date first hospitalized",
                TaskTitleText: "First Hospitalized Date",
                TaskDisplayText:
                  "Please provide the date on which you were first hospitalized for this claim.",
                TaskActualStartDate: "/Date(1511804371000)/",
                OutstandingItemActions: [
                  {
                    ActionDisplayText: "Submit",
                    ActionParameterText: "Date",
                    ActionTypeText: "SingleField"
                  }
                ],
                PartyIdentifier: null,
                NamePrefix: null,
                PersonFirstName: null,
                PersonMiddleName: null,
                PersonLastName: null,
                NameSuffix: null,
                OrganizationName: null,
                OrganizationNameSecond: null
              }
            ]
          }
        ]
      }
    };
    await act(async () => {
      await axios.get.mockImplementationOnce(() => Promise.resolve(response));
      wrapper = mount(
        <NewTaskPage filteredTasks={response.data.tasks.ClaimId} />
      );
    });
    wrapper.setProps({ testing: false, isCompleted: true });
    wrapper.update();
    await expect(axios.get).toHaveBeenCalledTimes(1);
  });

Any help or suggestion is appreciated, and thanks in advance.

Hi @anon42932716 Sorry about the link I have also created new post about the issue what I am facing. Which you can see here I just have tagged you on this post

Welcome back to the community @tapesh !

Did you have a question for the community?

We can see that you have posted a link and wonder if there is some way the community can be of help to you.

Happy coding!

Please do not create multiple topics for the same question. I have merged your topics.

3 Likes
useEffect(async () => {
  if (!testing && isCompleted) {
    setIsCompleted(false);
    await fetchTasks();
    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }
}, [isCompleted]);

make the useEffect function asynchronous and use await for fetchTasks .

In your test, you are using axios.get.mockImplementationOnce(() => Promise.resolve(response)); . While this is generally okay, keep in mind that it will only work for the first call to axios.get . If you have subsequent calls to axios.get in your fetchTasks function, you might need to use mockImplementation instead.

axios.get.mockImplementation(() => Promise.resolve(response));

Your test checks if axios.get has been called, but it doesn’t verify if it has been called with the correct URL.

await expect(axios.get).toHaveBeenCalledWith(
  process.env.REACT_APP_BASE_PATH + "task/outstanding-items/list",
  tasksConfig
);

1 Like

Thanka for reply will surely give it a try. And yes I do have multiple axios call…

1 Like

You should get an error if you try to make the useEffect callback async.

Error message:

Warning: useEffect must not return anything besides a function, which is used for clean-up.

It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching

What is providing the code coverage, Jest?

Hi I tried the this solution but it throws an error. Also I have share the full code of my component as well in below reply. to @lasjorg

1 Like

Yes exactly, I did get the error, however when I tried to call function inside useEffect it was still the same no change.

Please see the full code implementation in the post, here.

import React, { useState, useEffect } from "react";
import axios from "axios";
import {
  checkForTimeOut,
  totalLeavePortalLink,
  getSSOEnvironment,
  getCookie
} from "../../Helpers";
import AlertBanner from "../AlertBanner/AlertBanner";
import TotalLeaveEmptyStateCTA from "../TotalLeaveEmptyStateCTA/TotalLeaveEmptyStateCTA";
import Skeleton from "@material-ui/lab/Skeleton";
import NewTaskList from "./NewTaskList";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBellOn } from "@fortawesome/pro-solid-svg-icons";
import { cdnImagePath, task } from "../../imageHelper";

const midBreakpoint = 768;

const NewTaskPage = props => {
  const { testing = false, totalLeave = false } = props;
  const [isLoading, setIsLoading] = useState(true);
  const [isMobile, setIsMobile] = useState(window.innerWidth < midBreakpoint);
  const [hasTotalLeave, setHasTotalLeave] = useState(totalLeave);
  const [tasks, setTasks] = useState(props.tasks || []);
  const [completedTasks, setCompletedTasks] = useState([]);
  const [isCompleted, setIsCompleted] = useState(false);

  let ssoEnvironment = getSSOEnvironment();

  if (process.env.NODE_ENV === "development") {
    const MockService = require("../../services/mockService.js");
    MockService.default.init(axios);
  }

  const handleResize = () => {
    setIsMobile(window.innerWidth < midBreakpoint);
  };

  const removeTask = claimId => {
    setCompletedTasks(prevCompletedTasks => [...prevCompletedTasks, claimId]);
  };

  const fetchData = async () => {
    const xsrfToken = window.RequestVerificationToken;
    const tasksPath =
      process.env.REACT_APP_BASE_PATH + "task/outstanding-items/list";

    const unumEnterpriseSSOValue = getCookie(
      `unumEnterpriseSSO${ssoEnvironment}`
    );

    const totalLeaveIndicatorPath =
      process.env.REACT_APP_BASE_PATH + "Event/TotalLeaveIndicator";

    const tasksConfig = {
      headers: {
        "Content-Type": "application/json",
        RequestVerificationToken: xsrfToken
      }
    };

    const totalLeaveConfig = {
      headers: {
        "Content-Type": "application/json"
      }
    };

    try {
      setIsLoading(true);

      const tasksResponse = await axios.get(tasksPath, tasksConfig);

      if (unumEnterpriseSSOValue) {
        const totalLeaveResponse = await axios.get(
          totalLeaveIndicatorPath,
          totalLeaveConfig
        );

        if (
          checkForTimeOut(tasksResponse) ||
          checkForTimeOut(totalLeaveResponse)
        )
          return;

        setHasTotalLeave(totalLeaveResponse.data.hasTotalLeave);
      }
      setTasks(tasksResponse.data);
    } catch (error) {
      console.error("Error fetching data:", error);
    } finally {
      setIsLoading(false);
    }
  };

  const fetchTasks = async () => {
    try {
      const xsrfToken = window.RequestVerificationToken;
      const tasksPath =
        process.env.REACT_APP_BASE_PATH + "task/outstanding-items/list";
      const tasksConfig = {
        headers: {
          "Content-Type": "application/json",
          RequestVerificationToken: xsrfToken
        }
      };
      setIsLoading(true);
      const tasksResponse = await axios.get(tasksPath, tasksConfig);

      if (checkForTimeOut(tasksResponse)) {
        return;
      }

      setTasks(tasksResponse.data);
      setIsLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    let env = process.env.NODE_ENV;
    if (env === "production" && !window.location.host.startsWith("services")) {
      env = window.location.host
        .substring(0, window.location.host.indexOf("services"))
        .replace("-", "");
    }

    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: "custom_pageview",
      env: env,
      app_source: "web",
      digital_asset: "unum claims",
      journey_name: "b&cc",
      page_location: window.location.href,
      page_title: "to-do's",
      page_referrer: document.referrer
    });

    if (!testing) {
      fetchData();
      window.addEventListener("resize", handleResize);

      return () => {
        window.removeEventListener("resize", handleResize);
      };
    }
  }, []);

  useEffect(() => {
    if (!testing && isCompleted) {
      setIsCompleted(false);
      fetchTasks();
      window.addEventListener("resize", handleResize);

      return () => {
        window.removeEventListener("resize", handleResize);
      };
    }
  }, [isCompleted]);

  const filteredTasks = tasks
    ? tasks.filter(item => completedTasks.indexOf(item.ClaimId) === -1)
    : [];

  return (
    <div className="taskPage">
      {isLoading ? (
        <>"isLoading"   </>
      ) : (
        <>
          {hasTotalLeave && filteredTasks.length > 0 && (
            <div className="alert-banner-wrapper">
              <AlertBanner
                text={
                  <>
                    To view or manage your leave or disability coverage, please
                    visit the{" "}
                    <strong>
                      <a
                        href={totalLeavePortalLink}
                        onClick={() => {
                          window.dataLayer.push({
                            event: "custom_event",
                            category: "button",
                            action: "click",
                            label: "visit the total leave portal",
                            attribute1: "to-dos",
                            attribute2: "undefined",
                            attribute3: "navigation_click",
                            attribute4: "undefined"
                          });
                        }}
                      >
                        Total Leave Portal
                      </a>
                    </strong>
                  </>
                }
              />
            </div>
          )}
          <div className="taskPageMain">
            <span>
              <img src={cdnImagePath(task)} alt="TaskIcon" />
            </span>
            Tasks
          </div>
          <div className="taskPageContent">
            <div className="taskPageInfoBanner">
              <div className="infoIcon">
                <FontAwesomeIcon icon={faBellOn} />
              </div>
              <div className="infoContent">
                Please complete the following items to ensure your leave
                requests and claims get processed as soon as possible.
              </div>
            </div>
            {filteredTasks.length > 0 ? (
              <NewTaskList
                tasks={filteredTasks}
                isLoading={isLoading}
                taskCompleted={removeTask}
                setIsCompleted={setIsCompleted}
                testing={testing}
                setIsLoading={setIsLoading}
              />
            ) : (
              <div>You do not have to-do items to complete right now.</div>
            )}
          </div>
          {!filteredTasks.length && hasTotalLeave && (
            <TotalLeaveEmptyStateCTA
              className=""
              isMobile={isMobile}
              type="to-dos"
            />
          )}
        </>
      )}
    </div>
  );
};

export default NewTaskPage;

Are you not just asking about the code coverage report? Did you look at the docs I linked to?

I think you got me wrong. I am asking about the test case why doesn’t it cover the full api call in code coverage while my test has run successfully? I am asking the help in regard to writing the correct unit test case .

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.