9

Given the following component:

export function App() {
  return withApollo(<BrowserRouter>
    <MatchListRouteHandler />
  </BrowserRouter>);
}

// MatchListRouteHandler
export const Query = addTypenameToDocument(gql`
  query GetMatches {
    matches {
      id
    }
  }
`);

export default graphql(Query)(MatchListRouteHandler);

And the test case:

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
});

I get the following error when Jest attempts to run the test case:

/home/dan/match-history-analyser/node_modules/jsdom/lib/jsdom/browser/Window.js:148
      return idlUtils.wrapperForImpl(idlUtils.implForWrapper(window._document)._location);
                                                                              ^

TypeError: Cannot read property '_location' of null
    at Window.get location [as location] (/home/dan/Projects/match-history-analyser/node_modules/jsdom/lib/jsdom/browser/Window.js:148:79)
    at Timeout.callback [as _onTimeout] (/home/dan/Projects/match-history-analyser/node_modules/jsdom/lib/jsdom/browser/Window.js:525:40)
    at ontimeout (timers.js:386:14)
    at tryOnTimeout (timers.js:250:5)
    at Timer.listOnTimeout (timers.js:214:5)
Dan
  • 10,282
  • 2
  • 37
  • 64

4 Answers4

6

This seems to occur because the Jest test process exits too quickly; Apollo attempts to continue to request the data you've provided after the App was mounted, but the response doesn't occur until after the test has ended, leading to this cryptic error message which causes the entire Jest runner to quit.

This can be remedied by artificially increasing the delay before the test in question ends, ie:

it('renders without crashing', (done) => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);

  setTimeout(() => done());
});

Note that this does not fix the error entirely (actually, your test above will always pass), but it does mean that your entire test runner will not completely bomb out.

The correct answer probably involves using Server Side Rendering in your tests.

Dan
  • 10,282
  • 2
  • 37
  • 64
  • 9
    This answer is terrible and I regret writing it. Please do not attempt to fight race conditions this way - Refer to Peter's answer. – Dan Jul 20 '18 at 12:20
6

Just a note on this. I came across this error today, also with Apollo + Jest but I fixed in in what might be a more elegant way, not sure, but I unmounted the components being tested in an afterEach.

beforeEach(() => {
    wrapper = mount(<Root location={ '/route/' } context={context} />);
})

afterEach(() => {
    wrapper.unmount();
});
peter.mouland
  • 1,893
  • 17
  • 30
0

just unmount the created component after rendering like that:

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);

  ReactDOM.unmountComponentAtNode(div); // unmounting the created component.
});

unmounting the component should make the error disappears.

Muho
  • 3,188
  • 23
  • 34
  • That won't work if there are asynchronous operations taking place in the component or an error is thrown. – Dan Aug 02 '19 at 13:58
0

@peter.mouland's answer worked for me. Because I was testing that a component could be rendered by ReactDOM, I implemented his approach like this:

describe('<MyComponent />', () => {
  const div = document.createElement('div');

  afterEach(() => {
    ReactDOM.unmountComponentAtNode(div);
  });

  it('deep renders without crashing', () => {
    ReactDOM.render(<MyComponen />,div);
  });
});
Brandon Brown
  • 331
  • 6
  • 16