I am using Jest 0.4.0. I have a component wrapped into this (from react-router docs):
var stubRouterContext = (Component, props, stubs) => {
function RouterStub() { }
Object.assign(RouterStub, {
makePath () {},
makeHref () {},
transitionTo () {},
replaceWith () {},
goBack () {},
getCurrentPath () {},
getCurrentRoutes () {},
getCurrentPathname () {},
getCurrentParams () {},
getCurrentQuery () {},
isActive () {},
getRouteAtDepth() {},
setRouteComponentAtDepth() {}
}, stubs)
return React.createClass({
childContextTypes: {
router: React.PropTypes.func,
routeDepth: React.PropTypes.number
},
getChildContext () {
return {
router: RouterStub,
routeDepth: 0
};
},
render () {
return <Component {...props} />
}
});
};
My component uses componentWillUpdate
:
getInitialState: function(){
return {something: ""};
},
componentWillUpdate: function(nextProps, nextState) {
if(nextState.something === "12345"){
this.context.router.transitionTo("MyRoute", {id: nextState.something});
}
},
In my test:
var ComponentWrapper = stubRouterContext(MyComponent, {});
var myComponentInstance = TestUtils.renderIntoDocument(<ComponentWrapper />);
it('expects to do something on componentWillUpdate', function(){
myComponentInstance.setState({something: "12345"});
expect(myComponentInstance.getChildContext().router.transitionTo.mock.calls[0][0]).toEqual('MyRoute');
expect(myComponentInstance.getChildContext().router.transitionTo.mock.calls[0][1]).toEqual({id: '12345'});
});
As much as I call setState
, my nextState
in componentWillUpdate
is always something: ""
. However, in the test, if I check the content of myComponentInstance.state
then it is something: "12345"
. So basically, componentWillUpdate
gets called but not having the new state even my instance component has it.
Any ideas on this?
--
EDIT 1
Below suggestions are based on setState being asynchronous function but that didn't solve the problem. I was also trying to simulate a store change (Flux pattern) in this way:
myStore.getState = jest.genMockFunction().mockImplementation(function() {
return{
something: "12345",
};
});
myComponentInstance.onChange(); //Simulate store change (this function has setState inside taking values from the store)
Well that didn't work either, actually was telling me that onChange
is not defined. So my problem is with the react-router wrapper. I found a solution but I am not sure if there are better ones cause this one looks very hacky. It is the following:
var RouterWrapper = stubRouterContext(Component, {ref: "myRealComponentInstance"});
var renderedComponent = TestUtils.renderIntoDocument(<RouterWrapper />);
var myComponentInstance = renderedComponent.refs.myRealComponentInstance;
In this way, both myComponentInstance.setState
or simulating a myComponentInstance.onChange
mocking the store work and I don't need to use asynchronous functions.