Подтвердить что ты не робот

Вызов 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). Это не помогает. Как я могу провести тестирование изменений состояния?

4b9b3361

Ответ 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.

Надеюсь, это поможет кому-то.