我有一个相对简单的React组件,它根据状态呈现列表。然后我有一个karma / jasmine测试,它会渲染组件,设置它的状态,并检查是否呈现了正确的标记。
我遇到的问题是,每次在我的组件上执行setState({})
或forceUpdate()
时,我都会收到错误:
TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild')
at /home/company/projects/user_interface_kit/bower_components/react/react.js:10314
在React组件中测试状态更改的正确方法是什么?
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;
});
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);
});
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
这是一个重现这个问题的小项目 https://github.com/treehau5/react_karma_requirejs_bug_reproduction
答案 0 :(得分:10)
我不知道之前的答案是否仍然存在。
使用React 0.11.1,此代码可以正常工作:
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');
});
});
});
答案 1 :(得分:2)
深入研究React和React_with_addons如何工作后,看起来测试中的本地React对象与React_with_addons使用的React实例不同。所以,如果你在测试中这样做:
react_with_addons.addons.TestUtils.renderIntoDocument(componentInstance);
然后react_with_addon的React实例注册componentInstance并填充其nodeCache对象。本地React实例保持不变。然后,如果您尝试更新组件的状态,请执行以下操作:
componentInstance.updateState({key:'newValue'});
React的本地实例用于尝试更新DOM。由于此实例尚未安装任何组件,因此更新失败,您将获得“未定义”。不是一个对象(评估&#39; deepestAncestor.firstChild&#39;)错误。
有趣的是,如果您将任何组件安装到本地React中,那么在更新组件的状态时您将不会看到错误,即使该组件是使用react_with_addon的React对象安装的。
现在避免此问题的最佳方法是,如果您的测试需要运行setState,则不要使用react_with_addon的renderIntoDocument函数。相反,只需创建自己的。它只有两行:
function renderIntoDocument(instance) {
var div = document.createElement('div');
return React.renderComponent(instance, div);
};
答案 2 :(得分:1)
你仍然可以使用原始的TestUtils.renderIntoDocument,只需将React转移到beforeEach即可。因为如果全局需要React,每个测试的上下文都会有所不同,这会导致2个不同的实例挂载相同的组件。
beforeEach(function () {
React = require('react/addons');
TestUtils = React.addons.TestUtils;
});
答案 3 :(得分:0)
这是renderIntoDocument源代码(React 0.14.8我在项目中使用): https://github.com/facebook/react/blob/v0.14.8/src/test/ReactTestUtils.js#L79
这是在2年前改变的时候:https://github.com/facebook/react/commit/ce95c3d042309d8aced894cc6be43d7e4cf96455
所以尽管这个名字并没有真正在文档中呈现任何内容。
我还可以确认Assaf的答案仍适用于0.14.8 - 基本上,编写自己的renderIntoDocument。这对我有用:
function renderIntoDocument (instance) {
var div = document.createElement('div');
document.documentElement.appendChild(div);
return ReactDOM.render(instance, div);
}