Vanja's Blog

Subscribe to Blog via Email


Enter your email address to subscribe and receive notifications of new posts by email.

Social


Recent Posts


Top Posts & Pages


Categories


Tags


Share


Testing React-Redux

KISS approach to React-Redux testing.

Vanja PetreskiVanja Petreski

Everything should be made as simple as possible, but not simpler.

~ Albert Einstein

I prefer to apply KISS Principle when solving problems, so the same goes for testing React-Redux apps.

I am building testing upon my Idiomatic Redux article and app. Here you can find React Countries app with tests included that I will be referring. After spending some time reading, thinking and trying different approaches I came to relatively simple, but efficient testing strategy. My goal was not to have near 100% test coverage, but to test what really matters without using too much resources (time, energy) and complex solutions.

The App

Testing described in this article has in mind following app setup/configuration:

Although I am sure it can be adjusted for other setups.

What (not) to Test

This is one of the most important questions – what to test and, more importantly, what not to test. My approach is to focus mostly on unit testing and some functional testing. Integration, E2E and complex interaction testing is completely skipped and left for QA team 😛

We will test:

We will NOT test:

Reasoning behind this decision is this:

Tools

There are many different tools and options out there, I did some investigation and this is my weapon of choice:

These tools are powerful and in this article I am not explaining all possible usages, refer to corresponding docs for more details. Fire this one-liner to install everything you need:

npm i -D react-test-renderer @types/jasmine react-addons-test-utils enzyme enzyme-adapter-react-16 redux-mock-store nock

There are also some other tools that I had to install and configure to make everything smooth:

Tests Organization

Jest is searching for __tests__ folders in your project tree and will run all files/tests from there. So for example – if I am testing reducers, I will create reducers/__tests__/my-reducer.test.js. I like this filename convention, but you can use anything else.

Testing Dumb Components

Let’s test our first presentational component. Check file src/components/__tests__/Toolbar.test.js and notice imports, Enzyme configuration/adapter and 3 tests we have:

  1. Component actually renders – this is our first test and we are using shallow function from Enzyme to render only light/shallow RcToolbar component without any children. Enzyme has jQuery like syntax, so it’s really easy to find what you need and assert.
  2. Here I am checking that Add button has “+” icon from Material UI. I am using mount function here and not shallow because I need to access child component to make assert.
  3. In the last test I am checking if toggle button/filter is turned on by default.

Other good example would be to test if RcList component renders N li elements when I pass N countries.

So we are making minimalistic tests for presentational components – do they render and show what they need to show.

Testing Reducers

Now open src/reducers/__tests__/countries.test.js. Country reducer is combined reducer for using normalized state, so we are testing both byId and list reducers here.

Testing reducers is really straightforward because they are pure functions. For the given input, we expect always the same output. In my example we are checking if country add success will result in state that contains newly added country.

Notice that we are using addCountrySuccess action creator inside the test, that’s why we don’t have to explicitly test simple action creators. Refactor your code, so that you can use these action creators in both code and tests, if you already don’t have them.

Testing Thunk Action Creators

It’s important to test thunk / async action creators to make sure that we have proper simple actions dispatched after promise has been resolved. Open src/actions/__tests__/actions.test.js. First thing you will notice is that we are using redux-mock-store library to mock Redux store. We are also adding thunk middleware to it. Mocking HTTP request (using Nock library) since adding a country will result in remote API call and we don’t want that in the test. We are then simply dispatching thunk action and when done checking if all expected actions have been dispatched. In this specific case we expect that adding a country will result in success event, closed dialog and a message.

Testing Utils

I don’t have any utility/common code in the project, but these should be fully tested, as they are usually pure functions.

Local Testing

It’s time to run our tests locally with npm test. It’s configured to run only newly added/changed tests from the last commit (more details here). There is also interactive mode allowing you to press “a” to run all tests anyway. This doesn’t work well in Webstorm when npm test is invoked from UI, so just use terminal if you want interactive mode.

CI

I am using Travis and if you check travis configuration file you will see that one new line has been added to enable CI testing. NPM testing will be invoked on every commit.

Outro

Testing topic is really complex and there are many possible options, but I think this approach is relatively simple and tests the core of React-Redux app – reducers, actions and presentational components. In combination with QA team, this can be good testing strategy 😉

Software Engineer & Digital Nomad

Comments 0
There are currently no comments.