Testing Async Redux Actions: Moxios + Redux-mock-store

How do we test asynchronous actions? The ones that depends on a API call that may or may not be resolved. This is what we are going to focus here: how to make sure your actions are called in order and how to intercept axios to not make actual API calls.

TL;DR: the complete code is in the end of the article!

Just to be clear this is what we are going to be using:

You are expected to know:

Let’s begin talking about our stack. Moxios is a testing utility created by Axios with the intent to mock our calls, so we don’t hit the server every time we run our tests. If you look at the documentation you will see that it works by intercepting the calls when they are made and mocking the response. Later we will see what are the necessary configurations for that!

Redux-mock-store is exactly what the name implies. Although it should not be used to mock an actual store to use in a Provider (to test connected components, see this and this). The goal of the library is to test actions and middlewares. The mocked store stores (no pun intended) the actions called in an array for you to compare to what you expect it to be.

So let’s get to it!

First things first, this is the action we are going to test: loginUser. It accepts userData as a parameter which returns a dispatch function (thunk) which returns the axios call. This is important: to return the axios call(a promise), we will see why later.

The step by step is commented in the code, but basically the action hits an API which returns an JWT Token (more about that here), that we store it locally. The token is set to every call header that axios make for now on, so we have authorized credentials. Then we decode the token using jwt_decode and dispatch the setCurrentUser action, that makes our user authenticated to our app. If any exceptions happen, we catch it and send a getErrors action. If the double arrow function confuses you check this.

If you haven’t done it yet, install every module necessary using npm or yarn: axios, moxios, redux-mock-store, redux-thunk

Now let’s get testing!

First we will need to configure our mockStore. A good idea is to create a Utils file (or helpers, or common, hard to decide…) to put your store configuration, so you don’t need to create it in every test file you make.

makeMockStore is a helper function that receives an object to be passed as initial state to our mockStore so it’s easy to set our state for different files and different tests.

So in our test file we will call it like this and pass our initial state

Now we are ready to begin our actual testing. Our frame of mind is: we need to test if the correct actions are called in the correct order. The reducer part should not be included in this testing, it should be tested in a separated reducer test file. So this is how our test file looks like

To make moxios work, you need to add the beforeEach and afterEach functions installing and unistalling for each test suite. Inside the test, you should declare the payload to send to your action (in this case it’s a user object) and specify what’s the response you expect from the API call. This is what moxios.wait() does: it waits for the API call your action sends, intercept it and mock the response with the passed information.

Moxios uses a status key to determine if it’s a successfull or failed call, and your expected response inside the response key.

When you use store.dispatch() it expects a promise back, that is why is necessary to return our axios call in our userAction, otherwise you will get an error

TypeError: Cannot read property ‘then’ of undefined

There are a few things you can do to optimize your tests and make it more elegant. This is our whole test file optimized. It tests both successful and failed API call and the actions called in each case.

You can see more about the redux-mock-store API in their github page, where maybe you’ll think about cleaning all your actions after each test with store.clearActions(), or check your mock store state with store.getState().

Redux-mock-store is also useful to test synchronous actions to make sure they are called, which you can also check out in their github page.

So that is it! I hope this helps you. See you in a next post!

Front End developer and UI designer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store