Test Utilities
testReducer
NOTE: This example uses Jest. We also use a feature called snapshot testing.
Standard example:
import { testReducer } from "@malfaitrobin/redux-test-utils";
import reducer from "./reducer";
import * as actionCreators from "./actionCreators";
const calculator = testReducer(reducer);
describe("calculator", () => {
it("should be able to calculate the universe", () => {
const actions = [
actionCreators.add(20),
actionCreators.multiply(3),
actionCreators.subtract(18)
];
expect(calculator(actions)).toMatchSnapshot();
});
});
The result of the snapshot will have the initial state Followed by the action followed by the state and so on. The snapshot will eventually look something like this:
Array [
State {
"value": 0,
},
Action {
"payload": 20,
"type": "ADD",
},
State {
"value": 20,
},
Action {
"payload": 3,
"type": "MULTIPLY",
},
State {
"value": 60,
},
Action {
"payload": 18,
"type": "SUBTRACT",
},
State {
"value": 42,
},
]
Overriding the current state before testing
Let's say that the default state from the reducer looks like
{ value: 0 }
, but now you want to test themultiply
function. Since multiplying by 0 is a no-op, we can override the "initial" value.
import { testReducer } from "@malfaitrobin/redux-test-utils";
import reducer from "./reducer";
import * as actionCreators from "./actionCreators";
const calculator = testReducer(reducer);
describe("calculator", () => {
it("should be able to calculate the universe", () => {
const actions = [actionCreators.multiply(3)];
expect(
calculator(actions, {
value: 14
})
).toMatchSnapshot();
});
});
Normally the snapshot would have looked like this:
Array [
State {
"value": 0,
},
Action {
"payload": 3,
"type": "MULTIPLY",
},
State {
"value": 0,
},
]
But since we provided a default "initial" value, the snapshot looks like this:
Array [
State {
"value": 14,
},
Action {
"payload": 3,
"type": "MULTIPLY",
},
State {
"value": 42,
},
]
Using testReducer to also test the selectors
- A reducer always operates on its part of the state
- A selector retrieves information from the full state in the application
// selectors.js
export function getCurrentValue(state) {
return state.applications.calculator.value;
}
import { testReducer } from "@malfaitrobin/redux-test-utils";
import reducer from "./reducer";
import * as actionCreators from "./actionCreators";
import * as selectors from "./selectors";
// We can mimic the "full" state, which will be used by selectors
const calculator = testReducer(reducer, state => {
return {
applications: {
calculator: state
}
};
});
describe("calculator", () => {
it("should be to retrieve the current value", () => {
const actions = [
actionCreators.add(20),
actionCreators.multiply(3),
actionCreators.subtract(18)
];
// A final `state` object can be retrieved from the reducer
const { state } = calculator(actions);
// Now the selector can operate on the "full state"
expect(selectors.getCurrentValue(state)).toMatchSnapshot();
});
});