Вызов setState в тестах на основе jsdom, вызывающих ошибку "Невозможно выполнить разметку в рабочем потоке"
Я тестирую свои компоненты React под jsdom с помощью моей собственной миниатюрной утилиты "виртуального браузера" . Работает нормально, пока я не попытаюсь 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);
});
});
... на строке setState
, которую я получаю:
Непринятая ошибка: инвариантное нарушение: опасно. RenderMarkup (...): не удается выполнить разметку в рабочем потоке. Убедитесь, что window
и document
доступны во всем мире, прежде чем требовать Реагировать при модульном тестировании или использовать React.renderToString для рендеринга сервера.
Я знаю, что window
и document
глобальные значения действительно устанавливаются на основе jsdom TestBrowser
, например:
global.document = jsdom.jsdom('<html><body></body></html>', jsdom.level(1, 'core'));
global.window = global.document.parentWindow;
Я даже пытался обернуть setState
в setTimeout(..., 0)
. Это не помогает. Как я могу провести тестирование изменений состояния?
Ответы
Ответ 1
В момент загрузки 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(){}};
Или убедитесь, что вы не загружаете React перед настройкой JSDOM, что является единственным способом, на котором я положителен, но это также самый трудный и подверженный ошибкам.
Или вы можете сообщить об этом как о проблеме или проверить источник шутки и посмотреть, как он ее разрешает.
Ответ 2
Если вы используете Mocha и Babel, вам нужно будет настроить jsdom, прежде чем компиляторы оценят код React.
// 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
Источник
Ответ 3
Я также получил эту ошибку, используя Babel для тестирования кода ES6. Дело в том, что существует разница между import React from 'react'
и const React = require('react')
. Если вы используете синтаксис import
, то все ваши импортные события произойдут раньше всего, поэтому вы не можете высмеивать window
или document
раньше.
Итак, первый бит должен заменить import
на require
в тестах (где это имеет значение)
Второй бит - это mock global.navigator
с помощью global.navigator = global.window.navigator
.
Надеюсь, это поможет кому-то.
Ответ 4
Ничего не работало для меня, пока я не попытался выполнить jsdom-global в команде mocha:
--require jsdom-global/register
Источник: https://github.com/rstacruz/jsdom-global/blob/master/README.md#mocha