Simulating click on document ReactJS/JSDom

ryanzec picture ryanzec · Dec 19, 2014 · Viewed 18.2k times · Source

So I am writing some tests for code that adds a click event on the document. I am using JSDom, ReactJS, and Mocha/Chai setup. I have tried the following code in a test:

document.addEventListener('click', function() {
  console.log('test');
});
React.addons.TestUtils.Simulate.click(document);
//also tried React.addons.TestUtils.Simulate.click(document.body);

however this code does not produce the echo that I am expecting.

Is there a way to simulate click, keyup, etc... on the document with JSDom and ReactJS?

UPDATE

To Nick answers, I have tried adding this code to the test:

document.body.addEventListener('click', function() {
  console.log('test');
});

document.body.click();

and I till don't get the console log output. I am not sure if there is some issue with JSDom and doing this type of thing.

If I can't unit test this code, that's fine, there is already some code that I can't unit test right now (code that requires a real DOM to be able to get widths, heights, etc...) but I would like to be able to unit test most of the code (and I am not interested in using PhantomJS for unit testing). My integration tests will cover that type of code.

UPDATE2

Another thing to note is that is that when I console.log(document); I see object attached to the _listeners property for click so I know the event is being attached, it just does not seem to be executing.

Answer

Nick Tomlin picture Nick Tomlin · Dec 19, 2014

Update: document.body.click will work in a browser, but for jsdom you need to manually create the event:

document.body.addEventListener('click', function() {
  console.log('test');
});

var evt = document.createEvent("HTMLEvents");
evt.initEvent("click", false, true);
document.body.dispatchEvent(evt)

The above code is working for me in Jest and should work with "solo" jsdom as well.

Autumn 2018 holiday update 🦃

The tools around simulating events have gotten a great deal better. I've currently shifted my approach to use the excellent react-testing-library to render my components and dispatch events:

import {render, fireEvent} from 'react-testing-library'

test('example', () => {
  const handleClick = jest.fn()

  const {getByText} = render(<div><button onClick={handleClick}>Click Me</button></div>)
  fireEvent.click(getByText('Click Me'))

  expect(handleClick).toHaveBeenCalled()
})

While I still believe in end to end tests with something like puppeteer or selenium (or cypress!) provide the highest level of confidence that something actually works, this provides a huge amount of value without polluting tests with manual event creation.