Comment implémenter le test Jest pour Axios et Hooks - useEffect

Sep 28 2020

Comment puis-je écrire un test Jest pour un appel Axios dans un useEffect dans React?

J'ai trouvé comment me moquer de l'Axios ici - https://stackoverflow.com/a/51654713/7883067

Je sais également comment déclencher le useEffect s'il est appelé par une interaction utilisateur telle que le clic d'un bouton. Mais dans le cas suivant, useEffect est appelé par une fonction asynchrone qui est déclenchée par la réponse d'Axios.

Exemple:

Composant

import React, { useState, useEffect } from "react";
import axios from "axios";

const LoadImage = () => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState(null);

  const fetchData = async () => {
    return await axios
      .get("https://picsum.photos/200/300.jpg", {
        "Content-Type": "application/xml; charset=utf-8",
      })
      .then((response) => {
        setData(response.config.url);
        setLoading(false);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    <div>
      {loading ? (
        <div>...loading</div>
      ) : (
        <div>
          {console.log(data)}
          <h3>Get Image</h3>
          <img alt="picsum-api" src={`${data}`} />
        </div>
      )}
    </div>
  );
};

export default LoadImage;

Test

// setUpTest.js
// import "@testing-library/jest-dom/extend-expect";
// import { configure } from "enzyme";
// import Adapter from "enzyme-adapter-react-16";
// configure({ adapter: new Adapter() });

import React from "react";
import { shallow } from "enzyme";
import * as axios from "axios";
import LoadImage from "../components/LoadImage";

describe("LoadImage test", () => {
  jest.mock("axios");
  axios.get = jest.fn();

  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<LoadImage />);
  });

  test("good response", () => {
    axios.get.mockImplementation(() => Promise.resolve({ status: 200 }));
    // expect();
  });
});

Quelqu'un pourrait-il m'aider à montrer ce que je pourrais manquer ou faire de mal, s'il vous plaît?

Réponses

4 MarkNunes Sep 30 2020 at 23:26

Suivant les conseils d'Estus Flask, j'ai réussi à tester ce code en utilisant mount au lieu de shallow et en lisant le post de Robin Wieruch, j'ai compris comment se moquer des promesses d'Axios.

Voici à quoi ressemble le code maintenant:

Composant

import React, { useState, useEffect } from "react";
import axios from "axios";

const LoadImage = () => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState(null);

  const fetchData = async () => {
    return await axios.get("https://picsum.photos/200/300.jpg");
  };

  useEffect(() => {
    fetchData().then((res) => {
      setData(res.config.url);
      setLoading(false);
    });
  }, []);

  return (
    <div>
      {loading ? (
        <div>...loading</div>
      ) : (
        <div>
          <h3>Get Image</h3>
          <img alt="picsum-api" src={`${data}`} />
        </div>
      )}
    </div>
  );
};

export default LoadImage;

Test

import React from "react";
import { mount, shallow } from "enzyme";
import axios from "axios";
import { act } from "react-dom/test-utils";

import LoadImage from "../components/LoadImage";

jest.mock("axios");

// mock data
const data = {
  config: {
    url: "image-url",
  },
};

describe("LoadImage test", () => {
  let wrapper;

  // clear all mocks
  afterEach(() => {
    jest.clearAllMocks();
  });

  test("renders with loading", () => {
    wrapper = shallow(<LoadImage />);    
    expect(wrapper.find("div").first().text()).toBe("...loading");
  });

  test("loads img", async () => {

    // mock axios promise
    await act(async () => {
      await axios.get.mockImplementationOnce(() => Promise.resolve(data));
      wrapper = mount(<LoadImage />);
    });

    // check the render output
    wrapper.update();

    await expect(axios.get).toHaveBeenCalledWith("https://picsum.photos/200/300.jpg");

    await expect(axios.get).toHaveBeenCalledTimes(1);

    await expect(wrapper.find("img").props().src).toEqual("image-url");
  });
});