Jest: document is null when running Jest test with Create React App

Created on 23 Mar 2019  路  3Comments  路  Source: facebook/jest

馃悰 Bug Report

I'm running a Jest test, which is erroring out when I set state due to react-dom not finding document. I put a log statement in react-dom and I see that document is populated initially

  console.log node_modules/react-dom/cjs/react-dom.development.js:5066
    !!!! Document {
      location: [Getter/Setter],
      _reactListenersID0002526682692260973: 0 }

but later in the test execution it's null and that's the error I encounter in my Jest test.

  console.log node_modules/react-dom/cjs/react-dom.development.js:5066
    !!!! null

This is has been encountered by another person who commented in https://github.com/facebook/jest/issues/7810

To Reproduce

Clone https://github.com/jcald1/grip-client/tree/feature/258.

Copy .env.development to .env

Run npm test

Expected behavior

The App.js test should pass.

Link to repl or repo (highly encouraged)

https://github.com/jcald1/grip-client/tree/feature/258. Just need to copy .env.development to .env first.

Run npm test

  console.log src/containers/App.js:266
    handleError TypeError: Cannot read property 'body' of null
        at getActiveElement (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:5069:16)
        at getActiveElementDeep (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:5334:17)
        at getSelectionInformation (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:5366:21)
        at prepareForCommit (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:8689:26)
        at commitRoot (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:17711:3)
        at completeRoot (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:19239:3)
        at performWorkOnRoot (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:19168:9)
        at performWork (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:19076:7)
        at performSyncWork (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:19050:3)
        at requestWork (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:18919:5)
        at scheduleWork (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:18728:5)
        at Object.enqueueSetState (/home/jc/projects/grip/grip-client/node_modules/react-dom/cjs/react-dom.development.js:12456:5)
        at App.Object.<anonymous>.Component.setState (/home/jc/projects/grip/grip-client/node_modules/react/cjs/react.development.js:375:16)
        at setState (/home/jc/projects/grip/grip-client/src/containers/App.js:250:14)
        at tryCatcher (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/util.js:16:23)
        at Promise._settlePromiseFromHandler (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/promise.js:512:31)
        at Promise._settlePromise (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/promise.js:569:18)
        at Promise._settlePromiseCtx (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/promise.js:606:10)
        at _drainQueueStep (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/async.js:142:12)
        at _drainQueue (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/async.js:131:9)
        at Async.Object.<anonymous>.Async._drainQueues (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/async.js:147:5)
        at Immediate.Async.drainQueues [as _onImmediate] (/home/jc/projects/grip/grip-client/node_modules/bluebird/js/release/async.js:17:14)
        at runCallback (timers.js:705:18)
        at tryOnImmediate (timers.js:676:5)
        at processImmediate (timers.js:658:5)

Code

App.test.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Provider } from 'react-redux';
    import { shallow, mount } from 'enzyme';
    import { BrowserRouter as Router, Route } from 'react-router-dom';

    import { JSDOM } from 'jsdom';

    import configureStore from '../../store/configureStore';

    global.Promise = require('bluebird');
    const util = require('util');

    jest.mock('../../actions/simulationRuns');
    let App;

    describe('App', () => {
      beforeEach(() => {
        // Set up some mocked out file info before each test
        App = require('../App').default;
      });

      it('renders without crashing - mount', () => {
        const div = document.createElement('div');
        ReactDOM.render(
          <Router>
            <Provider store={configureStore()}>
              <Route path="/">
                <App />
              </Route>
            </Provider>
          </Router>,
          div
        );
      });
    });

setupTests.js

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

I also tried adding

    Object.defineProperty(document, 'currentScript', {
      value: document.createElement('script')
    });

to setupTests.js and beforeEach.

Bug Report Needs Repro Needs Triage

All 3 comments

I've cloned your repo and your tests passes on mine.

image

@natealcedo, thanks. I'm going to close this for now as I'm seeing different results from what I was seeing earlier. I'll re-open if I encounter the same issue and am able to recreate it

Just want to report that I am experiencing the same issue, and I have a live reproduction on replit here: https://repl.it/repls/PeskyStimulatingBetaversion

The stack is React + Jest + React Testing Library. It seems as though Jest is catching the code's unhandled rejection (which is good and expected), but then when RTL tries to run its built-in afterEach hook (that unmounts leftover React root) Jest tears down JSDOM too quickly.

React Testing Library afterEach hook is asynchronous - it has a "flush microtasks" snippet that it executes before ultimately unmounting the React DOM tree. By the time that unmount happens, JSDOM already gets torn down and document object is set to null - even though technically the afterEach hook did not finish running.

This is the afterEach hook in RTL: https://github.com/testing-library/react-testing-library/blob/9fc8581713d03972f935132b5cfab316d6b93abe/src/index.js#L9 and this is the part where it waits for an extra tick before unmounting the DOM: https://github.com/testing-library/react-testing-library/blob/9fc8581713d03972f935132b5cfab316d6b93abe/src/pure.js#L93

The main difference from a typical use case is that this is a test failure due to unhandled rejection - could that be preventing Jest from waiting for afterEach hooks to complete?

Was this page helpful?
0 / 5 - 0 ratings