Simulating Mouse Click Events in JavaScript

July 08, 2011

As our interfaces get more complex, JavaScript testing is becoming more critical. With browser testing, you should get as close to native events as you can. Jörn Zaefferer recommended I check out jQuery Simulate. In my case I just needed a pure JavaScript way to simulate browser click events at a given location, so I ripped out the jQuery dependance and created a wrapper just around the mouse events.

Pure JavaScript Click Simulate

function mouseEvent(type, sx, sy, cx, cy) {
var evt;
var e = {
bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
screenX: sx, screenY: sy, clientX: cx, clientY: cy,
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
button: 0, relatedTarget: undefined
};

if (typeof( document.createEvent ) == "function") {
evt = document.createEvent("MouseEvents");
evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
e.screenX, e.screenY, e.clientX, e.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
e.button, document.body.parentNode);
} else if (document.createEventObject) {
evt = document.createEventObject();
for (prop in e) {
evt[prop] = e[prop];
}
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
}
return evt;
}

function dispatchEvent (el, evt) {
if (el.dispatchEvent) {
el.dispatchEvent(evt);
} else if (el.fireEvent) {
el.fireEvent(on + type, evt);
}
return evt;
}

There is some good stuff in here, namely document.createEvent and the fallback to document.createEventObject(). As well as el.dispatchEvent and the fallback to el.fireEvent.

Here is an example of using my extracted methods to perform a simulated click.

window.onclick = function(){
console.log(window clicked);
}

var test = document.getElementById(test);
test.onclick = function(){
console.log(test clicked);
}

var evt = mouseEvent("click", 1, 50, 1, 50);
dispatchEvent(test, evt);

We are just console logging here, but there is no reason you can’t hitch jQuery simulate or something like this into your current testing framework.

If you do have jQuery, you can use jQuery Simulate as mentioned above, or in the past I’ve achieved virtually the same thing with this method:

jQuery Click Simulate (without a plugin)

var $el = $(selector);
var offset = $el.offset();
var event = $.extend( $.Event( "mousedown" ), {
which: 1,
pageX: offset.left,
pageY: offset.top
});
$el.trigger(event);

Just extend a new mousedown event and set set some properties.

In jQuery 1.6 events, this is even easier.

As of jQuery 1.6, you can also pass an object to jQuery.Event() and its properties will be set on the newly created Event object.

Bonus Testing Method

Scott González also pointed me to another gem for testing, document.elementFromPoint(x, y). Browser support for elementFromPoint seems to be pretty good. With it you can determine what element is positioned in front at a given location.

Now go add some test coverage to your UI.

6 comments

#1. Andrew on July 08, 2011

Why not just use Cucumber with Capybara?

#2. Marc Grabanski on July 08, 2011

Andrew: That is a good combo, but pure JavaScript testing is more portable.

#3. Gilberto Ramos on July 11, 2011

Nice! This is useful..! =)

#4. AWL on July 11, 2011

I’m curious, do you think this would pass those events on to plugins, like flash?

#5. Marc Grabanski on July 11, 2011

AWL: I just tried triggering a click event on a Flash object and Flash didn’t register it.

#6. Marc Ziegerath on February 16, 2012

dows not in work in ie 9 =(

can you fix this? this would be very nice =D

Leave a comment

Comment in textile images by gravatar