Red, Green, Refactor: Refactoring an action list unit test in Redux

Red, Green, Refactor is a famous test-driven development mantra, where red means to write a failing test first and green means write code to make the failing test pass.

Having an actions list is an important part of reducing the boilerplate needed in Redux. It helps keep your naming convention consistent since all the actions are located in one place. Something very important when you have a lot of collaborators working on a large project.

So let’s assume that your Redux-enhanced application already has a list of actions and each action already has a test for it.

Why are these tests important? It’s because you want to make sure that when you use CREATE_TODO that the action that you see logged is also called CREATE_TODO and not something else. You don’t want to be calling UPDATE_TODO and then have it appear as DELETE_TODO in your logger. Right? Exactly.

However, this can get very repetitive. And you can probably see where I’m going with this especially after line 12. If you need 100 actions, then you’ll need to write 100 tests. One for each action that you add.

So let’s take a step back and ask ourselves what do we really want to test…

  • Is our action list immutable?
  • Does each action have the same key and value?

Time to refactor our test

When we refactor our test we want to make sure that it still tests the behaviours that we want.

Our first refactor session is us removing the copy/paste behaviour to reduce test boilerplate and reduce the risk of forgetting to update the test description.

This happens a lot when you forget to take a double take on your tests.

By iterating over the actionsToTest array, we can also use it for writing our test descriptions through JavaScript template literals. Now each test description is correct.

So far so good then. But what if we have someone else add an action without writing a test first?

If we stick to our first refactor, then this test will still pass. So how do we prevent people from adding a new action first without testing it? Or at least making sure that each action added is tested?

The second refactor session is us removing the use of forEach and instead use a deep compare of the array against the object.

Now you have a guard against untested actions. But this is also a problem in itself because of this possible error.

Since we’re comparing the object values of actions against the object values of actionsToTest then as long as they look the same the test will pass.

So how do we fix this? By testing the object keys from actions against the object values of actionsToTest.

One thing to note though is that this is possible with the help of another tool — ESLint’s plugin eslint-plugin-sorting which lets you sort your object properties alphabetically.

Not only do you have a unit test that will test the following.

  • Is your action list immutable?
  • Does each action have the same key and value?
  • Is each action tested?

But you also have a unit test that scales.