Testing Redux Selectors with resultFunc
Tags: testing, redux, react
Published: 2022-01-12 15:16:28

Over the years, as I've been using Redux, I've tried quite a few different forms of testing. Actions, reducers, sagas, selectors, some with more boiler plate results than others. One of the evolutions of testing that I've enjoyed the most has been with the library I use for selectors, [reselect](https://github.com/reduxjs/reselect).

When I initially started testing selectors, I was mocking out entire state trees.  This is pretty simple when your selector is interacting with a tiny subset of state, but can be much more difficult as your state tree grows.

In this example, I have a simple selector I'm using to turn an array of strings into an array of objects with a value & label.

```
import { createSelector } from 'reselect'
import map from 'lodash/map'
import { selectToDoListItems } from '.'

const selectFormattedToDoListItems = createSelector(
  selectToDoListItems, // state.todo.items
  items => map(items, item => ({
    label: item.toUpperCase(),
    value: item,
  })),
)

export default selectFormattedToDoListItems
```

So how can I go about testing this?


## Option 1 -- Testing via state tree
Since I know that the selector `selectToDoListItems` is pulling from `state.todo.items`, I can mock out what my relevant state tree looks like, and pass this into the function.

```
const state = {
      todo: {
        items: [
          'write blog post',
          'walk dog',
          'take out trash',
        ],
      },
    }
```

We then write out our expected result from this selector and test it.  The entire block looks something like this: 
```
import selectFormattedToDoListItems from '../selectFormattedToDoListItems'

describe('selectFormattedToDoListItems', () => {
  it('returns the items from a todo list', () => {
    const state = {
      todo: {
        items: [
          'write blog post',
          'walk dog',
          'take out trash',
        ],
      },
    }
    const expectedOutput = [
      {
        label: 'WRITE BLOG POST',
        value: 'write blog post',
      },
      {
        label: 'WALK DOG',
        value: 'walk dog',
      },
      {
        label: 'TAKE OUT TRASH',
        value: 'take out trash',
      },
    ]

    expect(selectFormattedToDoListItems(state)).toEqual(expectedOutput)
  })
})
```

This can be a simple solution for a small state tree, but if your state tree is large or your selector is utilizing many other complex selectors, managing a mock version of your state tree can be frustrating and brittle.


## An Alternative -- `resultFunc`
The pattern I have gravitated towards over the last couple of years is using reselect's built in testing option `resultFunc`.  Utilizing this function, we can pass in _exactly_ the data format we are looking for.  No matter if we are using a selector that has manipulated our state tree, we can simply mock out exactly what the inputs of our selector will look like.  Using our above test as an example, updating it to use `resultFunc` looks as follows:

```
it('returns the items from a todo list using resultFunc', () => {
    const items = [
      'write blog post',
      'walk dog',
      'take out trash',
    ]
    const expectedOutput = [
      {
        label: 'WRITE BLOG POST',
        value: 'write blog post',
      },
      {
        label: 'WALK DOG',
        value: 'walk dog',
      },
      {
        label: 'TAKE OUT TRASH',
        value: 'take out trash',
      },
    ]

    expect(selectFormattedToDoListItems.resultFunc(items)).toEqual(expectedOutput)
  })
  ```

  Notice the change in the parameter of the `expect` statement.  This cuts down on our need to mock out the state tree exactly as designed, since we can instead pass in a replica of the relevant data.


## The bottom line
  Ultimately, these are both viable ways of testing selectors.  Where I find `resultFunc` to be especially useful is in cases where the selector I am testing is utilizing other selectors that manipulate data in a way that would require the mock data I create to effectively reimplement the adjacent selectors.  In future articles, I will demonstrate this via more expansive examples.

  Thanks for reading out my article, and if you are inclined, check out my favorite Git client [GitKraken](https://www.gitkraken.com/invite/62u1vDsC)! Use this link for a chance to win a $100 Amazon gift card :)