BARNOWL
BARNOWL

Reputation: 3599

how to unit test component that relies on redux props

I have a component called Comment List, comment list is getting all comments that is apart of this.props.posts Which comes from the dashboard container.

The <CommentList/> component is being called in the <PostList/> component, from there it is passing {post.Comments} as props to

My question is how would i properly test <CommentList/> Component, considering it relies on redux selector, api call etc.

Here is the flow.

1) dashboard container holds the props for 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 gets mapped, and post.Commments gets passed to 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>
)}

CommentList.tsx

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

How would i correctly test this component with redux, considering im not getting it from redux, here is my approach,

CommentList.test.tsx

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

Upvotes: 0

Views: 61

Answers (1)

Arber Sylejmani
Arber Sylejmani

Reputation: 2108

My question is how would i properly test Component, considering it relies on redux selector, api call etc.

I don't see this being true anywhere. Component doesn't rely nor know about Redux, it's only getting props (which you can mock in your tests).

How would i correctly test this component with redux, considering I'm not getting it from redux, here is my approach

You don't - that's testing implementation details. You can test the reducers themselves, but the best way to test this is not to tie them together.

The way I see it, you're trying to test your reducers using this component, not necessarily the component itself as to test the component itself works just fine.

Or to test it all together, you should look at E2E tests.

Upvotes: 2

Related Questions