在基于jsdom的测试中调用setState导致"无法在工作线程中呈现标记"错误

Iva*_*tov 20 testing node.js jsdom reactjs reactjs-testutils

我正在使用我自己的小"虚拟浏览器"实用程序jsdom下测试我的React组件.工作得很好,直到我努力setState.例如,在测试儿童年龄输入控制时:

describe('rendering according to the draft value', function () {
    var component;

    beforeEach(function () {
        component = TestUtils.renderIntoDocument(
            React.createElement(ChildrenInput, {value: []})
        );

        component.setState({draft: [{age: null}, {age: null}]}, done);
    });

    it('overrides the value property for the count', function () {
        assert.strictEqual(component.refs.count.props.value, 2);
    });

    it('overrides the value property for the ages', function () {
        assert.strictEqual(component.refs.age1.props.value, null);
    });
});
Run Code Online (Sandbox Code Playgroud)

...... setState我在线上:

未捕获错误:不变违规:dangerouslyRenderMarkup(...):无法在工作线程中呈现标记.确保windowdocument提供需要的时候进行单元测试或使用React.renderToString服务器渲染才反应过来全局.

我知道window并且document全局变量确实是由基于jsdom设置的TestBrowser,就像那样:

global.document = jsdom.jsdom('<html><body></body></html>', jsdom.level(1, 'core'));
global.window = global.document.parentWindow;
Run Code Online (Sandbox Code Playgroud)

我甚至试图包装setState成一个setTimeout(..., 0).它没有帮助.如何测试状态更改是否有效?

Bri*_*and 21

在加载时,React确定它是否可以使用DOM,并将其存储为布尔值.

var canUseDOM = !!(
  typeof window !== 'undefined' &&
  window.document &&
  window.document.createElement
);
ExecutionEnvironment.canUseDOM = canUseDOM;
Run Code Online (Sandbox Code Playgroud)

这意味着如果在这些条件成立之前加载它,它就会假定它不能使用DOM.

你可以在你的beforeEach中修补它.

require('fbjs/lib/ExecutionEnvironment').canUseDOM = true
Run Code Online (Sandbox Code Playgroud)

或者你可以先伪造它:

global.window = {}; global.window.document = {createElement: function(){}};
Run Code Online (Sandbox Code Playgroud)

或者确保在设置JSDOM之前不加载React,这是我唯一的积极方式,但它也是最难以解决的问题.

或者您可以将此报告为问题,或者检查jest的来源并查看它如何解决它.


lep*_*rem 10

如果您使用Mocha和Babel,则需要在编译器评估React代码之前设置jsdom.

// setup-jsdom.js

var jsdom = require("jsdom");

// Setup the jsdom environment
// @see https://github.com/facebook/react/issues/5046
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = document.defaultView;
global.navigator = global.window.navigator;
Run Code Online (Sandbox Code Playgroud)

随着--requirearg:

$ mocha --compilers js:babel/register --require ./test/setup-jsdom.js test/*.js
Run Code Online (Sandbox Code Playgroud)

请参阅https://github.com/facebook/react/issues/5046#issuecomment-146222515

资源