March 12, 2015

Create a Jasmine Spy Object That’s Also An EventEmitter

Say you’re writing Jasmine tests for Node.js to test some module FooModule. FooModule expects to have an instance of some non-trivial service BarService injected into its constructor so it can call lots of methods on it. One easy way to create a mock of BarService’s complicated interface without creating a real object and stubbing out all of its many methods is to use jasmine.createSpyObj():

var mockBarService = jasmine.createSpyObj("BarService", [
    "reload",
    "hasChanges",
    "addLink",
    "replaceLink",
    "deleteLink",
    "hasLinkForUrl",
    "setApiKey",
    "setSessionManager",
    // ...
]);

var moduleToTest = new FooModule(mockBarService);

But what if FooModule also expects to register for events on its instance of BarService, because the real BarService inherits from EventEmitter?

For the real BarService, we have access to its constructor function, so we can use Util.inherits(BarService, EventEmitter). But here in this unit test, jasmine.createSpyObj() creates the mock instance from {}, meaning the mock instance’s constructor function is Object. And trying to make Object inherit from EventEmitter seemed like a bad idea.

After several dumb attempts at making this work - which I’ll spare you from - I found the answer. I’m recording it here so I don’t forget, and because I didn’t find an acceptable answer anywhere else:

var mockBarService = jasmine.createSpyObj("BarService", [
    //...
]);

_.assign(mockBarService, EventEmitter.prototype);

var moduleToTest = new FooModule(mockBarService);

This uses Lodash’s _.assign() to assign the necessary properties of EventEmitter’s prototype to the mock instance. I suppose the same thing could be done with ECMAScript 6’s Object.assign() if that’s available to you.