3

Using React 13.2 and looking to test lifecyles with a setup like the one shown on this gist. If I don't stop subsequent renders (via the shouldComponentUpdate method) then anything causes a render (after the initial) explodes with a DOMException Wrong Document:

     DOMException: Wrong document
 at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level1\core.js:583:13)
 at core.Node.insertBefore (D:\development\projects\fsm\node_modules\jsdom\lib\jsdom\level2\events.js:326:32)
 at insertChildAt (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOperations.js:34:14)
 at Object.DOMChildrenOperations.processUpdates (D:\development\projects\fsm\node_modules\react\lib\DOMChildrenOpertions.js:106:11)

JSDOM bails because the parent node is not a document and it don't share the same owner document as the child being inserted. Yeah. How could the owning document be anything other than that the global unless React is doing something funky under the hood.

Just surprised that I don't see more people having a similar problem? There is nothing odd-ball with my Mocha setup nor the JSX components being rendered. Plus the initial render goes fine.

Matthew Campbell
  • 1,864
  • 3
  • 24
  • 51
  • Found the answer (https://groups.google.com/forum/#!msg/reactjs/5UlF-mBsG2o/B-Gx8lrWDbgJ) thanks to Ben Alpert and Jonathan Kim for pointing out that React caches the document despite making a instance before each test case. – Matthew Campbell May 05 '15 at 06:34

1 Answers1

4

Update for node 4

With node 4 we can use the latest jsdom and solve this issue in a better way, e.g. using testdom.

This is how I test a React 0.13 component with mocha on node 4:

import testDom from "testdom";
import { expect } from "chai";

testDom("<html><body></body></html>");
const React = require("react/addons");
const MyTestableComponent = require("../src/MyTestableComponent");
const ExecutionEnvironment = require("react/lib/ExecutionEnvironment");
ExecutionEnvironment.canUseDOM = true;

describe("MyTestableComponent", () => {
   it("works!", () => {
       const component = <MyTestableComponent />;
       expect(true).to.equal(true);
   })
})

Note that we should require rather than import React and the component.


Previous answer

I could fix this issue by following the OP's own comment to the question.

Since React stores the document in an internal variable when it is required, we need to remove React from the require.cache object, before requiring it again:

var jsdom = require("jsdom").jsdom;
var React, TestUtils;

describe("Example", function() {

  beforeEach(function() {
    // remove react from the require cache
    for (var key in require.cache) {
      if (key.match(/\/node_modules\/react\//)) {
        delete require.cache[key];
      }
    }

    // init the DOM
    global.document = jsdom("<html><head><script></script></head><body></body></html>");
    global.window = document.parentWindow;

    // require react again    
    React = require("react/addons");
    TestUtils = React.addons.TestUtils;

  });

  // my tests...

});
gpbl
  • 4,721
  • 5
  • 31
  • 45
  • yet i'm getting a performance downgrade repeating tests with this setup: not sure if there's something to do on `afterEach` – gpbl Jun 06 '15 at 06:45
  • It seems that this is causing errors on components using `refs`: `Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's render method). Try rendering this component inside of a new top-level component which will hold the ref.` – silvenon Jul 13 '15 at 20:32
  • Pretty sure react/lib/ExecutionEnvironment vanishes in React 0.14.x and this fix won't work going forward. In general, probably best to avoid reaching into the internals of any module, as it may change without warning. To address this, I installed the 'exenv' module and used it in place of 'ExecutionEnvironment' in code similar to the above. Its really just a copy of ExecutionEnvironment, but seeing as it has no complex dependencies it seems like a perfectly good long term solution. – killthrush Jan 05 '16 at 21:50