How to test event listeners using QUnit

2019-06-10 22:54发布

问题:

I'm using pure Javascript (no JQuery) and I'm trying to get QUnit to test my function that is only invoked via an event, i.e. it's an event listener.

So the function I wish to test is of the form:

(function() {
   function the_one_i_want_to_test() {
      // do stuff
   }

   window.addEventListener('load', function() {
      var some_element = ...;
      some_element.addEventListener('click', the_one_i_want_to_test);
   });
})();

I know I could expose the function to test it, but it is only ever used as an event listener and I don't want to pollute the global namespace.

That's why I am trying to kill two birds with one stone by manually triggering a "click" event and then checking for desired effects (in my tests).

The problem is that the event handler doesn't seem to be executing at all, either because QUnit doesn't wait for it before performing the effects checks, or for some other reason.

So my QUnit test code looks like this:

QUnit.test('test function', function(assert) {             
   var some_element = ...;
   var event = document.createEvent('Event');
   event.initEvent('click', true, true);
   some_element.dispatchEvent(event);

   assert.ok(...assert one or more effects of running "the_one_i_want_to_test"...);
});

I have tried including JQuery just for the tests to use ".trigger()", but that doesn't seem to help.

The event listener executes fine/normally on the production page, just not in the tests.

Any ideas on why the event listener doesn't seem to be running?

回答1:

In Javascript, event handlers are not executed immediately when the event is raised. They are queued up on a list, and execute after the current code block is done. By that time, the test is over.

You have to use the setTimeout trick to queue up your validation code so that it executes after the handler. When the delay is 0 (or unspecified), the code will be queued for execution as soon as possible, meaning right after the event handler gets a chance to run.

As Amit says, you also need to use the assert.async() method to get a done() function that you'll call after your assertions. This makes QUnit.test wait until you invoke it before moving on to the next test.

Try something like this:

QUnit.test('test function', function(assert) {             
   var some_element = ...;
   var event = document.createEvent('Event');
   event.initEvent('click', true, true);
   some_element.dispatchEvent(event);

   var done = assert.async();
   setTimeout(function() {
        assert.ok(...assert one or more effects of running "the_one_i_want_to_test"...);
        done();
   });

});


回答2:

Ensure that the code you wish to test is actually included in your web page.

I have been running in a headless environment and didn't get any runtime errors (apart from the failed assertions). With the help of @Amit (to bring me to my senses), I tried running the tests in a browser and discovered the code was not even being included in the page.