Using react 16.3.1, jest 16.3.1, enzyme 3.3.0.
Within my React Class component I have created a react ref which I use to ensure that when the component is mounted the browser is at the top of the page.
class PageView extends React.Component {
constructor(props) {
super(props);
this.topOfPageRef = React.createRef();
}
componentDidMount() {
ReactDOM.findDOMNode(this.topOfPageRef.current).scrollIntoView();
}
render(){
const { x } = this.props;
return (
<React.Fragment>
<div className="main-wrapper" ref={this.topOfPageRef}>
Top
</div>
)}
</React.Fragment>
);
}
}
This all works perfectly within the browser but fails in my enzyme test.
My test is simple, it just tries to render the component.
it('should render component correctly', () => {
const props = {
...defaultProps,
};
const wrapper = mount(<PageView {...props} />);
expect(wrapper).toMatchSnapshot();
});
TypeError: Cannot read property 'scrollIntoView' of null
I have tried both shallow and mount methods and whilst the element found is not null, it appears to be a react instance of HTMLDivElement which is missing the scrollIntoView method.
Best Answer
Error message clarification
Using
mount
like in the sample code above gives this error:TypeError: _reactDom2.default.findDOMNode(...).scrollIntoView is not a function
Using
shallow
gives the error listed above:TypeError: Cannot read property 'scrollIntoView' of null
shallow
Issue
shallow
does not do DOM rendering so there will never be a DOM node on which to callscrollIntoView()
.Solution
Any code that does DOM manipulation needs to be tested using the full DOM rendering provided by
mount
.mount
"The default environment in Jest is a browser-like environment through jsdom".
"
jsdom
is a pure-JavaScript implementation of many web standards...[that] emulate[s] enough of a subset of a web browser to be useful for testing".Issue
jsdom
implements much of the browser environment but it does not implement everything. Of particular note for this question is that it does not implementscrollIntoView
sincejsdom
does not do layout and would therefore not be able to provide an accurate implementation.Because
jsdom
does not implementscrollIntoView
it will be undefined on elements provided byjsdom
.Solution
The recommended approach from this Google dev is to add the following line to your test code:
Element.prototype.scrollIntoView = () => {};
That line will add a noop implementation of
scrollIntoView
to thejsdom
-providedElement
.For your test you could take it a step further and set
scrollIntoView
to aspy
to make sure it is called:Also, Antonio is correct that you shouldn't need to use
ReactDOM.findDOMNode()
, you should be able to usethis.topOfPageRef.current
directly: