TL;DR - I wrote a library called Happen that makes it easier to use the createEvent API to do browser tests that actually use events.

A quick interlude of the land of testing.

For my projects recently, I’ve been using Jasmine for testing Wax and Modest Maps. 1

But the bugs that started hitting me weren’t the bugs I was testing against. Picky browser bugs as silly as Internet Explorer’s handling of window.setInterval(function(){}, 0) weren’t being tested for because all I was testing was the API, not the functioning of the thing. What I needed was browser events, and I found that there weren’t any options for getting them, so I wrote a very tiny one: Happen.

Happen lets Wax and Modest Maps do tests with user events. That means full-integration tests - not just testing that Modest Maps can figure out the URLs for tile images. With Happen, I can test that the browser can successfully move a map, reposition tiles, and fire events at the proper time when a user mouses down, drags, and mouseups - and the rest of the things a map should do in response to user input. And not by rewriting the API or wrapping these things any more - by actually providing the code with events that work just like normal events, because they are normal events.

This test is mapping bliss:

it ( ' does not zoom in on single click ' , function () { expect ( map . getZoom ()). toEqual ( 0 ); happen . click ( map . parent ); expect ( map . getZoom ()). toEqual ( 0 ); }); it ( ' zooms in on double click ' , function () { expect ( map . getZoom ()). toEqual ( 0 ); happen . dblclick ( map . parent ); expect ( map . getZoom ()). toEqual ( 1 ); });

The How and Why

The magic under the surface is document.createEvent and the initEvent APIs. They’re rather obtuse: here’s part of Happen’s abstraction code:

evt . initMouseEvent ( o . type , true , // canBubble true , // cancelable window , // 'AbstractView' o . clicks || 0 , // click count o . screenX || 0 , // screenX o . screenY || 0 , // screenY o . clientX || 0 , // clientX o . clientY || 0 , // clientY o . ctrl || 0 , // ctrl o . alt || false , // alt o . shift || false , // shift o . meta || false , // meta o . button || false , // mouse button null // relatedTarget );

Other Options

jQuery does have part of this API: you can call $('#thing').click() , but it operates on a different level, by attempting to find event listeners and then triggering them: the freeform jQuery event system is super-useful, but not something that’s actually in the DOM - it’s very well-orchestrated magic. What we’re creating here are real events with normal bubbling and normal default behavior.

So far this combo is what works: Selenium is the only alternative I’ve found that does real-life events, and I think that it solves the wrong problems: is it really that hard to initially write tests and run them in browers? That’s not a problem for smaller test suites - the problem is maintenance and being able to run your tests everywhere, that matters.

So, now I can open up the testing index.html in Modest Maps or Wax and it just works - no need to install tests on a Windows-running netbook or an iPad. So far it’s testing bliss. If you’ve got client-side libraries and loove testing, happen might help you out.