在基于jsdom的testing中调用setState导致“无法在工作线程中呈现标记”错误

我正在使用我自己的小型“虚拟浏览器”实用程序在jsdom下testing我的React组件。 工作得很好,直到我想setState 。 例如,当testing儿童年龄input控件时:

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

…在我得到的setState行上:

未捕获的错误:不变的违规:dangerouslyRenderMarkup(…):无法在工作线程中呈现标记。 当unit testing需要React或服务器渲染使用React.renderToString时,确保windowdocument全局可用。

我知道windowdocument全局的确是由基于TestBrowser的TestBrowser设置的,就像那样:

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

我甚至试图将setState换成setTimeout(..., 0) 。 这没有帮助。 我怎样才能testing状态变化的工作?

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

 var canUseDOM = !!( typeof window !== 'undefined' && window.document && window.document.createElement ); ExecutionEnvironment.canUseDOM = canUseDOM; 

这意味着如果在这些条件成立之前加载它,则认为它不能使用DOM。

你可以在你之前把猴子打补丁。

 require('fbjs/lib/ExecutionEnvironment').canUseDOM = true 

或者你可以假装它:

 global.window = {}; global.window.document = {createElement: function(){}}; 

或者确保在设置JSDOM之前不加载React,这是我唯一的方法,但是这也是最困难和最容易出错的。

或者你可以把这个问题作为一个问题来报告,或者检查一下jess的来源,看看它是如何解决的。

如果你使用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; 

--require arg:

 $ mocha --compilers js:babel/register --require ./test/setup-jsdom.js test/*.js 

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

资源

我也有使用巴别testingES6代码的这个错误。 重点是import React from 'react'const React = require('react') import React from 'react'是有区别的。 如果您使用的是import语法,那么您的所有导入都会在其他任何事情之前发生,所以您不能在之前模拟windowdocument

所以第一点是要在testing中取代import (在哪里是重要的)

第二点是通过使用global.navigator = global.window.navigator来模拟global.navigator = global.window.navigator

希望它会帮助别人。

直到我尝试在mocha命令中要求使用jsdom-global时,没有任何工作对我有用:

 --require jsdom-global/register 

来源: https : //github.com/rstacruz/jsdom-global/blob/master/README.md#mocha