Вызов 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
линия я получаю:
Uncaught Error: Invariant Violation: dangerouslyRenderMarkup (...): Невозможно отобразить разметку в рабочем потоке. Удостовериться window
а также document
доступны глобально, прежде чем требовать React при модульном тестировании или использовать 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)
, Это не помогает Как я могу заставить тестирование изменений состояния работать?
4 ответа
Во время загрузки React определяет, может ли он использовать DOM, и сохраняет его как логическое значение.
var canUseDOM = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);
ExecutionEnvironment.canUseDOM = canUseDOM;
Это означает, что если он загружен до того, как эти условия будут выполнены, предполагается, что он не может использовать DOM.
Вы могли бы обезьяна исправить это в вашем beforeEach.
require('fbjs/lib/ExecutionEnvironment').canUseDOM = true
Или вы могли бы подделать это сначала:
global.window = {}; global.window.document = {createElement: function(){}};
Или убедитесь, что вы не загружаете React до того, как настроите JSDOM, и это единственный способ, которым я уверен, но он также наиболее сложен и подвержен ошибкам.
Или вы можете сообщить об этом как о проблеме, или проверить источник шутки и посмотреть, как это решает.
Если вы используете 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
Я также получил эту ошибку, используя Babel для тестирования кода ES6. Дело в том, что есть разница между import React from 'react'
а также const React = require('react')
, Если вы используете import
синтаксис, тогда все ваши импорта будут происходить раньше, чем что-либо еще, поэтому вы не можете издеваться window
или же document
до.
Итак, первый бит должен заменить import
от require
в тестах (где это важно)
Второй бит, чтобы издеваться global.navigator
используя global.navigator = global.window.navigator
,
Надеюсь, это кому-нибудь поможет.
У меня ничего не получалось, пока я не попытался запросить jsdom-global в команде mocha:
--require jsdom-global/register
Источник: https://github.com/rstacruz/jsdom-global/blob/master/README.md#mocha