loading...

How to Test Your Presentational Components with Jest

a_reiterer profile image Andreas Reiterer Originally published at andreasreiterer.at on ・5 min read

Did you ever ask yourself, if it makes sense to test presentational components, or if it’s just too time consuming? Good news, you’re not alone! That’s why I put together three ways to create useful Jest tests for your presentational components without spending too much time.

“Does it make sense to test static components that only render a UI?”

The answer is: It depends. It might not be too useful if you only test if your JSX is rendered correctly, or if componentDidMount was called correctly. However, there are cases, where you really want to test your component, as well as the one or other quick-win, that can help you to avoid some nasty bugs later on.

In this post we will discuss some ways to introduce basic tests to your app. Please note: This is not meant to be a full blown in-depth article about the secrets of unit testing and how to achieve 100% code coverage. However, some testing is better than no testing – and the kind of tests that we’re discussing in the next sections might still save you some hours of debugging and bug fixing – without being too complicated and time consuming.

Test Conditional Rendering

If your component renders different content or child components, depending on the props that were passed, it is a good idea to test, if your component actually renders as intended.

To assert your rendered components with Jest, you can use enzyme or React’s TestUtils. For this example we use enzyme but feel free to use whatever library suits you best.

import React from "react"; import { shallow } from "enzyme"; import ContactListWithLoadingIndicator from "./ContactListWithLoadingIndicator"; import LoadingIndicator from "./LoadingIndicator"; import ContactList from "./ContactList"; const dummyFunc = () =\> {}; const dummyArray = [{ id: 1, firstName: "Max", lastName: "Mustermann", street: "Duck Creek Road", house: 2561, zip: 94107, city: "San Francisco", phone: "650-795-0470", email: "max.mustermann@internet.com" }, { id: 2, firstName: "Maxine", lastName: "Musterfrau", street: "Duck Creek Road", house: 2562, zip: 94107, city: "San Francisco", phone: "650-795-0471", email: "maxine.musterfrau@internet.com" }]; test("ContactListWithLoadInd shows LoadingIndicator when loading", () =\> { const contactList = shallow( \<ContactListWithLoadingIndicator isLoading={true} contacts={dummyArray} /\> ); const loadingIndicator = contactList.find(LoadingIndicator); expect(loadingIndicator).toHaveLength(1); }); test("ContactListWithLoadInd shows ContactList when not loading", () =\> { const contactList = shallow( \<ContactListWithLoadingIndicator isLoading={false} contacts={dummyArray} /\> ); const list = contactList.find(ContactList); expect(list).toHaveLength(1); });

In this example we created two unit tests. The first one, renders our <ContactListWithLoadingIndicator> with isLoading={true} to check, if it renders a <LoadingIndicator>, while in the second test case, we check if it renders the <ContactList> component when it’s not currently loading.

Add Basic Component Tests

“It only renders some UI, it can’t break, so I don’t need to test it”

Imagine the following scenario: Months after you created your app, you get a change request, that requires you to change a certain object at one point. Chances are, that other components might be dependent on this object and are now breaking, because of your change. You won’t know if it actually broke something, until you clicked through your whole app. And with “whole app”, I mean each possible combination of components was rendered. Or … you could just hope that nothing else depends on the object you changed.

Sounds like a lot of fun, heh?

You can avoid the necessity of clicking through all possible paths of your app. To do so, we can add basic component tests for each of your components.

To do so, you have to create mock objects for everything you pass down the props of the component. Then you simply render it with ReactDOM inside a Jest test, and if it can’t be rendered for some reason, the test will fail.

import React from "react"; import ReactDOM from "react-dom"; import ContactDetailView from "./ContactDetailView"; const dummyFunc = () =\> {}; const dummy = { id: 1, firstName: "Max", lastName: "Mustermann", street: "Duck Creek Road", house: 2561, zip: 94107, city: "San Francisco", phone: "650-795-0470", email: "max.mustermann@internet.com" }; test("ContactDetailView rendered correctly", () =\> { const div = document.createElement("div"); ReactDOM.render( \<ContactDetailView contact={dummy} onDelete={dummyFunc} onEdit={dummyFunc} /\>, div ); });

“But how would I notice that my app breaks from a changed object, if I always pass a correct object in the test?” – You might think right now.

You’re right. The above example renders a component and it’s child components. It only covers errors caused by changes that were made to the component or it’s children. However, if you change the props of a component, you also have to update the tests of this component. So if some child components depend on your changed object that was passed down through props, this test won’t pass, unless you fixed all the child components. As you can see, this small test might save you some hours bug fixing.

Add Basic Jest Snapshot Tests

Snapshot tests are a powerful tool to exactly compare the rendered markup with a previously saved snapshot.

Let’s have a look how we can create a snapshot for our ContactDetailView

import React from "react"; import ContactDetailView from "./ContactDetailView"; import renderer from "react-test-renderer"; const dummyFunc = () =\> {}; const dummy = { [... cropped for brevity ...] }; test("ContactDetailView matches the Snapshot", () =\> { const component = renderer.create( \<ContactDetailView contact={dummy} onDelete={dummyFunc} onEdit={dummyFunc} /\> ); let tree = component.toJSON(); expect(tree).toMatchSnapshot(); });

As you can see, we first render our component with renderer.create. The first run will create a new snapshot, file that contains the exact markup of the rendered component. Now each time the test is executed, it compares the rendered markup with the snapshot.

Snapshots are a good way to perform a very detailed check, if something in your components changed. This is especially useful to test presentational components.

However, there are caveats: Each time you change the component, you will have to generate a new snapshot by running jest -u to overwrite the existing snapshot. At this point it’s necessary to manually check how the markup has changed and if it’s really correct. You really don’t want your test to run against an incorrect snapshot. Usually you should check the snapshot before committing the file.

Note: Snapshot tests are worth nothing if you don’t take the time to manually check the changes in your snapshot files.

Wrapping Up

Congratulations to your new skill! You just learned three ways to add basic unit tests to test presentational components for your React components.

  • Testing Conditional Rendering
  • Basic Component Tests
  • Basic Snapshot Testing

As mentioned in the beginning of this post, there are a lot more ways to test your components in detail. However, if you’re concerned about the necessary time effort to add testing to your app, those three approaches are a quick way to reduce the risk of adding new bugs.

Did you like this post? Subscribe to my newsletter and get more like that delivered directly to your inbox.

Posted on by:

a_reiterer profile

Andreas Reiterer

@a_reiterer

I'm a full-time App/Software Developer who does some Freelancing on the side. I focus mainly on React / React Native and their eco systems.

Discussion

pic
Editor guide