Redux TDD: a deep dive

Luca Matteis
HackerNoon.com
5 min readOct 25, 2017

--

This is a description of the redux-tdd project and how its API works. If you’re looking for a more high-level explanation of test-driven development with redux, please check out my freeCodeCamp article.

Redux TDD is a simple library that let’s you test React components along with the Redux data-flow in a test-driven development (TDD) fashion.

After several iterations of the API, I came up with a simple abstraction that concentrates less on the implementation details of your components or state, and more on the actions dispatched and the props your components should receive:

In this piece of code above we are shallow rendering (from enzyme) the Counter component, and passing it props which are mapped to a specific part of the state.

The counter prop is mapped to the state value state.counter.count. The state => [] function acts in fact not only as our render function, but also as our mapStateToProps function.

As first argument reduxTdd takes our reducers and therefore the shape of our state.

Next we call .action(props => props.onClick()) which is where the magic happens. Anything returned by the callback passed to the action operator will essentially be dispatched (even though we’re not using redux’s dispatch — more on this later).

The action operator will therefore update the internal state and also update the props of our components based on such new state.

toMatchProps and contains simply check at this point that our component receive the correct values after the action has been dispatched.

TodoList example

In the next example we’ll try to implement a simple TodoList in a TDD fashion — what else 😄?

We start with simply passing our not-yet-existing TodoList component to reduxTdd:

Our list items will probably live in state, so let’s go ahead next and introduce a list reducer, and pass that along to our component as a prop called “listItems”.

Running this will of course fail, since nothing is yet implemented, but let’s write more tests before implementing our logic.

A todo-list is meant to have an input-box where you add todos so let’s also add an AddTodo component (remember we’re returning an array so we can test multiple components):

Great now let’s continue the dot-chaining from the above example and actually simulate the addition of a todo by calling the onAdd action creator:

So next we should be seeing the “clean house” todo in the TodoList, right? Let’s test that:

We can even add another todo:

Great that’s enough for now, let’s run this code and start implementing our components, reducers and actions:

(hint: the text-input logic is purposely left out of AddTodo)

Our addTodo action:

And finally our reducer:

If we run our code again some things will fail:

This is because our state.list is an object, but the listItems prop expects an array. Let’s fix that using a selector (you can even use reselect if you want) ❤️

In our initial reduxTdd definition let’s change the way state maps to props for our TodoList component:

And the selector:

Now if we run our tests again we get:

🎉

Let’s also TDD the idea of “setting a todo item as complete”.

For this I’m thinking there should be a TodoItem component that is clickable right? Let’s add it to our initial list:

But there’s a problem! The TodoItem must know which item it must complete. And it must work with a single item, but in our state we keep an object! To solve this we can simply pass a single item from our state.list object:

Next we mark it as complete:

At this point we realize that our TodoList component has no way of showing whether the item is complete or not (there should be a striked line over it). So we pass a new “completedItems” prop which is an array of the items that are complete:

And we change again our definition to work for such behavior:

If we run our tests, they tell us some things need to be implemented like our completeTodo action creator:

And we update our reducer accordingly:

Again running our tests will tell us our getCompletedItems is missing:

And we’re done!

We can go further and use other operators like contains and view to test more fine-grained parts of our UI. But the main parts of our app have been implemented step-by-step in a TDD way.

More importantly we didn’t have to come up with intricate engineering decisions about our state or our props beforehand. We implemented them as we went ahead and as we saw the need.

I hope these examples helped you understand the idea behind Redux TDD and how you can use it for your own projects. To look at more complex examples please have a look at the tests/ folder inside the repo. You’ll find another important operator called epic which can be used to test async behavior!

Thanks and happy TDD 🤗

--

--