The Get Speaker reducer

To handle the actions related to getting a speaker, we must create two reducers. The first reducer is extremely similar to the reducer we made for the get speakers actions. The second is going to need to be slightly different and is for handling the error case.

Let's begin with the simplest of the two and create the speaker reducer.

describe('Speaker Reducer', () => {
it('exists', () => {
expect(speakerReducer).to.exist;
});
});

Our typical existence test is easily passed.

export function speakerReducer() {
}

The next test ensures that the reducer updates state properly, and will close out the tests needed for this reducer.

it('gets a speaker', () => {
// arrange
const initialState = { id: '', firstName: '', lastName: '' };
const speaker = { id: 'test-speaker', firstName: 'Test', lastName: 'Speaker'};
const action = actions.getSpeakerSuccess(speaker);

// act
const newState = speakerReducer(initialState, action);

// assert
expect(newState).to.deep.equal(speaker);
});

The changes from this test are the inputs to the reducer, and the output of a state. Let's make this test pass by modeling our reducer after the speakers reducer.

export function speakerReducer(state = { 
id: '',
firstName: '',
lastName: ''
}, action) {
switch(action.type) {
case types.GET_SPEAKER_SUCCESS:
return action.speaker;
default:
return state;
}
}

Similar to the speakers reducer, this reducer simply checks the action type for GET_SPEAKER_SUCCESS and, if found, returns the speaker attached to the action as the new state. Otherwise, we just return the state object we received.

Next up, we need an error reducer.

describe('Error Reducer', () => {
it('exists', () => {
expect(errorReducer).to.exist;
});
});

Passing this test is just as easy as all the other existence tests.

import * as types from './actionTypes';
import * as errors from './errorTypes';

export function errorReducer() {
}

The error reducer will have some interesting functionality. In the event that an error is received, we want multiple errors to stack up so we won't be replacing the state. Instead, we will be cloning and adding to the state. However, when an action is received that is not an error we will want to clear the errors and allow normal program execution to continue. We will also want to ignore duplicate errors. First, we will handle the error we know about.

it('returns error state', () => {
// arrange
const initialState = [];
const error = { type: errorTypes.SPEAKER_NOT_FOUND };
const action = actions.getSpeakerFailure(error);

// act
const newState = errorReducer(initialState, action);

// assert
expect(newState).to.deep.equal([error]);
});

Our test is slightly different from the previous reducer test. The main difference is that we are wrapping our expected value in an array. We are doing this to meet the need for having multiple errors potentially stack up and display for the user.

To make this test pass we follow the familiar reducer pattern we have been using.

export function errorReducer(state = [], action) {
switch(action.type) {
case types.GET_SPEAKER_FAILURE:
return [...state, action.error];
default:
return state;
}
}

For the same reasons as stated previously, notice how we use the rest of the parameter syntax to spread the existing state into a new array, effectively cloning state.

We have two more tests for the error reducer; the first is to ensure duplicate errors are not added. The second test will be to clear the errors when a non-error action is called.

it('ignores duplicate errors', () => {
// arrange
const error = { type: errorTypes.SPEAKER_NOT_FOUND };
const initialState = [error];
const action = actions.getSpeakerFailure(error);

// act
const newState = errorReducer(initialState, action);

// assert
expect(newState).to.deep.equal([error]);
});

In the test, to set the condition of having a prepopulated state, all we had to do was modify the initialState parameter.

export function errorReducer(state = [], action) {
switch(action.type) {
case types.GET_SPEAKER_FAILURE:
let newState = [...state];

if(newState.every(x => x.type !== action.error.type)) {
newState.push(action.error);
}

return newState;
default:
return state;
}
}

All we must do to make this test pass is to make sure that the error type is not already present in the state array. There are many ways to do this; we have chosen to use the every function as a check that none of the existing errors match. It is likely that this method is not extremely performant, but there should only be a couple errors at most so it shouldn't be a performance issue.

The next test is to clear the error state when a non-error is received.

it('clears when a non-error action is received', () => {
// arrange
const error = { type: errorTypes.SPEAKER_NOT_FOUND };
const initialState = [error];
const action = { type: 'ANY_NON_ERROR' };

// act
const newState = errorReducer(initialState, action);

// assert
expect(newState).to.deep.equal([]);
});

Making this test pass is exceedingly simple. All we have to do is replace the default functionality where the existing state is returned.

default:
return [];
..................Content has been hidden....................

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