Error: Invariant Violation: dangerouslyRenderMarkup(...): Cannot render markup in a worker thread
Asked Answered
F

2

6

React Tests Fails after set State causes second render

Up until now testing has been going well with JSDOM and Mocha. So far have not had to test any components that change their state. I found my first issue testing a component that changes it's state.

The Error

1) Reduced Test Case - @current Tests that Fail when Component changes state and renders "before each" hook:
 Error: Invariant Violation: dangerouslyRenderMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use React.renderToString for server rendering.
  at Context.<anonymous> (test/react-reflux/parts/Reduced-spec.js:47:32)

The Component : Reduced.js

var React = require('react');

var Reduced = React.createClass({

  getInitialState() {
      console.log("start off with editing as false");
      return {editing: false};
  },

  edit() {
      console.log("Setting State to Edit");
      this.setState({editing: true});
  },

  render() {
      console.log("Rendering");
      return (
          <span onClick={this.edit}>
            {(this.state.editing) ? "Editing" : "Click To Edit"}
          </span>
      );
  }

});

module.exports = Reduced;

The Tests : 1-pass, 1-fail

    var React, TestUtils, jsdom, Reduced, expect;

    describe('Reduced Test Case', function () {

        before(function () {

            jsdom = require('jsdom');
            global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
            global.window = global.document.parentWindow;

            React = require('react/addons');
            TestUtils = React.addons.TestUtils;

            Reduced = require('./Reduced');

            expect = require('chai').expect;

            this.component = TestUtils.renderIntoDocument(
                <Reduced />
            );

            var root = TestUtils.findRenderedDOMComponentWithTag(this.component, 'span');
            this.el = root.getDOMNode();

        });

        describe("Tests Pass without simulate", function () {

            it("Root Element Reads 'Click To Edit'", function () {
                expect(this.el.innerHTML).to.equal('Click To Edit');
            });

        });

        describe("Tests that Fail when Component changes state and renders", function () {

            beforeEach(function () {

                //
                //  Simulate invokes edit, invokes set state, invokes render, then error occures
                //

                TestUtils.Simulate.click(this.el);

            });

            it("Root Element Reads 'Editing'", function () {
                expect(this.el.innerHTML).to.equal('Editing');
            });

        });

    });

The Results

> mocha --compilers js:babel/register

Reduced Test Case - @current
  start off with editing as false
  Rendering

Tests Pass without simulate
  ✓ Root Element Reads 'Click To Edit'

Tests that Fail when Component changes state and renders
  Setting State to Edit
  Rendering 

  1) "before each" hook


1 passing (379ms)
1 failing

1) Reduced Test Case Tests that Fail when Component changes state and renders "before each" hook:
Error: Invariant Violation: dangerouslyRenderMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use React.renderToString for server rendering.
at Context.<anonymous> (test/Reduced-spec.js:47:32)

I've been going crazy

  • Everything is loaded after global.window and global.document
  • The Simulate Event invokes edit(), then render() before error
  • All React Mocha JSDOM tests have been working well until this state change issue
  • Please help ???
Fletcherfletcherism answered 13/5, 2015 at 0:54 Comment(4)
This error is thrown because the following expression evaluates to false: typeof window !== 'undefined' && window.document && window.document.createElement. Make sure that window is correctly defined within the component's render method.Altar
I placed that test directly into my before hook, it says true... I also placed the other tests from React's ExecutionEnvironment.js file... They all come back as true..Fletcherfletcherism
var canUseDOM = !!( typeof window !== 'undefined' && window.document && window.document.createElement ), canUseEventListeners = canUseDOM && !!(window.addEventListener || window.attachEvent),canUseViewport = canUseDOM && !!window.screen; var isInWorker = !canUseDOM; console.log(canUseDOM); console.log(canUseEventListeners); console.log(canUseViewport); console.log(isInWorker);Fletcherfletcherism
I placed that code in the before hook, after global.window is set before requiring React.Fletcherfletcherism
F
3

The setup JSDOM setup was missing global.navigator.

global.navigator = {
   userAgent: 'node.js'
};
Fletcherfletcherism answered 16/5, 2015 at 21:51 Comment(1)
It seems that jsdomify does a good job of taking care of these bugs.Thaumatology
T
2

Insert your global object modifying(passing window and document objects to global) before React is required. Because React creates its ExecutionEnvironment object while required and don't modify it while works.

Twelvetone answered 29/9, 2015 at 9:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.