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();
});