Testing Event Listeners In Jest (Without Using A Library)

I love using Jest to unit test my Aurelia applications. Sadly, one of the most popular options for mocking event listeners and simulating events called Enzyme is targeted at React applications and to my knowledge, does not work with Aurelia or any other framework like Angular.

If you are wanting to test events registered using addEventListener there is an easy way to mock them.

describe('My Test', () => {
	let sut;
	let events = {};

	beforeEach(() => {
		sut = new Dependency();

		// Empty our events before each test case
		events = {};

		// Define the addEventListener method with a Jest mock function
		document.addEventListener = jest.fn((event, callback) => {
      		events[event] = callback;
    	});
      
        document.removeEventListener = jest.fn((event, callback) => {
      	    delete events[event];
        });
	});

	test('Test Keypress fires callback', () => {
        // Watch the function that gets called when our event fires
        jest.spyOn(sut, 'pressed');
        
        // A method inside of our dependency that sets up event listeners
		sut.setupEvents();

		// Fire the keypress event
		events.keypress({ key: 'Enter' });
        
        // We fired an event, so this should have been called
        expect(sut.pressed).toHaveBeenCalled();
	});
});

Inside of the beforeEach we do a few bootstrapping things before we run our tests. The sut variable is actually the thing we are testing. In this instance, Dependency is a class with some methods inside of it.

We populate our object which stores our events called events when addEventListener is called, our mocked version will be used, so we replicate how this would work in the browser, except we just use an object.

Inside of our test case, we are calling a method on our class called pressed here is what the dependency might look like:

export class Dependency {
    setupEvents() {
        document.addEventListener('keypress', this.pressed.bind(this), false);
    }
  
    pressed() {
        // Called when keypress event is fired
    }
}

This approach works for a lot of other things you want to test and mock.