Writing tests for redux-observable
Tags: react, redux, reduxobservable
Published: 2017-09-24 23:46:49

---
title: Writing tests for redux-observable
published: true
description: Thoughts about testing epics defined created with redux-observable
tags: react, redux, redux-observable
---

I attended a talk about `redux-observable` recently and, having been playing with Rx and liking it, I decided to give it a try. I won't get into the details of how to use it, but I did spend some time figuring out a way to easily test my epics that I wanted to share.

Let's say that, for authenticating users of our app, we have an epic that looks like this:

```js
function loginEpic(action$) {
  return action$.ofType(LOGIN_START).mergeMap(action =>
    api
      .login(action.payload.email, action.payload.password)
      .map(loginSuccessful)
      .catch(err => Observable.of(loginFailed(err))),
  );
}
```

The epic takes our main stream of actions and for each `LOGIN_START` action, generates either an action with the `loginSuccessful` action creator, or one with the `loginFailed` action creator.

Here I see three things that deserve their own unit test:

* The proper API call is being made.
* We generate the success action if the login succeeded.
* We generate the error action if the login fails.

The rationale behind all of the tests is going to be the same: We'll create an observable with the LOGIN_START action and pass it to the epic, subscribe to it and assert on the actions generated. Let's take a look at the first one, to check the API call:

_I'm using Jest for the assertions and mocking here, but the same could be done with any other framework_

```js
it('logins through the api on LOGIN_START', (done) => {
  const email = 'test@test.com';
  const password = '123456';
  const action$ = ActionsObservable.from([login(email, password)]);

  api.login.mockImplementation(() => ActionsObservable.of({}));

  epic(action$)
    .subscribe(() => {
      expect(api.login).toHaveBeenCalledWith(email, password);
      done();
    });
});
```

A couple of things to note:

* The `login` function is the action creator that generates `LOGIN_START` actions. Since we have it already, it makes sense to use it.
* The API is implemented to return observables, so that's why the mock implementation returns one that simply emits an empty object (we don't really care about the response in this test)
* `api` is mocked with Jest's mock facilities outside this test, like this:

```
jest.mock('../lib/api', () => ({ login: jest.fn() }));
```

Other than that, we pass the action stream to the epic, we subscribe and then we expect that after the first action is generated then we should've called the API already with the right parameters. Let's take a look at the tests that check the generated actions:

```js
it('emits a LOGIN_SUCCESS action if the API call succeeds', (done) => {
  const action$ = ActionsObservable.from([login('test@test.com', '123456')]);
  const user = {};

  api.login.mockImplementation(() => ActionsObservable.of(user));

  epic(action$)
    .filter(action => action.type === LOGIN_SUCCESS)
    .subscribe((action) => {
      expect(action.payload).toBe(user);
      done();
    });
});

it('emits a LOGIN_FAILED action if the API call fails', (done) => {
  const action$ = ActionsObservable.from([login('test@test.com', '123456')]);
  const error = new Error();

  api.login.mockImplementation(() => ActionsObservable.throw(error));

  epic(action$)
    .filter(action => action.type === LOGIN_FAILED)
    .subscribe((action) => {
      expect(action.payload).toBe(error);
      done();
    });
});
```

The gist of it is that we filter the actions generated by the epic to ensure that we got the right type, and then when we subscribe we check that the payload of those actions are the right ones.

*Note*: I'm using `filter` instead of `ofType` like I would use to filter by action type inside an epic. This is because I can't be sure that the observable returned by the epic is going to be an `ActionsObservable` instead of a regular observable.

And that's it! I think this is a simple way to test epics. It might not be enough for more complicated cases, but personally I found it very simple and easy to reason about.