A Guide to Testing React Components
React is a framework that has made headway within the JavaScript developer community. React has a powerful composition framework for designing components. React components are bits of reusable code you can wield in your web application.
React components are not tightly coupled from the DOM, but how easy are they to unit test? In this take, let’s explore what it takes to unit test React components. I’ll show the thought process for making your components testable.
Keep in mind, I’m only talking about unit tests, which are a special kind of test. (For more on the different kinds of tests, I recommend you read “JavaScript Testing: Unit vs Functional vs Integration Tests”.)
With unit tests, I’m interested in two things: rapid and neck-breaking feedback. With this, I can iterate through changes with a high degree of confidence and code quality. This gives you a level of reassurance that your React components will not land dead on the browser. Being capable of getting good feedback at a rapid rate gives you a competitive edge — one that you’ll want to keep in today’s world of agile software development.
For the demo, let’s do a list of the great apes, which is filterable through a checkbox. You can find the entire codebase on GitHub. For the sake of brevity, I’ll show only the code samples that are of interest. This article assumes a working level of knowledge with React components.
If you go download and run the demo sample code, you’ll see a page like this:
Write Testable Components
In React, a good approach is to start with a hierarchy of components. The single responsibility principle comes to mind when building each individual component. React components use object composition and relationships.
For the list of the great apes, for example, I have this approach:
FilterableGreatApeList
|_ GreatApeSearchBar
|_ GreatApeList
|_ GreatApeRow
Take a look at how a great ape list has many great ape rows with data. React components make use of this composition data model, and it’s also testable.
In React components, avoid using inheritance to build reusable components. If you come from a classic object-oriented programming background, keep this in mind. React components don’t know their children ahead of time. Testing components that descend from a long chain of ancestors can be a nightmare.
I’ll let you explore the FilterableGreatApeList
on your own. It’s a React component with two separate components that are of interest here. Feel free to explore the unit tests that come with it, too.
To build a testable GreatApeSearchBar
, for example, do this:
class GreatApeSearchBar extends Component {
constructor(props) {
super(props);
this.handleShowExtantOnlyChange = this.handleShowExtantOnlyChange.bind(this);
}
handleShowExtantOnlyChange(e) {
this.props.onShowExtantOnlyInput(e.target.checked);
}
render() {
return(
<form>
<input
id="GreatApeSearchBar-showExtantOnly"
type="checkbox"
checked={this.props.showExtantOnly}
onChange={this.handleShowExtantOnlyChange}
/>
<label htmlFor="GreatApeSearchBar-showExtantOnly">Only show extant species</label>
</form>
);
}
}
This component has a checkbox with a label and wires up a click event. This approach may already be all too familiar to you, which is a very good thing.
Note that with React, testable components come for free, straight out of the box. There’s nothing special here — an event handler, JSX, and a render method.
The next React component in the hierarchy is the GreatApeList
, and it looks like this:
class GreatApeList extends Component {
render() {
let rows = [];
this.props.apes.forEach((ape) => {
if (!this.props.showExtantOnly) {
rows.push(<GreatApeRow key={ape.name} ape={ape} />);
return;
}
if (ape.isExtant) {
rows.push(<GreatApeRow key={ape.name} ape={ape} />);
}
});
return (
<div>
{rows}
</div>
);
}
}
It’s a React component that has the GreatApeRow
component and it’s using object composition. This is React’s most powerful composition model at work. Note the lack of inheritance when you build reusable yet testable components.
In programming, object composition is a design pattern that enables data-driven elements. To think of it another way, a GreatApeList
has many GreatApeRow
objects. It’s this relationship between UI components that drives the design. React components have this mindset built in. This way of looking at UI elements allows you to write some nice unit tests.
Here, you check for the this.props.showExtantOnly
flag that comes from the checkbox. This showExtantOnly
property gets set through the event handler in GreatApeSearchBar
.
For unit tests, how do you unit test React components that depend on other components? How about components intertwined with each other? These are great questions to keep in mind as we get into testing soon. React components may yet have secrets one can unlock.
For now, let’s look at the GreatApeRow
, which houses the great ape data:
class GreatApeRow extends Component {
render() {
return (
<div>
<img
className="GreatApeRow-image"
src={this.props.ape.image}
alt={this.props.ape.name}
/>
<p className="GreatApeRow-detail">
<b>Species:</b> {this.props.ape.name}
</p>
<p className="GreatApeRow-detail">
<b>Age:</b> {this.props.ape.age}
</p>
</div>
);
}
}
With React components, it’s practical to isolate each UI element with a laser focus on a single concern. This has key advantages when it comes to unit testing. As long as you stick to this design pattern, you’ll find it seamless to write unit tests.
Continue reading %A Guide to Testing React Components%
LEAVE A REPLY
You must be logged in to post a comment.