Testing a thunk

Because the getSpeakersSuccess action is intended to be the resulting action of a successful service call, we need a special kind of action to represent the service call itself. Redux does not inherently support asynchronous actions, as stated before. So, we need some other way to accomplish communication with the backend. Thankfully, Redux does support middleware and much middleware has been designed to add asynchronous capability to Redux. We are going to use redux-thunk for simplicity.

To start the next test, we need to first import redux-thunk and redux-mock-store to our speaker action tests.

import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';

Then we can test the getting speakers.

describe('Async Actions', () => {
describe('Get Speakers', () => {
it('exists', () => {
expect(speakerActions.getSpeakers).to.exist;
});
});
});

As usual, we start with a test for existence. And, as usual, it is fairly easy to make this test pass. In the speaker actions file, add a definition for the getSpeakers function and export it.

export function getSpeakers() {
}

The next test is slightly more complicated than the tests we have been working on, so we will explain it in rather more detail.

The first thing we will need to do is configure a mock store and add the thunk middleware. We need to do this because to properly test a thunk we will have to pretend that Redux is actually running so that we can dispatch our new action and retrieve the results. So, let's add our mock store configuration to the Async Actions describe:

const middleware = [thunk];
let mockStore;

beforeEach(() => {
mockStore = configureMockStore(middleware);
});

Now that we have a store available to us, we are ready to begin writing the test.

it('creates GET_SPEAKERS_SUCCESS when loading speakers', () => {
// arrange
const speaker = {
id: 'test-speaker',
firstName: 'Test',
lastName: 'Speaker'
};

const expectedActions = speakerActions.getSpeakersSuccess([speaker]);
const store = mockStore({
speakers: []
});

In the arrange, we are configuring a bare minimum speaker. Then, we call the action we previously tested to build the proper data structure. Finally, we define a mock store and its initial state.

  // act
return store.dispatch(speakerActions.getSpeakers()).then(() => {
const actions = store.getActions();

// assert
expect(actions[0].type).to.equal(types.GET_SPEAKERS_SUCCESS);
});
});

Now, when testing asynchronously in Mocha, we can return a promise and Mocha will automatically know that test is asynchronous. Our assertions, for asynchronous tests, go in the resolve or the reject function of the promise. In the case of the get speaker action, we are going to assume a successful server interaction and test the resolved promise.

Because we are not returning anything from our getSpeakers action, the mockStore throws an error stating that the action may not be an undefined. To move the test forward, we must return something. To move in the direction of using a thunk, we need to return a function.

export function getSpeakers() {
return function(dispatch) {
};
};

Adding the return of a function that does nothing else moves the test failure message forward and now presents us with a failure to read the property then of undefined. So, now we need to return a promise from our action. We already have the service endpoint built in the mock API service, so let's call that now.

export function getSpeakers() {
return function(dispatch) {
return new MockSpeakerService().getAll().then(speakers => {
dispatch(getSpeakersSuccess(speakers))
}).catch(err => {
throw(err);
});
};
}

Now the test passes and we have written our first test dealing with thunks. As you can see, both the test and the code to pass the test are fairly easy to write.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.11.226