Como implementar o teste Jest para Axios e Hooks - useEffect
Como posso escrever um teste de Jest para uma chamada do Axios dentro de um useEffect no React?
Eu descobri como zombar dos Axios aqui - https://stackoverflow.com/a/51654713/7883067
Também sei como acionar o useEffect se for chamado pela interação do usuário, como o clique de um botão. Mas, no caso a seguir, o useEffect está sendo chamado por uma função assíncrona que é disparada pela resposta do Axios.
Exemplo:
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;
Teste
// 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();
});
});
Alguém poderia me ajudar a mostrar o que posso estar faltando ou fazendo de errado, por favor?
Respostas
Seguindo o conselho de Estus Flask, consegui testar esse código usando mount em vez de shallow e lendo a postagem de Robin Wieruch entendi como simular as promessas do Axios.
Esta é a aparência do código agora:
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;
Teste
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");
});
});