I have a relatively simple React component that renders a list based on its state. Then I have a karma/jasmine test that renders the component, sets its state, and checks that the correct markup is rendered.
The problem I'm running into is that every time I do a setState({})
or forceUpdate()
on my component, I'm getting an error:
TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild')
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10314
What's the correct way to test state changes in a React component?
React Code:
var NotificationCenter = React.createClass({
getInitialState: function(){
return {notifications:[]}
},
render: function() {
countContainerStyle = {
display: this.state.notifications.length > 0 ? '' : 'none'
};
return (
<div id="pc-notification-center">
<span className="pc-notification-center-bell" >
B
</span>
<span className="pc-notification-count-container" style={countContainerStyle}>
<span className="pc-notification-count-circle">●</span>
<span className="pc-notification-count">{this.state.notifications.length}</span>
</span>
</div>);
}
});
return NotificationCenter;
});
Test Code:
it('should set its notification count to the number of notifications it has', function() {
var notificationCenter = NotificationCenter({}),
countNode;
TestUtils.renderIntoDocument(notificationCenter);
notificationCenter.setState({
notifications: [1,2]
});
countNode = TestUtils.findRenderedDOMComponentWithClass(notificationCenter,'pc-notification-count');
expect(countNode).toBe(2);
});
Edit: Full stack Trace
PhantomJS 1.9.7 (Linux) [object Object] [object Object] [object Object] should default its notification count to 0 FAILED
TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild')
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10314
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10260
at getNode (/home/company/projects/user_interface_kit/bower_components/react/react.js:9874)
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4472
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:28
at /home/company/projects/user_interface_kit/bower_components/react/react.js:5925
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:75
at /home/company/projects/user_interface_kit/bower_components/react/react.js:5925
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:81
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10461
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11924
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13944
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13877
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4360
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10055
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11169
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10105
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11169
at /home/company/projects/user_interface_kit/.tmp/notification_center/notification_center.js:50
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10461
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11924
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13944
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13877
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4360
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:10483
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:11597
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:10533
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:11597
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:12716
at /home/company/projects/user_interface_kit/test/notification_center/notification_center_test.js:19
at /home/company/projects/user_interface_kit/node_modules/karma-jasmine/lib/adapter.js:171
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1585
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:841
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1104
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:754
at callGetModule (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1129)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1479
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1606
Here is a small project reproducing the issue
I have a relatively simple React component that renders a list based on its state. Then I have a karma/jasmine test that renders the component, sets its state, and checks that the correct markup is rendered.
The problem I'm running into is that every time I do a setState({})
or forceUpdate()
on my component, I'm getting an error:
TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild')
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10314
What's the correct way to test state changes in a React component?
React Code:
var NotificationCenter = React.createClass({
getInitialState: function(){
return {notifications:[]}
},
render: function() {
countContainerStyle = {
display: this.state.notifications.length > 0 ? '' : 'none'
};
return (
<div id="pc-notification-center">
<span className="pc-notification-center-bell" >
B
</span>
<span className="pc-notification-count-container" style={countContainerStyle}>
<span className="pc-notification-count-circle">●</span>
<span className="pc-notification-count">{this.state.notifications.length}</span>
</span>
</div>);
}
});
return NotificationCenter;
});
Test Code:
it('should set its notification count to the number of notifications it has', function() {
var notificationCenter = NotificationCenter({}),
countNode;
TestUtils.renderIntoDocument(notificationCenter);
notificationCenter.setState({
notifications: [1,2]
});
countNode = TestUtils.findRenderedDOMComponentWithClass(notificationCenter,'pc-notification-count');
expect(countNode).toBe(2);
});
Edit: Full stack Trace
PhantomJS 1.9.7 (Linux) [object Object] [object Object] [object Object] should default its notification count to 0 FAILED
TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild')
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10314
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10260
at getNode (/home/company/projects/user_interface_kit/bower_components/react/react.js:9874)
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4472
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:28
at /home/company/projects/user_interface_kit/bower_components/react/react.js:5925
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:75
at /home/company/projects/user_interface_kit/bower_components/react/react.js:5925
at /home/company/projects/user_interface_kit/.tmp/notification_center/popover.js:81
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10461
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11924
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13944
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13877
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4360
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10055
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11169
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10105
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11169
at /home/company/projects/user_interface_kit/.tmp/notification_center/notification_center.js:50
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10461
at /home/company/projects/user_interface_kit/bower_components/react/react.js:11924
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13944
at /home/company/projects/user_interface_kit/bower_components/react/react.js:13877
at /home/company/projects/user_interface_kit/bower_components/react/react.js:4360
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:10483
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:11597
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:10533
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:11597
at /home/company/projects/user_interface_kit/bower_components/react/react-with-addons.js:12716
at /home/company/projects/user_interface_kit/test/notification_center/notification_center_test.js:19
at /home/company/projects/user_interface_kit/node_modules/karma-jasmine/lib/adapter.js:171
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1585
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:841
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1074
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:126
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1117
at each (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:58)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1118
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:895
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1104
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:754
at callGetModule (/home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1129)
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1479
at /home/company/projects/user_interface_kit/node_modules/karma-requirejs/lib/require.js:1606
Here is a small project reproducing the issue https://github.com/treehau5/react_karma_requirejs_bug_reproduction
Share Improve this question edited Mar 19, 2014 at 15:56 Assaf Weinberg asked Mar 17, 2014 at 19:05 Assaf WeinbergAssaf Weinberg 1881 gold badge1 silver badge8 bronze badges 4- Can you post more of the stack trace? Which line of your test causes the exception to be thrown? – Ross Allen Commented Mar 17, 2014 at 20:33
- A minimal repro case (in jsbin, etc) would be helpful; you shouldn't ever get that error. Feel free to file as a bug on the react repo. – Sophie Alpert Commented Mar 18, 2014 at 0:55
- I added the full stack trace. The line that causes the exception is the .setState(). I get the same error if I update the state object manually and call forceUpdate() on the forceUpdate call. It seems that this error happens when the component tries to re-render itself. – Assaf Weinberg Commented Mar 18, 2014 at 20:30
- @BenAlpert I could not easily make a jsbin/fiddle, but I created a small project reproducing the issue. Pretty straightforward github.com/treehau5/react_karma_requirejs_bug_reproduction – Assaf Weinberg Commented Mar 19, 2014 at 15:54
4 Answers
Reset to default 10I don't know if the previous answer is still true.
With React 0.11.1, this code works fine:
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
jest.dontMock('public/components/MyThing.jsx');
var MyThing = require('public/components/MyThing.jsx');
describe('MyThing', function() {
var html;
describe('#render', function() {
beforeEach(function(){
var component = MyThing();
var componentInstance = TestUtils.renderIntoDocument(component);
componentInstance.setState({isCool: true});
html = componentInstance.getDOMNode().textContent;
});
it('includes something cool', function(){
expect(html).toContain('something cool');
});
});
});
After digging deep into how React and React_with_addons works, it looks like the local React object in the test is different than the instance of React that React_with_addons uses. So if you do this in your test:
react_with_addons.addons.TestUtils.renderIntoDocument(componentInstance);
Then react_with_addon's instance of React registers the componentInstance and primes its nodeCache object. The local React instance remains is untouched. Then, if you try to update the component's state like this:
componentInstance.updateState({key:'newValue'});
The local instance of React is used to try to update the DOM. Because no components have ever been mounted with this instance, the update fails and you get the 'undefined' is not an object (evaluating 'deepestAncestor.firstChild') error.
Interestingly, if you mount ANY component into the local React, then you won't see an error when updating a component's state, even if that component was mounted using react_with_addon's React object.
The best way to avoid this problem for now, if your test needs to run setState, is to simply not use react_with_addon's renderIntoDocument function. Instead, just create your own. Its only two lines:
function renderIntoDocument(instance) {
var div = document.createElement('div');
return React.renderComponent(instance, div);
};
You still can use original TestUtils.renderIntoDocument, only need to do is to move requiring React into beforeEach. Because if you require React globally, the context will be different for each test, which causes 2 different instances mount the same component.
beforeEach(function () {
React = require('react/addons');
TestUtils = React.addons.TestUtils;
});
This is renderIntoDocument source code (React 0.14.8 I'm using in a project): https://github.com/facebook/react/blob/v0.14.8/src/test/ReactTestUtils.js#L79
And here's when it was changed - over 2 years ago: https://github.com/facebook/react/commit/ce95c3d042309d8aced894cc6be43d7e4cf96455
So despite the name it doesn't actually render anything into the document.
I can also confirm that Assaf's answer still works for 0.14.8 - basically, write your own renderIntoDocument. Here's what worked for me:
function renderIntoDocument (instance) {
var div = document.createElement('div');
document.documentElement.appendChild(div);
return ReactDOM.render(instance, div);
}