Interception EventEmitters with Jasmine

I am creating a node.js module and I also want to test it with Jasmine.

Say my module looks something like this:

var myModule = function (foo, bar) { // Begin a workflow var workflow = new (require('events').EventEmitter)(); workflow.on('test', function () { var greet = greet(); return greet; }); workflow.emit('test'); }; function greet () { return "Hi!"; } module.exports = { myModule: myModule }; 

How can I test my module with Jasmine for all of my events that I have selected?

Something like that:

 var myModule = require('../myModule.js'); describe('My Module test', function () { it('should get greet value', function () { myModule.on('test', function () { // "test" as I wrote in myModule expect(myModule.greet).toHaveBeenCalled(); }); }); }); 
+5
source share
2 answers

I am doing this with proxyquire: https://github.com/thlorenz/proxyquire

In the test file:

 var proxyquire = require('proxyquire'); var mockEvents = {}; var myModule = proxyquire('../myModule.js', { events: mockEvents }); describe('My Module test', function () { beforeEach(function() { mockEvents.EventEmitter = function () {}; mockEvents.EventEmitter.prototype = { on: function () { }, emit: function () { } }; spyOn(mockEvents.EventEmitter.prototype, 'on'); spyOn(mockEvents.EventEmitter.prototype, 'emit'); }); it('should get greet value', function () { myModule() expect(mockEvents.EventEmitter.prototype.on).toHaveBeenCalledWith('test'); expect(mockEvents.EventEmitter.prototype.emit).toHaveBeenCalledWith('test'); }); }); 

You can also use a spy as your dummy EventEmitter, etc.

0
source

The main problem is that greet is not actually displayed and therefore not available in tests. Here are some ways to handle this:

  • Add it to the prototype chain to make it available (this is what I did below).

  • Open the function in module.exports . This could be wrapped in process.env.NODE_ENV !== production to exclude it from production.

  • Do not expose it, but check the functionality of the event emitter and the influence of the function (this is probably not ideal).

In order to achieve what you want, you can neutralize the functions and check that they have been called, and check the result of greet individually:

Mymodule.js

 var EventEmitter = require('events').EventEmitter; var MyModule = function (foo, bar) { // Begin a workflow var workflow = new EventEmitter(); workflow.on('test', function () { return this.greet(); }.bind(this)); workflow.emit('test'); }; MyModule.prototype.greet = function () { return "Hi!"; }; module.exports = MyModule; 

Mymodule-tests.js

 var EventEmitter = require('events').EventEmitter; describe('MyModule', function () { it('emits an event upon construction', function () { // Monkey patch var originalEventEmitterOn = EventEmitter.prototype.on; EventEmitter.prototype.on = jasmine.createSpy('on'); // Create module var MyModule = require('./MyModule'); new MyModule(); expect(EventEmitter.prototype.on).toHaveBeenCalled(); // Reset EventEmitter.prototype.on = originalEventEmitterOn; }); it('calls greet upon construction', function () { var MyModule = require('./MyModule'); // Monkey patch var originalGreet = MyModule.prototype.greet MyModule.prototype.greet = jasmine.createSpy('greet'); var myModule = new MyModule(); expect(myModule.greet).toHaveBeenCalled(); // Reset MyModule.prototype.greet = originalGreet; }); it('returns "Hi!"', function () { var MyModule = require('./MyModule'); var myModule = new MyModule(); expect(myModule.greet()).toBe("Hi!"); }); }); 
0
source

Source: https://habr.com/ru/post/1259284/


All Articles