Reactjs 如何对依赖redux道具的组件进行单元测试

Reactjs 如何对依赖redux道具的组件进行单元测试,reactjs,jestjs,enzyme,Reactjs,Jestjs,Enzyme,我有一个名为Comment List的组件,Comment List获取来自仪表板容器的this.props.posts之外的所有注释 组件在组件中被调用,从那里它将{post.Comments}作为道具传递给 我的问题是,考虑到组件依赖于redux选择器、api调用等,我如何正确地测试组件 这里是流程图 1) 仪表板容器包含this.props.post的道具 import { connect } from "react-redux"; import { createStructuredSel

我有一个名为Comment List的组件,Comment List获取来自仪表板容器的
this.props.posts
之外的所有注释

组件在
组件中被调用,从那里它将
{post.Comments}
作为道具传递给

我的问题是,考虑到组件依赖于redux选择器、api调用等,我如何正确地测试组件

这里是流程图

1) 仪表板容器包含this.props.post的道具

import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
    addContent,
    addTitle,
    createPostInit,
    deleteCommentInit,
    initCommentUpdates,
    deletePostInit,
    dislikePostInit,
    getPostsInit,
    likePostInit,
    notificationInit,
    postCommentInit,
} from "../actions/postActions";
import Dashboard from "../components/dashboard/dashboard";
import { getBodyError, getIsNotified, getNotification, getPopPosts, getPosts, getTitleError, getUser, postContent, title } from "./../selectors/selectors";
const mapDispatchToProps = (dispatch: any) => ({
    getPostsInit: () => dispatch(getPostsInit()),
    initCommentUpdates: () => dispatch(initCommentUpdates()),
    notificationInit: () => dispatch(notificationInit()),
    likePost: (id: number) => dispatch(likePostInit(id)),
    addTitle: (data: string) => dispatch(addTitle(data)),
    addContent: (data: string) => dispatch(addContent(data)),
    postCommentInit: (commentData: object) => dispatch(postCommentInit(commentData)),
    dislikePost: (id: number) => dispatch(dislikePostInit(id)),
    deletePostInit: (id: number, userId: number) => dispatch(deletePostInit(id, userId)),
    deleteComment: (id: number, postId: number, userId: number) => dispatch(deleteCommentInit(id, postId, userId)),
    createPostInit: (postData: object) => dispatch(createPostInit(postData)),
});

const mapStateToProps = createStructuredSelector({
    posts: getPosts(),
    popPosts: getPopPosts(),
    user: getUser(),
    isNotified: getIsNotified(),
    titleError: getTitleError(),
    bodyError: getBodyError(),
    title: title(),
    postContent: postContent(),
    notification: getNotification(),
});

export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
this.props.posts被映射,post.comments被传递给commentList prop

postList.tsx

{post.Comments.length > 0 ? (
    <Fragment>
        <Typography style={{ padding: "10px 0px", margin: "20px 0px" }}>Commments</Typography>
        <CommentList user={currentUser} deleteComment={props.deleteComment} userId={post.userId} postId={post.id} comments={post.Comments} />
        {/*  if show more hide show more button and show show less comments button */}
    </Fragment>
) : (
    <Grid item={true} sm={12} lg={12} style={{ padding: "30px 0px" }}>
        <Typography>No Commments Yet</Typography>
    </Grid>
)}
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Typography from "@material-ui/core/Typography";
import OurListItem from "../../common/OurListItem";
import DeleteOutlineOutlinedIcon from "@material-ui/icons/DeleteOutlineOutlined";
import moment from "moment";
import React, { Fragment, useState } from "react";
export default function CommentList(props: any) {
    const [showMore, setShowMore] = useState<Number>(3);
    const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
    const showComments = (e) => {
        e.preventDefault();
        setShowMore(12);
        setShowLessFlag(true);
    };
    const showLessComments = (e) => {
        e.preventDefault();
        setShowMore(3);
        setShowLessFlag(false);
    };
    return (
        <Grid>
            {props.comments.slice(0, showMore).map((comment, i) => (
                <div key={i}>
                    <List style={{ paddingBottom: "20px" }}>
                        <OurListItem>
                            <Typography color="primary" align="left">
                                {comment.comment_body}
                            </Typography>
                            {comment.gifUrl && (
                                <div style={{ display: "block" }}>
                                    <img width="100%" height="300px" src={`${comment.gifUrl}`} />
                                </div>
                            )}
                        </OurListItem>
                        {props.user && props.user.user && comment.userId === props.user.user.id ? (
                            <Typography style={{ display: "inline-block", float: "right" }} align="right">
                                <span style={{ cursor: "pointer" }} onClick={() => props.deleteComment(comment.id, props.postId, comment.userId)}>
                                    <DeleteOutlineOutlinedIcon style={{ margin: "-5px 0px" }} color="primary" /> <span>Delete</span>
                                </span>
                            </Typography>
                        ) : null}
                        <Typography style={{ padding: "0px 0px" }} variant="caption" align="left">
                            {comment.author.username}
                        </Typography>
                        <Typography style={{ fontSize: "12px" }} variant="body1" align="left">
                            {moment(comment.createdAt).calendar()}
                        </Typography>
                        <Divider variant="fullWidth" component="li" />
                    </List>
                </div>
            ))}
            <Fragment>
                {props.comments.length > 3 && showLessFlag === false ? (
                    <Button onClick={(e) => showComments(e)} variant="outlined" component="span" color="primary">
                        Show More Comments
                    </Button>
                ) : (
                    <Fragment>
                        {props.comments.length > 3 && (
                            <Button onClick={(e) => showLessComments(e)} variant="outlined" component="span" color="primary">
                                Show Less Comments
                            </Button>
                        )}
                    </Fragment>
                )}
            </Fragment>
        </Grid>
    );
}
import React from "react";
import CommentList from "./CommentList";
import Grid from "@material-ui/core/Grid";
import { createShallow } from "@material-ui/core/test-utils";
import toJson from "enzyme-to-json";
const props = {
    comments: [
        {
            userId: 1,
            id: 1,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 2,
            id: 2,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 3,
            id: 3,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
    ],
};
describe("Should render <CommentList/>", () => {
    let wrapper;
    let shallow;
    beforeEach(() => {
        shallow = createShallow();
        wrapper = shallow(<CommentList {...props} />);
    });

    it("should render <CommentList/>", () => {
        expect(wrapper.find(Grid)).toHaveLength(1);
    });

    it("should snap <CommentList/> component", () => {
        // expect(toJson(wrapper)).toMatchSnapshot();
    });
});
{post.Comments.length>0(
命令
{/*如果显示更多隐藏显示更多按钮和显示较少注释按钮*/}
) : (
还没有通知
)}
CommentList.tsx

{post.Comments.length > 0 ? (
    <Fragment>
        <Typography style={{ padding: "10px 0px", margin: "20px 0px" }}>Commments</Typography>
        <CommentList user={currentUser} deleteComment={props.deleteComment} userId={post.userId} postId={post.id} comments={post.Comments} />
        {/*  if show more hide show more button and show show less comments button */}
    </Fragment>
) : (
    <Grid item={true} sm={12} lg={12} style={{ padding: "30px 0px" }}>
        <Typography>No Commments Yet</Typography>
    </Grid>
)}
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Typography from "@material-ui/core/Typography";
import OurListItem from "../../common/OurListItem";
import DeleteOutlineOutlinedIcon from "@material-ui/icons/DeleteOutlineOutlined";
import moment from "moment";
import React, { Fragment, useState } from "react";
export default function CommentList(props: any) {
    const [showMore, setShowMore] = useState<Number>(3);
    const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
    const showComments = (e) => {
        e.preventDefault();
        setShowMore(12);
        setShowLessFlag(true);
    };
    const showLessComments = (e) => {
        e.preventDefault();
        setShowMore(3);
        setShowLessFlag(false);
    };
    return (
        <Grid>
            {props.comments.slice(0, showMore).map((comment, i) => (
                <div key={i}>
                    <List style={{ paddingBottom: "20px" }}>
                        <OurListItem>
                            <Typography color="primary" align="left">
                                {comment.comment_body}
                            </Typography>
                            {comment.gifUrl && (
                                <div style={{ display: "block" }}>
                                    <img width="100%" height="300px" src={`${comment.gifUrl}`} />
                                </div>
                            )}
                        </OurListItem>
                        {props.user && props.user.user && comment.userId === props.user.user.id ? (
                            <Typography style={{ display: "inline-block", float: "right" }} align="right">
                                <span style={{ cursor: "pointer" }} onClick={() => props.deleteComment(comment.id, props.postId, comment.userId)}>
                                    <DeleteOutlineOutlinedIcon style={{ margin: "-5px 0px" }} color="primary" /> <span>Delete</span>
                                </span>
                            </Typography>
                        ) : null}
                        <Typography style={{ padding: "0px 0px" }} variant="caption" align="left">
                            {comment.author.username}
                        </Typography>
                        <Typography style={{ fontSize: "12px" }} variant="body1" align="left">
                            {moment(comment.createdAt).calendar()}
                        </Typography>
                        <Divider variant="fullWidth" component="li" />
                    </List>
                </div>
            ))}
            <Fragment>
                {props.comments.length > 3 && showLessFlag === false ? (
                    <Button onClick={(e) => showComments(e)} variant="outlined" component="span" color="primary">
                        Show More Comments
                    </Button>
                ) : (
                    <Fragment>
                        {props.comments.length > 3 && (
                            <Button onClick={(e) => showLessComments(e)} variant="outlined" component="span" color="primary">
                                Show Less Comments
                            </Button>
                        )}
                    </Fragment>
                )}
            </Fragment>
        </Grid>
    );
}
import React from "react";
import CommentList from "./CommentList";
import Grid from "@material-ui/core/Grid";
import { createShallow } from "@material-ui/core/test-utils";
import toJson from "enzyme-to-json";
const props = {
    comments: [
        {
            userId: 1,
            id: 1,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 2,
            id: 2,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 3,
            id: 3,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
    ],
};
describe("Should render <CommentList/>", () => {
    let wrapper;
    let shallow;
    beforeEach(() => {
        shallow = createShallow();
        wrapper = shallow(<CommentList {...props} />);
    });

    it("should render <CommentList/>", () => {
        expect(wrapper.find(Grid)).toHaveLength(1);
    });

    it("should snap <CommentList/> component", () => {
        // expect(toJson(wrapper)).toMatchSnapshot();
    });
});
从“@material ui/core/Button”导入按钮;
从“@material ui/core/Divider”导入分隔器;
从“@material ui/core/Grid”导入网格;
从“@material ui/core/List”导入列表;
从“@material ui/core/ListItem”导入ListItem;
从“@material ui/core/Typography”导入排版;
从“../../common/OurListItem”导入OurListItem;
从“@material ui/icons/DeleteOutlined”导入DeleteOutlineDicon;
从“时刻”中导入时刻;
从“React”导入React,{Fragment,useState};
导出默认函数注释列表(道具:任意){
const[showMore,setShowMore]=useState(3);
const[showLessFlag,setShowLessFlag]=useState(false);
const showcoments=(e)=>{
e、 预防默认值();
setShowMore(12);
setShowLessFlag(真);
};
const showLessComments=(e)=>{
e、 预防默认值();
setShowMore(3);
setShowLessFlag(假);
};
返回(
{props.comments.slice(0,showMore.map)((comment,i)=>(
{comment.comment_body}
{comment.gifull&&(
)}
{props.user&&props.user.user&&comment.userId===props.user.user.id(
props.deleteComent(comment.id,props.postId,comment.userId)}>
删除
):null}
{comment.author.username}
{时刻(comment.createdAt.calendar()}
))}
{props.comments.length>3&&showLessFlag==false(
showcoments(e)}variant=“outlined”component=“span”color=“primary”>
显示更多评论
) : (
{props.comments.length>3&&(
showLessComments(e)}variant=“outlined”component=“span”color=“primary”>
少发表评论
)}
)}
);
}
考虑到我不是从redux得到这个组件,我如何用redux正确地测试这个组件,这是我的方法

CommentList.test.tsx

{post.Comments.length > 0 ? (
    <Fragment>
        <Typography style={{ padding: "10px 0px", margin: "20px 0px" }}>Commments</Typography>
        <CommentList user={currentUser} deleteComment={props.deleteComment} userId={post.userId} postId={post.id} comments={post.Comments} />
        {/*  if show more hide show more button and show show less comments button */}
    </Fragment>
) : (
    <Grid item={true} sm={12} lg={12} style={{ padding: "30px 0px" }}>
        <Typography>No Commments Yet</Typography>
    </Grid>
)}
import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import Typography from "@material-ui/core/Typography";
import OurListItem from "../../common/OurListItem";
import DeleteOutlineOutlinedIcon from "@material-ui/icons/DeleteOutlineOutlined";
import moment from "moment";
import React, { Fragment, useState } from "react";
export default function CommentList(props: any) {
    const [showMore, setShowMore] = useState<Number>(3);
    const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
    const showComments = (e) => {
        e.preventDefault();
        setShowMore(12);
        setShowLessFlag(true);
    };
    const showLessComments = (e) => {
        e.preventDefault();
        setShowMore(3);
        setShowLessFlag(false);
    };
    return (
        <Grid>
            {props.comments.slice(0, showMore).map((comment, i) => (
                <div key={i}>
                    <List style={{ paddingBottom: "20px" }}>
                        <OurListItem>
                            <Typography color="primary" align="left">
                                {comment.comment_body}
                            </Typography>
                            {comment.gifUrl && (
                                <div style={{ display: "block" }}>
                                    <img width="100%" height="300px" src={`${comment.gifUrl}`} />
                                </div>
                            )}
                        </OurListItem>
                        {props.user && props.user.user && comment.userId === props.user.user.id ? (
                            <Typography style={{ display: "inline-block", float: "right" }} align="right">
                                <span style={{ cursor: "pointer" }} onClick={() => props.deleteComment(comment.id, props.postId, comment.userId)}>
                                    <DeleteOutlineOutlinedIcon style={{ margin: "-5px 0px" }} color="primary" /> <span>Delete</span>
                                </span>
                            </Typography>
                        ) : null}
                        <Typography style={{ padding: "0px 0px" }} variant="caption" align="left">
                            {comment.author.username}
                        </Typography>
                        <Typography style={{ fontSize: "12px" }} variant="body1" align="left">
                            {moment(comment.createdAt).calendar()}
                        </Typography>
                        <Divider variant="fullWidth" component="li" />
                    </List>
                </div>
            ))}
            <Fragment>
                {props.comments.length > 3 && showLessFlag === false ? (
                    <Button onClick={(e) => showComments(e)} variant="outlined" component="span" color="primary">
                        Show More Comments
                    </Button>
                ) : (
                    <Fragment>
                        {props.comments.length > 3 && (
                            <Button onClick={(e) => showLessComments(e)} variant="outlined" component="span" color="primary">
                                Show Less Comments
                            </Button>
                        )}
                    </Fragment>
                )}
            </Fragment>
        </Grid>
    );
}
import React from "react";
import CommentList from "./CommentList";
import Grid from "@material-ui/core/Grid";
import { createShallow } from "@material-ui/core/test-utils";
import toJson from "enzyme-to-json";
const props = {
    comments: [
        {
            userId: 1,
            id: 1,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 2,
            id: 2,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
        {
            userId: 3,
            id: 3,
            comment_body: "delectus aut autem",
            author: {
                username: "Bill",
            },
        },
    ],
};
describe("Should render <CommentList/>", () => {
    let wrapper;
    let shallow;
    beforeEach(() => {
        shallow = createShallow();
        wrapper = shallow(<CommentList {...props} />);
    });

    it("should render <CommentList/>", () => {
        expect(wrapper.find(Grid)).toHaveLength(1);
    });

    it("should snap <CommentList/> component", () => {
        // expect(toJson(wrapper)).toMatchSnapshot();
    });
});
从“React”导入React;
从“/CommentList”导入CommentList;
从“@material ui/core/Grid”导入网格;
从“@material ui/core/test utils”导入{createshall}”;
从“酶到json”导入toJson;
常量道具={
评论:[
{
用户ID:1,
id:1,
评论主体:“授权或授权”,
作者:{
用户名:“比尔”,
},
},
{
用户ID:2,
id:2,
评论主体:“授权或授权”,
作者:{
用户名:“比尔”,
},
},
{
用户ID:3,
id:3,
评论主体:“授权或授权”,
作者:{
用户名:“比尔”,
},
},
],
};
描述(“应该呈现”,()=>{
让包装纸;
让浅;
在每个之前(()=>{
shallow=createShallow();
包装器=浅();
});
它(“应该呈现”,()=>{
expect(wrapper.find(Grid)).toHaveLength(1);
});
它(“应捕捉组件”,()=>{
//expect(toJson(wrapper)).toMatchSnapshot();
});
});
我的问题是,考虑到组件依赖于redux选择器、api调用等,如何正确地测试组件

我不认为这是真的。组件既不依赖也不了解Redux,它只获得道具(您可以在测试中模拟道具)

考虑到我不是从redux得到这个组件,我如何用redux正确地测试这个组件,下面是我的方法

你没有-这是测试实现细节。您可以测试减速器本身,但最好的测试方法不是将它们绑在一起

在我看来,你试图用这个组件来测试你的减速器,不一定是组件本身,因为测试组件本身工作得很好

或者一起测试,您应该看看E2E测试

我的问题是,考虑到组件依赖于redux选择器、api调用等,如何正确地测试组件

我不认为这是真的。组件不依赖也不知道Redux,它是