javascript 在 Jasmine 测试中更新 React 组件状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22463156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating React component state in Jasmine Test
提问by Assaf Weinberg
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.
我有一个相对简单的 React 组件,它根据其状态呈现一个列表。然后我有一个 karma/jasmine 测试来渲染组件,设置它的状态,并检查是否渲染了正确的标记。
The problem I'm running into is that every time I do a setState({})
or forceUpdate()
on my component, I'm getting an error:
我遇到的问题是,每次在我的组件上执行 asetState({})
或forceUpdate()
时,我都会收到错误消息:
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 组件中测试状态变化的正确方法是什么?
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
这是一个重现问题的小项目 https://github.com/treehau5/react_karma_requirejs_bug_reproduction
采纳答案by duereg
I don't know if the previous answer is still true.
不知道之前的答案是否仍然正确。
With React 0.11.1, this code works fine:
使用 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');
});
});
});
回答by Assaf Weinberg
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 和 React_with_addons 的工作原理后,看起来测试中的本地 React 对象与 React_with_addons 使用的 React 实例不同。因此,如果您在测试中执行此操作:
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:
然后 react_with_addon 的 React 实例注册了 componentInstance 并初始化了它的 nodeCache 对象。本地 React 实例保持不变。然后,如果您尝试像这样更新组件的状态:
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.
React 的本地实例用于尝试更新 DOM。由于此实例从未安装过任何组件,因此更新失败并且您会收到“未定义”不是对象(正在评估“deepestAncestor.firstChild”)错误。
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.
有趣的是,如果您将任何组件挂载到本地 React 中,那么在更新组件状态时您将不会看到错误,即使该组件是使用 react_with_addon 的 React 对象挂载的。
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:
目前避免这个问题的最好方法,如果你的测试需要运行 setState,就是不使用 react_with_addon 的 renderIntoDocument 函数。相反,只需创建自己的。它只有两行:
function renderIntoDocument(instance) {
var div = document.createElement('div');
return React.renderComponent(instance, div);
};
回答by Hank Hsiao
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.
你仍然可以使用原来的TestUtils.renderIntoDocument,只需要将要求React移动到beforeEach中即可。因为如果你全局需要 React,那么每次测试的上下文都会不同,这会导致 2 个不同的实例挂载同一个组件。
beforeEach(function () {
React = require('react/addons');
TestUtils = React.addons.TestUtils;
});
回答by Tomasz Modrzyński
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
这是 renderIntoDocument 源代码(我在项目中使用的 React 0.14.8):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
这是改变的时间 - 2 多年前: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:
我还可以确认 Assaf 的答案仍然适用于 0.14.8 - 基本上,编写您自己的 renderIntoDocument。这是对我有用的:
function renderIntoDocument (instance) {
var div = document.createElement('div');
document.documentElement.appendChild(div);
return ReactDOM.render(instance, div);
}