在Jasmine测试中更新React组件状态

时间:2014-03-17 19:05:19

标签: javascript reactjs

我有一个相对简单的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">&#9679;</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

4 个答案:

答案 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);
}