"Cannot read property _location of null" 在 Jest 测试用例中使用 React Apollo 时
"Cannot read property _location of null" when using React Apollo in a Jest test case
给定以下组件:
export function App() {
return withApollo(<BrowserRouter>
<MatchListRouteHandler />
</BrowserRouter>);
}
// MatchListRouteHandler
export const Query = addTypenameToDocument(gql`
query GetMatches {
matches {
id
}
}
`);
export default graphql(Query)(MatchListRouteHandler);
和测试用例:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
当 Jest 尝试 运行 测试用例时出现以下错误:
/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)
这似乎是因为 Jest 测试进程退出得太快; Apollo 尝试继续请求您在 after 应用程序安装后提供的数据,但响应不会发生,直到 after 测试完成结束,导致这个神秘的错误消息导致整个 Jest runner 退出。
这可以通过人为增加相关测试结束前的延迟来补救,即:
it('renders without crashing', (done) => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
setTimeout(() => done());
});
请注意,这并不能完全修复错误(实际上,您上面的测试总是会通过),但这确实意味着您的整个测试运行器不会完全崩溃。
正确答案可能涉及在测试中使用Server Side Rendering。
请注意这一点。我今天遇到了这个错误,也遇到了 Apollo + Jest 但我以一种可能更优雅的方式修复了,不确定,但我卸载了在 afterEach 中测试的组件。
beforeEach(() => {
wrapper = mount(<Root location={ '/route/' } context={context} />);
})
afterEach(() => {
wrapper.unmount();
});
像这样渲染后卸载创建的组件:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div); // unmounting the created component.
});
卸载组件应该会使错误消失。
@peter.mouland 的回答对我有用。因为我在测试一个组件可以被 ReactDOM 渲染,所以我实现了他的方法:
describe('<MyComponent />', () => {
const div = document.createElement('div');
afterEach(() => {
ReactDOM.unmountComponentAtNode(div);
});
it('deep renders without crashing', () => {
ReactDOM.render(<MyComponen />,div);
});
});
给定以下组件:
export function App() {
return withApollo(<BrowserRouter>
<MatchListRouteHandler />
</BrowserRouter>);
}
// MatchListRouteHandler
export const Query = addTypenameToDocument(gql`
query GetMatches {
matches {
id
}
}
`);
export default graphql(Query)(MatchListRouteHandler);
和测试用例:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
当 Jest 尝试 运行 测试用例时出现以下错误:
/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)
这似乎是因为 Jest 测试进程退出得太快; Apollo 尝试继续请求您在 after 应用程序安装后提供的数据,但响应不会发生,直到 after 测试完成结束,导致这个神秘的错误消息导致整个 Jest runner 退出。
这可以通过人为增加相关测试结束前的延迟来补救,即:
it('renders without crashing', (done) => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
setTimeout(() => done());
});
请注意,这并不能完全修复错误(实际上,您上面的测试总是会通过),但这确实意味着您的整个测试运行器不会完全崩溃。
正确答案可能涉及在测试中使用Server Side Rendering。
请注意这一点。我今天遇到了这个错误,也遇到了 Apollo + Jest 但我以一种可能更优雅的方式修复了,不确定,但我卸载了在 afterEach 中测试的组件。
beforeEach(() => {
wrapper = mount(<Root location={ '/route/' } context={context} />);
})
afterEach(() => {
wrapper.unmount();
});
像这样渲染后卸载创建的组件:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div); // unmounting the created component.
});
卸载组件应该会使错误消失。
@peter.mouland 的回答对我有用。因为我在测试一个组件可以被 ReactDOM 渲染,所以我实现了他的方法:
describe('<MyComponent />', () => {
const div = document.createElement('div');
afterEach(() => {
ReactDOM.unmountComponentAtNode(div);
});
it('deep renders without crashing', () => {
ReactDOM.render(<MyComponen />,div);
});
});