This project was bootstrapped with Create React App. It is built on a demo repo used for the react intro 2 lecture, a simple blog style posts page built using useState, prop types and basic event handlers.
Here we will using Jest, React testing library and React test renderer to add tests that:
- create snapshots
- use valid props for test objects
- fetch elements using queries
- validate elements on screen using matchers
- mock functions with Jest
- validate functions are being called when triggering an event listener
Clone down the repo, and cd
and into the new directory. If you want to start from the same place as we did at the start of the lecture, simply run npm i
then npm start
If you want to see the finished app as it was at the end of the session, you will need to checkout the complete
branch on this repo. You can do that by running
git checkout -t origin/complete
which will pull down the completed branch to your local environment (you will have to run npm i
to update the new dependencies)
- Create a snapshot for the component
Solution
test("Renders correctly", () => {
const rendered = renderer.create(<App />)
expect(rendered).toMatchSnapshot()
})
- Assert the title text displayed within the component is correct
Solution
test("Renders correct title", () => {
render(<App />);
const linkElement = screen.getByText("Testing in React", {exact: true});
expect(linkElement).toBeInTheDocument();
});
In order to test the Post component we will need to mock the props it will take. Create a validProps
object in your test file as follows:
const validProps = {
postData: {
author: "test author",
body: "test body",
date:"test date",
isPublished: true,
tags: ["test tag1", "test tag2", "test tag3"],
title: "test title"
},
handleUpvote: jest.fn()
}
- Create a snapshot
Solution
test("Renders as expected" , () => {
const rendered = renderer.create(
<Post
postData={validProps.postData}
handleUpvote={validProps.handleUpvote}
/>)
expect(rendered).toMatchSnapshot()
})
- Assert the post author is present
Solution
test("Assert the post author is present", () => {
render(
<Post
postData={validProps.postData}
handleUpvote={validProps.handleUpvote}
/>);
expect(screen.getByText("Author: test author")).toBeInTheDocument();
})
- Assert there is a single button and that it has the correct text
Solution
test("Renders a single button with correct text", () => {
render(
<Post
postData={validProps.postData}
handleUpvote={validProps.handleUpvote}
/>
);
const buttons = screen.getAllByRole("button");
expect(buttons).toHaveLength(1);
expect(buttons[0]).toHaveTextContent("Upvote this")
})
- Assert the tags list has the correct number of items
Solution
test("Tags list renders correct number of items", () => {
render(
<Post
postData={validProps.postData}
handleUpvote={validProps.handleUpvote}
/>
);
const tags = screen.getAllByRole("listitem");
expect(tags.length).toBe(3);
})
- Assert clicking the button calls the handler function, and it has been called with the expected argument
Solution
test("Upvote button calls correct function", () => {
render(
<Post
postData={validProps.postData}
handleUpvote={validProps.handleUpvote}
/>
);
fireEvent.click(screen.getByRole("button"));
expect(validProps.handleUpvote).toHaveBeenCalled();
expect(validProps.handleUpvote).toHaveBeenCalledTimes(1);
expect(validProps.handleUpvote).toHaveBeenCalledWith(
validProps.postData.title
);
})
Similarly to the Post component we will need to mock the props that the Postlist component will take. So will once again create a validProps
object in your test file:
const validProps = {
posts: [
{
id: 1,
author: "test author",
body: "test body",
date: "test date",
isPublished: true,
tags: ["test tag1", "test tag2", "test tag3"],
title: "test title",
},
{
id: 2,
author: "test author 2",
body: "test body 2",
date: "test date 2",
isPublished: false,
tags: ["test tag1-2", "test tag2-2", "test tag3-2"],
title: "test title 2",
},
],
};
- Create a snapshot
Solution
test("Renders as expected", () => {
const rendered = renderer.create(<Postlist posts={validProps.posts} />)
expect(rendered).toMatchSnapshot()
})
- Assert the 'last upvoted' field is updated when clicking on a post
Solution
test("Last upvoted post is displayed when clicked", async () => {
render(<Postlist posts={validProps.posts} />);
const buttons = screen.getAllByRole("button");
const firstPostUpvote = buttons[0];
const secondPostUpvote = buttons[1];
expect(firstPostUpvote).toHaveValue(validProps.posts[0].title);
expect(secondPostUpvote).toHaveValue(validProps.posts[1].title);
const lastUpvotedBox = screen.queryByText("Last upvoted post:");
expect(lastUpvotedBox).toBeNull;
fireEvent.click(firstPostUpvote);
let lastUpvoted = await screen.findByText("Last upvoted post: test title");
expect(lastUpvoted).toBeInTheDocument();
fireEvent.click(secondPostUpvote);
lastUpvoted = await screen.findByText("Last upvoted post: test title 2");
expect(lastUpvoted).toBeInTheDocument();
});
Run the app with:
Open http://localhost:3000 to view it in your browser.
Run the tests with: