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 ???
Tabbyofjudah
  • 1,973
  • 3
  • 17
  • 29
  • 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. – Alexandre Kirszenberg May 13 '15 at 12:00
  • 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.. – Tabbyofjudah May 15 '15 at 00:18
  • 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); – Tabbyofjudah May 15 '15 at 00:19
  • I placed that code in the before hook, after global.window is set before requiring React. – Tabbyofjudah May 15 '15 at 00:21

2 Answers2

3

The setup JSDOM setup was missing global.navigator.

global.navigator = {
   userAgent: 'node.js'
};
Tabbyofjudah
  • 1,973
  • 3
  • 17
  • 29
  • 1
    It seems that [jsdomify](https://github.com/podio/jsdomify) does a good job of taking care of these bugs. – silvenon Jul 12 '15 at 20:10
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.

Vlad
  • 59
  • 4