使用React测试库测试依赖状态的条件渲染

时间:2020-05-29 03:59:14

标签: reactjs react-testing-library

测试依赖于初始状态的组件进行条件渲染的方法是什么?

例如showLessFlag取决于状态,而react-testing-library中的测试状态适得其反。

那么我将如何在CommentList组件中测试这种情况

{showLessFlag === true ? (
    // will show most recent comments below
    showMoreComments()
) : (
    <Fragment>
        {/* filter based on first comment, this shows by default */}
        {filterComments.map((comment, i) => (
            <div key={i} className="comment">
                <CommentListContainer ref={ref} comment={comment} openModal={openModal} handleCloseModal={handleCloseModal} isBold={isBold} handleClickOpen={handleClickOpen} {...props} />
            </div>
        ))}
    </Fragment>
)}

是否应该像下面这样进行测试

  it("should check more comments", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const commentList = getByTestId("comment-show-more");
        expect(commentList).toBeNull();
    });

但是由于条件渲染,我收到了这个错误

TestingLibraryElementError:无法通过以下方式找到元素: [data-testid =“ comment-show-more”]

CommentList.tsx

import React, { Fragment, useState, Ref } from "react";
import Grid from "@material-ui/core/Grid";
import OurSecondaryButton from "../../../common/OurSecondaryButton";
import CommentListContainer from "../commentListContainer/commentListContainer";

function CommentList(props: any, ref: Ref<HTMLDivElement>) {
    const [showMore, setShowMore] = useState<Number>(2);
    const [openModal, setOpenModal] = useState(false);
    const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
    const the_comments = props.comments.length;
    const inc = showMore as any;
    const min = Math.min(2, the_comments - inc);
    const showComments = (e) => {
        e.preventDefault();
        if (inc + 2 && inc <= the_comments) {
            setShowMore(inc + 2);
            setShowLessFlag(true);
        } else {
            setShowMore(the_comments);
        }
    };
    const handleClickOpen = () => {
        setOpenModal(true);
    };
    const handleCloseModal = () => {
        setOpenModal(false);
    };

    const showLessComments = (e) => {
        e.preventDefault();
        setShowMore(2);
        setShowLessFlag(false);
    };
    const isBold = (comment) => {
        return comment.userId === props.userId ? 800 : 400;
    };
    // show comments by recent, and have the latest comment at the bottom, with the previous one just before it.
    const filterComments = props.comments
        .slice(0)
        .sort((a, b) => {
            const date1 = new Date(a.createdAt) as any;
            const date2 = new Date(b.createdAt) as any;
            return date2 - date1;
        })
        .slice(0, inc)
        .reverse();

    const showMoreComments = () => {
        return filterComments.map((comment, i) => (
            <div data-testid="comment-show-more" key={i} className="comment">
                <CommentListContainer ref={ref} comment={comment} openModal={openModal} handleCloseModal={handleCloseModal} isBold={isBold} handleClickOpen={handleClickOpen} {...props} />
            </div>
        ));
    };

    return (
        <Grid data-testid="comment-list-div">
            <Fragment>
                <div style={{ margin: "30px 0px" }}>
                    {props.comments.length > 2 ? (
                        <Fragment>
                            {min !== -1 && min !== -2 ? (
                                <Fragment>
                                    {min !== 0 ? (
                                        <OurSecondaryButton onClick={(e) => showComments(e)} component="span" color="secondary">
                                            View {min !== -1 && min !== -2 ? min : 0} More Comments
                                        </OurSecondaryButton>
                                    ) : (
                                        <OurSecondaryButton onClick={(e) => showLessComments(e)} component="span" color="secondary">
                                            Show Less Comments
                                        </OurSecondaryButton>
                                    )}
                                </Fragment>
                            ) : (
                                <OurSecondaryButton onClick={(e) => showLessComments(e)} component="span" color="secondary">
                                    Show Less Comments
                                </OurSecondaryButton>
                            )}
                        </Fragment>
                    ) : null}
                </div>
            </Fragment>
            {showLessFlag === true ? (
                // will show most recent comments below
                showMoreComments()
            ) : (
                <Fragment>
                    {/* filter based on first comment  */}
                    {filterComments.map((comment, i) => (
                        <div key={i} className="comment">
                            <CommentListContainer ref={ref} comment={comment} openModal={openModal} handleCloseModal={handleCloseModal} isBold={isBold} handleClickOpen={handleClickOpen} {...props} />
                        </div>
                    ))}
                </Fragment>
            )}
        </Grid>
    );
}

export default React.forwardRef(CommentList) as React.RefForwardingComponent<HTMLDivElement, any>;

CommentList.test.tsx

import "@testing-library/jest-dom";
import React, { Ref } from "react";
import CommentList from "./CommentList";
import { render, getByText, queryByText, getAllByTestId } from "@testing-library/react";

const props = {
    user: {},
    postId: null,
    userId: null,
    currentUser: {},
    ref: {
        current: undefined,
    },
    comments: [
        {
            author: { username: "barnowl", gravatar: "https://api.adorable.io/avatars/400/bf1eed82fbe37add91cb4192e4d14de6.png", bio: null },
            comment_body: "fsfsfsfsfs",
            createdAt: "2020-05-27T14:32:01.682Z",
            gifUrl: "",
            id: 520,
            postId: 28,
            updatedAt: "2020-05-27T14:32:01.682Z",
            userId: 9,
        },
        {
            author: { username: "barnowl", gravatar: "https://api.adorable.io/avatars/400/bf1eed82fbe37add91cb4192e4d14de6.png", bio: null },
            comment_body: "fsfsfsfsfs",
            createdAt: "2020-05-27T14:32:01.682Z",
            gifUrl: "",
            id: 519,
            postId: 27,
            updatedAt: "2020-05-27T14:32:01.682Z",
            userId: 10,
        },
    ],
    deleteComment: jest.fn(),
};
describe("Should render <CommentList/>", () => {
    it("should render <CommentList/>", () => {
        const commentList = render(<CommentList {...props} />);
        expect(commentList).toBeTruthy();
    });

    it("should render first comment", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const commentList = getByTestId("comment-list-div");
        expect(commentList.firstChild).toBeTruthy();
    });

    it("should render second child", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const commentList = getByTestId("comment-list-div");
        expect(commentList.lastChild).toBeTruthy();
    });

    it("should check comments", () => {
        const rtl = render(<CommentList {...props} />);

        expect(rtl.getByTestId("comment-list-div")).toBeTruthy();
        expect(rtl.getByTestId("comment-list-div")).toBeTruthy();

        expect(rtl.getByTestId("comment-list-div").querySelectorAll(".comment").length).toEqual(2);
    });
    it("should match snapshot", () => {
        const rtl = render(<CommentList {...props} />);
        expect(rtl).toMatchSnapshot();
    });

    it("should check more comments", () => {
      const { getByTestId } = render(<CommentList {...props} />);
      const commentList = getByTestId("comment-show-more");
      expect(commentList).toBeNull();
    });
});

2 个答案:

答案 0 :(得分:1)

如果未找到匹配项,则react-testing-library中的任何getBy*查询都将引发错误。如果要测试/断言元素的缺失,则要使用任何queryBy*查询,如果找不到匹配项,它们将返回null。

Queries

enter image description here

it("should check more comments", () => {
  const { queryByTestId } = render(<CommentList {...props} />);
  const commentList = queryByTestId("comment-show-more");
  expect(commentList).toBeNull();
});

答案 1 :(得分:0)

为了更好地回答这个问题,我现在有更多使用React Testing库的经验。

在进行条件测试时,我们需要触发更改状态的动作。

例如在这种情况下

我们有类似showLessFlag

的条件
{showLessFlag === true ? (
    // will show most recent comments below
    showMoreComments()
) : (
    <Fragment>
        {/* filter based on first comment, this shows by default */}
        {filterComments.map((comment, i) => (
            <div key={i} className="comment">
                <CommentListContainer ref={ref} comment={comment} openModal={openModal} handleCloseModal={handleCloseModal} isBold={isBold} handleClickOpen={handleClickOpen} {...props} />
            </div>
        ))}
    </Fragment>
)}

为了正确地对此进行测试,我们需要触发将showLessFlag更改为false的事件。

所以我们可以做类似的事情

 <OurSecondaryButton
      onClick={(e) => showLessComments(e)}
      data-testid="_test-show-less"
      component="span"
      color="secondary"
    >
      Show Less Comments
 </OurSecondaryButton>

测试

it("should trigger showLessComments ", () => {
   const { getByTestId } = render(<CommentList {...props} />);
   const showLessButton = getByTestId("__test-show-less");
   fireEvent.click(showLessButton);
   expect(...) // whatever to be called, check for the existence of a div tag, or whatever you want
});

测试条件可以提高代码覆盖率:)

相关问题