Cómo implementar la prueba Jest para Axios y Hooks - useEffect
¿Cómo puedo escribir una prueba de Jest para una llamada de Axios dentro de un useEffect en React?
Encontré cómo burlarme de los Axios aquí: https://stackoverflow.com/a/51654713/7883067
También sé cómo activar useEffect si lo llama la interacción del usuario, como el clic de un botón. Pero en el siguiente caso, useEffect está siendo llamado por una función asíncrona que es activada por la respuesta de Axios.
Ejemplo:
Componente
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;
Prueba
// 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();
});
});
¿Alguien podría ayudarme a mostrar lo que podría estar perdiendo o haciendo mal, por favor?
Respuestas
Siguiendo el consejo de Estus Flask, logré probar ese código usando mount en lugar de superficial y leyendo la publicación de Robin Wieruch entendí cómo burlarme de las promesas de Axios.
Así es como se ve el código ahora:
Componente
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;
Prueba
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");
});
});