2014-11-11 6 views
20

Ich teste meine React-Komponenten unter jsdom mit my own tiny "virtual browser" utility. Funktioniert gut, bis ich versuche, setState. Wenn zum Beispiel ein Kind im Alter von Eingangssteuer Prüfung:Aufruf von SetState in jsdom-basierten Tests verursacht "Kann Markup in einem Worker-Thread nicht rendern" Fehler

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

... auf der setState Linie Ich erhalte:

nicht erfasste Fehler: Invariant Verletzung: dangerouslyRenderMarkup (...): Kann nicht machen Markup in ein Worker-Thread. Stellen Sie sicher, dass window und document global verfügbar sind, bevor Reagieren beim Komponententest erforderlich ist, oder verwenden Sie React.renderToString für das Server-Rendering.

Ich weiß, dass window und document Globals in der Tat durch die jsdom-basierten TestBrowser eingestellt sind, wie folgt aus:

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

Ich habe sogar versucht setState in eine setTimeout(..., 0) zu wickeln. Es hilft nicht. Wie kann ich die Zustandsänderungen testen lassen?

+1

Es sieht so aus, als ob Sie der Autor des von Ihnen erwähnten Dienstprogramms sind. Ich sehe es nirgendwo gespalten. Sie sollten also erwähnen, dass dies Ihr Werkzeug ist. (Dies ist eine SO-Richtlinie.) Außerdem scheint es einige wichtige Informationen zu geben, die bei der Frage fehlen: nämlich wie jsdom initialisiert und von Ihrem Code verwendet wird. Die Zusendung einer externen Website ist kein Ersatz dafür, diese Informationen in die Frage selbst zu stellen. – Louis

+0

Ich habe den Text aktualisiert. Danke für die Rückmeldung. –

Antwort

21

Bei Ladezeit React bestimmt, ob es DOM verwenden kann, und speichert es als Boolean.

Dies bedeutet, dass wenn es geladen wird, bevor diese Bedingungen zutreffen, es davon ausgeht, dass es DOM nicht verwenden kann.

Sie könnten Affe es in Ihrem beforeEach Patch.

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

Oder man könnte es auf den ersten Fälschung:

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

oder stellen Sie sicher, dass Sie laden nicht reagieren, bevor Sie auf JSDOM gesetzt, das ist der einzige Weg über Ich bin positiv, aber es ist auch der schwierigste und fehleranfälligste.

Oder Sie könnten dies als ein Problem melden, oder überprüfen Sie Quelle und sehen, wie es es löst.

+1

ExecutionEnvironment scheint sich verschoben zu haben: 'const ExecutionEnvironment = require ('fbjs/lib/ExecutionEnvironment');' – ehrencrona

3

Ich habe auch diesen Fehler mit Babel zum Testen von ES6-Code. Der Punkt ist, dass es einen Unterschied zwischen import React from 'react' und const React = require('react') gibt. Wenn Sie import Syntax verwenden, dann alle Ihre Importe würden vor allem anderen passieren, so dass Sie nicht window oder document vorher vortäuschen können.

So erster Bit import durch require in den Tests zu ersetzen (wo es wichtig ist)

das zweite Bit global.navigator zu verspotten durch global.navigator = global.window.navigator verwenden.

Ich hoffe, es wird jemandem helfen.

10

Wenn Sie Mocha und Babel verwenden, müssen Sie jsdom einrichten, bevor die Compiler den React-Code auswerten.

// 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; 

Mit dem --require arg:

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

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

Source

+0

Sie können einfach 'require (' babel/register '); 'zu setup-jsdom.js hinzufügen und' 'verwenden mocha --compilers js: setup-jsdom.js' – senornestor

+0

Dieser Quelllink war sehr hilfreich für mich - ich eliminierte wahrscheinlich 80% der Mistmuster, die ich vorher benutzt habe. Vielen Dank! Empfehlen Sie diesen Link in der Antwort besser sichtbar zu machen - es ist leicht zu übersehen. – killthrush

+0

Dieser Quelllink ist jetzt unterbrochen. –

1

Nichts für mich gearbeitet, bis ich jsdom-global im Mokka Befehl versucht erfordert:

--require jsdom-global/register 

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

+1

Während dies die Frage theoretisch beantworten könnte, [wäre es vorzuziehen] (// meta.stackoverflow.com/q/8259), die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. –