Collecting with Moksi

Manfred Stienstra

For some reason language designers and implementers usually do a bad job a designing the API of the standard library. That’s why I’m pretty happy with the bareness of the JavaScript standard library: it leaves room for libraries like Prototype and jQuery to step in and tailor the APIs to the task the everyday programmer is trying to achieve.

I do mind that JavaScript doesn’t allow you to introspect or invoke event handlers because that’s bad for people who like to write tests.

Getting your test to introspect observers is not that hard, you just collect all the calls to Event.observe and element.observe.

Event.observers = [];
Moksi.stub(Event, 'observe', function(element, name, handler) {
  Event.observers.push([element, name, handler]);
});
$$('input').each(function(element) {
  Moksi.stub(element, 'observe', function(name, handler) {
    Event.observers.push([element, name, handler]);
  });
});

Now you can look in Event.observers and see what handlers got defined on which elements.

this.assertObserves = function(expectedElement, expectedName) {
  this.assert(Event.observers.any(function(args) {
    return (args[0] == expectedElement) && (args[1] == expectedName);
  }));
};

this.assertObserves($('input[name="artist_name"]'), 'blur');

And you can also call them from a test to make sure they work as expected. To keep the example short we assume you don’t have to pass arguments to the handler.

this.callObserver = function(element, eventName) {
  var observer = Event.observers.detect(function(args) {
    return (args[0] == element) && (args[1] == eventName);
  });
  observer[2]();
};

this.callObserver($('input[name="artist_name"]'), 'blur');

You can find Moksi on GitHub and testunit.js is part of script.aculo.us.