Jest/Enzyme - 如何将 nock 库与连接的 redux 存储组件一起使用?
Jest/Enzyme - How to use nock library with a connected redux store component?
目标
我们想测试 Reviews 组件中 componentDidMount() 上的异步调用 fetchReviews(),并检查它是否更新了我们的之后查看 组件。
这里是评论:
const Review: React.FC<ReviewProps> = (props) => {
useEffect(() => {
props.fetchReviews();
}, []);
//other code...
const mapStateToProps = (state: StoreState): FetchReviewsResponse => {
return {
reviews: state.reviews,
};
};
export default connect(mapStateToProps, { fetchReviews })(Review);
问题
测试终端报错:
给定操作“1”,reducer“评论”return未定义。
要忽略操作,您必须明确 return 之前的状态。
如果你想让这个 reducer 不持有任何价值,你可以 return null 而不是 undefined.
return dispatch<FetchReviewsAction>({
| ^
28 | //Generic is an extra step to ensure that everything has the right values
29 | type: ActionTypes.FETCH_REVIEWS,
30 | payload: response.data,
为了演示,这是我的 Review.test:
import React from "react";
import nock from "nock";
import { mount, ReactWrapper } from "enzyme";
import Root from "Root";
import Body from "components/Body";
import waitForExpect from "wait-for-expect";
import ReviewBox from "components/ReviewBox";
describe("<Body> integration", () => {
let wrapper: ReactWrapper;
let mockData: any;
beforeEach(() => {
mockData = [
{
id: 1,
username: "Big Fish",
date: "2017-09-16",
title: "Apple Store Review",
description: "App Description 1",
rating: 1,
},
];
wrapper = mount(
<Root>
<Body />
</Root>
);
});
it("has the correct type and payload", async () => {
//mock fetchReviews()
const scope = nock("https://apple-review-backend.vercel.app")
.get("/db.json")
.query(true)
.reply(200, mockData, { "Access-Control-Allow-Origin": "*" });
await waitForExpect(() => {
wrapper.update();
expect(scope.isDone()).toBe(true);
expect(wrapper.find(ReviewBox).length).toEqual(1);
});
});
});
审核 Reducer
export default (state: Review[] = [], action: FetchReviewsAction) => {
switch (action.type) {
case ActionTypes.FETCH_REVIEWS:
return action.payload.reviews;
default:
return state;
}
};
评论操作
export const fetchReviews = () => async (dispatch: Dispatch) => {
const response = await reviews.get<FetchReviewsResponse>("/db.json");
return dispatch<FetchReviewsAction>({
//Generic is an extra step to ensure that everything has the right values
type: ActionTypes.FETCH_REVIEWS,
payload: response.data,
});
};
解决了!问题不包括
act(async () => {
//https://github.com/enzymejs/enzyme/issues/2423
//
wrapper = mount(
<Root>
<Body />
</Root>
);
});
似乎在我们的测试结束后解决了 fetchReviews(..)(使用 axios)。通过用 act(async()...) 覆盖它,我们可以“等待”fetchRequest() 完成,这样我们就可以用 nock.
来模拟它
完整代码:
describe("<Body> integration", () => {
let wrapper: ReactWrapper;
let mockData: any;
beforeEach(async () => {
mockData = {
reviews: [
{
id: 1,
username: "Big Fish",
date: "2017-09-16",
title: "Apple Store Review",
description: "App Description 1",
rating: 1,
},
{
id: 2,
username: "ILoveApple",
date: "2017-10-16",
title: "Review of App",
description: "App Description 2",
rating: 2,
},
],
};
await act(async () => {
//https://github.com/enzymejs/enzyme/issues/2423
//
wrapper = mount(
<Root>
<Body />
</Root>
);
});
});
it("has the correct type and payload", async () => {
const scope = nock("https://apple-review-backend.vercel.app")
.get("/db.json")
.reply(200, mockData, { "Access-Control-Allow-Origin": "*" });
await waitForExpect(() => {
wrapper.update();
expect(scope.isDone()).toBe(true);
expect(wrapper.find(ReviewBox).length).toEqual(2);
});
}, 30000);
});
afterEach(function () {
// if (!nock.isDone()) {
// console.log("Not all nock interceptors were used!");
// nock.cleanAll();
// }
nock.restore();
});
目标
我们想测试 Reviews 组件中 componentDidMount() 上的异步调用 fetchReviews(),并检查它是否更新了我们的之后查看 组件。
这里是评论:
const Review: React.FC<ReviewProps> = (props) => {
useEffect(() => {
props.fetchReviews();
}, []);
//other code...
const mapStateToProps = (state: StoreState): FetchReviewsResponse => {
return {
reviews: state.reviews,
};
};
export default connect(mapStateToProps, { fetchReviews })(Review);
问题
测试终端报错:
给定操作“1”,reducer“评论”return未定义。 要忽略操作,您必须明确 return 之前的状态。 如果你想让这个 reducer 不持有任何价值,你可以 return null 而不是 undefined.
return dispatch<FetchReviewsAction>({
| ^
28 | //Generic is an extra step to ensure that everything has the right values
29 | type: ActionTypes.FETCH_REVIEWS,
30 | payload: response.data,
为了演示,这是我的 Review.test:
import React from "react";
import nock from "nock";
import { mount, ReactWrapper } from "enzyme";
import Root from "Root";
import Body from "components/Body";
import waitForExpect from "wait-for-expect";
import ReviewBox from "components/ReviewBox";
describe("<Body> integration", () => {
let wrapper: ReactWrapper;
let mockData: any;
beforeEach(() => {
mockData = [
{
id: 1,
username: "Big Fish",
date: "2017-09-16",
title: "Apple Store Review",
description: "App Description 1",
rating: 1,
},
];
wrapper = mount(
<Root>
<Body />
</Root>
);
});
it("has the correct type and payload", async () => {
//mock fetchReviews()
const scope = nock("https://apple-review-backend.vercel.app")
.get("/db.json")
.query(true)
.reply(200, mockData, { "Access-Control-Allow-Origin": "*" });
await waitForExpect(() => {
wrapper.update();
expect(scope.isDone()).toBe(true);
expect(wrapper.find(ReviewBox).length).toEqual(1);
});
});
});
审核 Reducer
export default (state: Review[] = [], action: FetchReviewsAction) => {
switch (action.type) {
case ActionTypes.FETCH_REVIEWS:
return action.payload.reviews;
default:
return state;
}
};
评论操作
export const fetchReviews = () => async (dispatch: Dispatch) => {
const response = await reviews.get<FetchReviewsResponse>("/db.json");
return dispatch<FetchReviewsAction>({
//Generic is an extra step to ensure that everything has the right values
type: ActionTypes.FETCH_REVIEWS,
payload: response.data,
});
};
解决了!问题不包括
act(async () => {
//https://github.com/enzymejs/enzyme/issues/2423
//
wrapper = mount(
<Root>
<Body />
</Root>
);
});
似乎在我们的测试结束后解决了 fetchReviews(..)(使用 axios)。通过用 act(async()...) 覆盖它,我们可以“等待”fetchRequest() 完成,这样我们就可以用 nock.
来模拟它完整代码:
describe("<Body> integration", () => {
let wrapper: ReactWrapper;
let mockData: any;
beforeEach(async () => {
mockData = {
reviews: [
{
id: 1,
username: "Big Fish",
date: "2017-09-16",
title: "Apple Store Review",
description: "App Description 1",
rating: 1,
},
{
id: 2,
username: "ILoveApple",
date: "2017-10-16",
title: "Review of App",
description: "App Description 2",
rating: 2,
},
],
};
await act(async () => {
//https://github.com/enzymejs/enzyme/issues/2423
//
wrapper = mount(
<Root>
<Body />
</Root>
);
});
});
it("has the correct type and payload", async () => {
const scope = nock("https://apple-review-backend.vercel.app")
.get("/db.json")
.reply(200, mockData, { "Access-Control-Allow-Origin": "*" });
await waitForExpect(() => {
wrapper.update();
expect(scope.isDone()).toBe(true);
expect(wrapper.find(ReviewBox).length).toEqual(2);
});
}, 30000);
});
afterEach(function () {
// if (!nock.isDone()) {
// console.log("Not all nock interceptors were used!");
// nock.cleanAll();
// }
nock.restore();
});