Use Scroll and Width in JSDOM

Viewed 1285

I am trying to write a test case for a component which checks if a function bound to a component is called if scroll is triggered on window object.This is not using react framework although I am using JEST as my testing framework which uses JSDOM since it is very good and fast.

The first problem is the scroll is not getting triggered at all. Read about it in a lot of github issues but had no luck.

The second problem is that I have set a width to one of the elements to 1000 px which is a sandbox element in jsdom using jest. But when I add another element below it which is the result of the rendered component the DOMElement function of getClientBoundingRect still returns all zeros.

I tried a couple of things which did not work:

  1. global.document.dispatch(new Event('scroll')) (this was done after adjusting the scroll position)

  2. After rendering my component which has around 19 li elements in it (each li element has a 10x10 px image and a title), I am trying to check the height of my component to scroll to that position, but unfortunately everything is coming to 0.

Is there any other way to test or cover a function which is called on window.scroll using jsdom/jest, I don't want to use phantomjs.

1 Answers

Jsdom does not perform any layouting and can only pretend to be a visual browser. It's default is to set things like document.hidden to indicate this, but integrations for test environments like Jest explicitly tell jsdom to lie and pretend to be a visual browser.

In order to achieve this they will mock many aspects of the APIs related to layouting, dimensionsionality, styling, scrolling, size, etc.

One way it does this is to always return 0 for some values, like for properties in getClientBoundingRect() or scrollTop.

It most likely processed your events, and may have triggered some of its own in reaction to some changes, but it won't ever scroll because there is no constraints of the size of the elements it pretends to render, and there can't be. Jsdom simply never truly renders anything, it only keeps track of elements as abstract components without dimensionality.

https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser

As for working around this, it depends on exactly what you are trying to do in each situation. Maybe you can mock parts of the APIs you need just for these tests, so that they try to keep track of scroll positions changing as methods are invoked or properties updated, but if that is worth it depends on how much time you want to spend on mocking vs how much it actually matters to test that.

Jest has the ability to temporarily switch out the environment used for certain tests, so you could rely on PhantomJS in only tests which need layouting. PhantomJS will be running in a separate process fully capable of being a visual browser, with the pros and cons of that, (perhaps not up to date with the latest APIs, but it does do perform the actual visual changes for scrolling etc). It can also screenshot those changes for visual consistently checks, whereas jsdom only really compares markup changes with its snapshot capability.

Related