В идеале вы должны переместить вызов API за пределы componentDidMount
в его собственный класс method
.Таким образом, он может быть вызван вручную из метода жизненного цикла или из обратного вызова события.Кроме того, вы должны ожидать, что ответ каким-то образом повлияет на ваш пользовательский интерфейс state
(пример: отображение сообщения о том, что запрос не выполнен, и повторная попытка).
Следующий пример можно выполнить с помощью .then/.catch
вместо async/await
.В любом случае, вы работаете с Promises
, которые asynchronous
, и поэтому им нужно asynchronous
тесты.
Примечание : ниже предполагается, что disableLifecycleMethods
верно в enzyme
адаптер.Кроме того, просто тестирование state
изменений (или console.log
) немного излишне;вместо этого вы должны проверить, отображается ли компонент на основе текущих state
.
Рабочий пример : https://codesandbox.io/s/939w229l9r (включает в себя тесты end to end
и integration
--- вы можете запустить тесты, нажав на вкладку Tests
, расположенную в левом нижнем углу песочницы)
App.js (это будет контейнер , который содержит все соответствующие state
и распределяет его по своему children
при необходимости)
import React, { Component } from 'react';
class App extends Component {
state = = {
error: "",
isLoading: true,
solutions: {},
username: ""
};
componentDidMount() {
this.fetchData("/api/info/tmp");
}
fetchData = async (url) => {
try {
const res = await axios.get(url);
...do stuff
this.setState({
error: "",
isLoading: false,
solutions: res.data.solutions,
username: res.data.username
});
} catch (err) {
this.setState({
error: err,
isLoading: false,
solutions: {},
username: ""
});
}
}
render() { ... }
}
App.test.js (предполагается, что вы захотитеend to end
тест)
import { shallow } from 'enzyme';
import App from './App';
const timeout = () =>
new Promise(resolve => {
setTimeout(() => {
resolve();
}, 2000);
});
const initialState = {
error: "",
isLoading: true,
solutions: {},
username: ""
};
describe("App", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<App />);
wrapper.setState({ ...initialState });
});
afterAll(() => {
wrapper.unmount();
});
it("sets data to state based upon successful API call", async () => {
wrapper.instance().fetchData("/api/info/tmp");
await timeout();
wrapper.update();
expect(wrapper.state('isLoading')).toBeFalsy();
expect(wrapper.state('solutions')).toEqual({ somedata });
expect(wrapper.state('username')).toEqual("Some User");
});
it("displays an error upon unsuccessful API call", async () => {
wrapper.instance().fetchData("/api/bad/url");
await timeout();
wrapper.update();
expect(wrapper.state('isLoading')).toBeFalsy();
expect(wrapper.state('solutions')).toEqual({});
expect(wrapper.state('username')).toEqual("");
expect(wrapper.state('error')).toEqual("No data found.");
});
});
App.test.js (предполагается, что вы хотите integration
тест)
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import React from "react";
import { shallow } from "enzyme";
import App from "../App";
const solutions = [{ ... }, { ... }];
const username = "Some User"
const mockAxios = new MockAdapter(axios);
const initialState = {
error: "",
isLoading: true,
solutions: {},
username: ""
};
describe("App", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<App />);
wrapper.setState({ ...initialState });
});
afterEach(() => {
mock.reset();
});
afterAll(() => {
mock.restore();
wrapper.unmount();
});
it("displays an error upon unsuccessful API call", async () => {
try {
mockAxios.onGet("/users").networkErrorOnce();
await axios.get("users");
} catch (err) {
const error = err.toString();
wrapper.setState({
error,
isLoading: false,
solutions: {},
username: ""
});
wrapper.update();
expect(wrapper.state('isLoading')).toBeEqual(error);
expect(wrapper.state('isLoading')).toBeFalsy();
expect(wrapper.state('solutions')).toEqual({});
expect(wrapper.state('username')).toEqual("");
}
});
it("sets data to state based upon successful API call", async () => {
try {
mockAxios.onGet("/users").reply(200, { solutions, username });
const res = await axios.get("users");
wrapper.setState({
error: "",
isLoading: true,
solutions: res.data.solutions,
username: res.data.username
});
wrapper.update();
expect(wrapper.state('isLoading')).toBeFalsy();
expect(wrapper.state('solutions')).toEqual(solutions);
expect(wrapper.state('username')).toEqual(username);
} catch (e) {
console.log(e);
}
});
});