What is the best way to test Window Scroll Event Handlers with Enzyme?

Unfortunately, I don't think Enzyme is going to be much help here. The library only handles events within React's synthetic event system. So a component you render with Enzyme is not going to work with event listeners added to the window. This issues thread on Enzyme's github gives more details and there are some suggested workarounds that might help you.

For example, you might want to spy on window.addEventListener, then you can check on mount that it was called with the arguments "scroll" and your callback.

Regarding your specific code, the scroll listener is set in componentDidMount but your component is shallow rendered, so componentDidMount isn't actually called (so there is no listener). Try adding this line to your beforeEach: MyTestComponent.instance().componentDidMount()


You could make the case that events are just simple messages - since enzyme is using JSDOM under the hood, you can adequately track these messages as they are attached to nodes using plain javascript, regardless of whether the event is 'scroll', 'foo', or 'bar'.

In a test environment, we don't really care the event is called, the system just has to know how to respond it.

Heres an example of tracking non-synthetic events like scroll with enzyme:

class Scrollable extends Component {
  componentDidMount() {
    if (this.myCustomRef) {
      this.myCustomRef.addEventListener('scroll', this.handleScroll)
    }
  }

  handleScroll = (e) => this.props.onScroll(e) 
}

// scollable-test.js
import React from 'react'
import { mount } from 'enzyme'
import Scrollable from '../Scrollable'

describe('shared/Scrollable', () => {
  it('triggers handler when scrolled', () => {
    const onScroll = jest.fn()
    const wrapper = mount(
      <Scrollable onScroll={onScroll}><div /></Scrollable>
    )
    const customEvent = new Event('scroll')
    // the first element is myCustomRef
    wrapper.first().getDOMNode().dispatchEvent(customEvent)
    expect(wrapper.prop('onScroll')).toHaveBeenCalled()
  })
})

After we attach the events to the dom, we can trigger their handlers by using getDOMNode and dispatchEvent, which fires our prop onScroll

There are some limitations here with JSDOM, in that if you need to do things like track the size or height, or scrollTop of a node after an event has fired, you are out of luck - this is because JSDOM doesn't actually render the page for you, but instead 'emulates' the DOM for usage with libs like enzyme - It could also be argued that a test with these needs would be better suited for end to end testing and entirely different tooling.