The React-Redux API makes this separation of concerns effortless; Write presentational components, and use the React-Redux
connect()
function to generate the container components that connect presentational components to the store. But we’re getting ahead of ourselves…

Before we can connect components, we must provide the application with a Redux store. The React-Redux
<Provider> component
wraps the application’s root component, and bestows magical access to the store on all nested components*:

Because connect() returns a new (connected) component, the unwrapped (presentational) component is still available, unmodified, to us.
We’re exporting this as well as the default connected component, as it can be easier to test components when they’re free of the
Redux dependency.

We’ll look at two unit tests. The second test will check the onClick handler. Passing the handler in
via the props object makes it easy to get hold of in tests.

A Quick Note About Extracting Actions

It’s a common pattern in Redux to extract actions from components, and
list action creators (pure functions that return an action object)
together for easy reference, e.g.:

constpubFooButtonClick=()=>({type:'FOO_BUTTON_CLICK'});

Jest With Enzyme

I’m using Jest with
Enzyme’s shallow rendering. Shallow rendering means a component’s tests still
pass when its children fail / change. This isolation helpfully narrows the field for bug hunting.

Test #1: Snapshot Testing

Snapshot tests flag changes to a component. Perhaps you want the change,
in which case, no problem, just update the snapshot. Otherwise, there’s something to fix.

Unlike test-driven development (TDD), the snapshot approach is code first and test second. The first time a snapshot test runs,
it saves a representation of the tested component to a snapshot file. Later executions compare the current shape to the saved shape.

Connected components rely on the Redux store being there. For this reason, it’s easier (and so common) to snapshot test the unwrapped component,
manually passing in the props it requires*:

Because calling toString() on a function yields inconsistent results, snapshots record function placement but nothing more.
Make what changes we like to the onClick handler (save deleting it), and the snapshot test will continue to heedlessly pass.

Test #2: Testing Functionality

Is this necessary? Maybe, maybe not. Is this trivial? Yes! Because we passed our handler in as a prop, it’s easy to get hold of. And while we
now need to handle the Redux dependency (since we’re testing the connected component), this too can be plain sailing.

If we export a function that handles the store setup and returns an instance of the store, rather than export the store itself, it’s as easy as this*:

Conclusion

TDD is the development process that might’ve brought you up properly with attention to discipline, but the ease of snapshot
testing might encourage a more comprehensive testing habit in more of us.

It takes a minimal amount of code to identify when a component changes, perhaps unexpectedly. There’s something to be said for
waiting until a component is somewhat stable before writing a snapshot test for it. Otherwise mechanically updating snapshot
files without proper scrutiny (to check changes are wanted) might become as inevitable as writing tests all at once,
just before pushing to production.

Should you favour unit testing React components, traditional unit tests still add value; The second test checked the proper
operation of an event handler.

Both tests were cheap - quick to implement and fast to run - and their simplicity should mean they won’t cause any headaches
down the line.

(Connected) React components: (How) do you test yours?

Subscribe to our mailing list

Name *

Email Address *

Never miss a post from toniandO...

Toni and O: Solving coding problems as a dynamic duo. Short posts on AWS, JavaScript, Go(lang) and serverless architecture.