Come implementare il test Jest per Axios e Hooks - useEffect
Come posso scrivere un test Jest per una chiamata Axios all'interno di un useEffect in React?
Ho scoperto come deridere gli Axios qui - https://stackoverflow.com/a/51654713/7883067
So anche come attivare useEffect se viene richiamato dall'interazione dell'utente come il clic di un pulsante. Ma nel caso seguente, useEffect viene chiamato da una funzione asincrona che viene attivata dalla risposta di Axios.
Esempio:
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;
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();
});
});
Qualcuno potrebbe aiutarmi a mostrare cosa potrei perdere o fare di sbagliato, per favore?
Risposte
Seguendo il consiglio di Estus Flask, sono riuscito a testare quel codice usando mount invece di superficiale e leggendo il post di Robin Wieruch ho capito come deridere le promesse di Axios.
Ecco come appare il codice ora:
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;
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");
});
});