Reputation: 9447
I am writing test cases for my application bases on react and redux.
container = TestUtils.renderIntoDocument(
<Provider store={createStore({"key": "old_val"})}>
{() => <Component />}
</Provider>
);
After rendering with initialState
, I dispatch an action and see if the state changes.
Component.store.dispatch({ type: 'SET_VAL', value: 'some_val' });
Then I print the state
console.log(store.getState());
I expect the state to be {"key": "some_val"}
. However, it still shows {"key": "old_val"}
.
The application works fine, just not the test, so there can't be any problem with my action-creators
or reducers
.
Am I doing something wrong here? Btw, I am using thunk
middleware for async action dispatch. Does that interfere here? If yes, how do I wait till the async action gets completed?
Update:
The redux tests shown here are pretty straightforward, yet they seem to work fine.
store.dispatch(addTodo('Hello'));
expect(store.getState()).toEqual([{
id: 1,
text: 'Hello'
}]);
Upvotes: 8
Views: 5680
Reputation: 1207
One of the huge benefits of redux is that it allows you to implement almost all of your application using pure functions and pure components. Redux and react-redux abstract the implementation details of subscribing UI to state changes which allows you to test all of your app's code in isolation. This way you don't need to render out a provider with a store every time you want to test out your code, which is a major reduction in complexity.
Let's say you have a key
property in your state and a KeyDisplay
component. You can implement the state with the following reducer file:
reducers.js
import { combineReducers } from 'redux';
export function key(state, { type, value }) {
switch(type) {
case 'SET_VAL': return value;
default: return state;
}
}
export default combineReducers({ key });
And you can set up a file for our component:
KeyDisplay.js
import React from 'react';
import { connect } from 'react-redux';
export function KeyDisplay({ keyProp }) {
return (
<div>The key is {keyProp}</div>
);
}
export default connect((state) => { keyProp: state.key })(KeyDisplay);
Then in the unit test for the reduce you can import just the reducer for key
and test it totally separate of the user interface:
keyReducer.test.js
import test from 'tape';
import { key } from './reducers.js';
test('key reducer', (t) => {
t.plan(1);
const output = key('old', { type: 'SET_VAL', value: 'new' });
t.equal(output, 'new', 'SET_VAL should override old value');
});
Additionally, since connect
passes state as props into the component you can just render the unconnect
ed component with some test props that represent a state you are interested in, again without setting up a store and provider:
KeyDisplay.test.js
import test from 'tape';
import { renderIntoDocument } from 'react-addons-test-utils';
import { KeyDisplay } from './KeyDisplay.js';
test('KeyDisplay', (t) => {
const component = renderIntoDocument(<KeyDisplay keyProp="test" />);
// test component
});
Upvotes: 7