Javascript 茉莉花试验中反应组分状态的更新

Javascript 茉莉花试验中反应组分状态的更新,javascript,reactjs,Javascript,Reactjs,我有一个相对简单的React组件,它根据列表的状态呈现列表。然后我有一个karma/jasmine测试来呈现组件,设置其状态,并检查是否呈现了正确的标记 我遇到的问题是,每当我在我的组件上执行setState({})或forceUpdate()时,我都会收到一个错误: TypeError: 'undefined' is not an object (evaluating 'deepestAncestor.firstChild') at /home/company/projects

我有一个相对简单的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组件中状态变化的正确方法是什么

反应代码: 编辑:完整堆栈跟踪 这里有一个小项目再现了这个问题

深入了解React和React\u with\u插件的工作原理后,测试中的本地React对象似乎与React\u with\u插件使用的React实例不同。因此,如果您在测试中这样做:

react_with_addons.addons.TestUtils.renderIntoDocument(componentInstance);
然后react_with_addon的react实例注册componentInstance并初始化其nodeCache对象。本地React实例保持不变。然后,如果您尝试像这样更新组件的状态:

componentInstance.updateState({key:'newValue'});
React的本地实例用于尝试更新DOM。由于此实例从未装入任何组件,因此更新失败,并且您会得到“未定义”不是对象(评估“deepestAncestor.firstChild”)错误

有趣的是,如果您将任何组件装入本地React,那么在更新组件的状态时将不会看到错误,即使该组件是使用React\u with\u addon的React对象装入的

如果您的测试需要运行setState,那么现在避免这个问题的最好方法就是不要使用react_with_插件的renderIntoDocument函数。相反,只需创建自己的。它只有两行:

 function renderIntoDocument(instance) {
        var div = document.createElement('div');
        return React.renderComponent(instance, div);
      };

我不知道前面的答案是否仍然正确

对于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');
    });
  });
});

您仍然可以使用原始的TestUtils.renderIntoDocument,只需要将React移到beforeach。因为如果需要全局响应,每个测试的上下文都会不同,这会导致两个不同的实例装载相同的组件

beforeEach(function () {
    React = require('react/addons');
    TestUtils = React.addons.TestUtils;
});

这是RenderToDocument源代码(我在项目中使用的React 0.14.8):

这是两年前改变的时间:

因此,尽管名称不同,它实际上并不会将任何内容呈现到文档中

我还可以确认,Assaf的答案仍然适用于0.14.8-基本上,编写自己的RenderToDocument。以下是对我有效的方法:

函数renderIntoDocument(实例){
var div=document.createElement('div');
document.documentElement.appendChild(div);
返回ReactDOM.render(实例,div);
}

您可以发布更多的堆栈跟踪吗?您的测试的哪一行导致抛出异常?一个最小的重新编译用例(在jsbin等中)会很有帮助;你不应该犯那样的错误。请随意在react-repo上作为bug进行归档。我添加了完整的堆栈跟踪。导致异常的行是.setState()。如果手动更新state对象并在forceUpdate调用中调用forceUpdate(),则会出现相同的错误。当组件试图重新呈现自身时,似乎会发生此错误。@BenAlpert我无法轻松制作jsbin/fiddle,但我创建了一个小项目来重现此问题。非常简单,任何人都可以验证这是否仍然适用于
0.12.*
?这仍然是有效的黑客攻击吗?或者现在有一个好的解决方法吗?我猜这不再有效,因为React自编写此答案以来经历了许多更改。在调试了近一周后,此答案救了我:)有趣的是,它可能不会使他们的测试失败,但肯定会让我的测试失败(因为我的代码期望
element.ownerDocument.body.contains(element)
为所有呈现的元素返回true)。
 function renderIntoDocument(instance) {
        var div = document.createElement('div');
        return React.renderComponent(instance, div);
      };
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');
    });
  });
});
beforeEach(function () {
    React = require('react/addons');
    TestUtils = React.addons.TestUtils;
});