Вызов 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

См. https://github.com/facebook/react/issues/5046.

Источник

Я также получил эту ошибку, используя 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

Другие вопросы по тегам