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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 23:12:39  来源:igfitidea点击:

Updating React component state in Jasmine Test

javascriptreactjs

提问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">&#9679;</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);
}