Intercept EventEmitters with Jasmine - javascript

I'm building a node.js module and I wish also to test it with Jasmine.
Let say my module look similar to 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 targeting all my Events I emit?
Something like this:
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();
});
});
});

I accomplish this using proxyquire: https://github.com/thlorenz/proxyquire
In your 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 mock EventEmitter, etc.

The main problem is that greet is not really exposed and is therefore not accessible in the tests. Here are some ways to handle this:
Add it to the prototype chain to make it accessible (this is what I have done below).
Expose the function in the module.exports. This could be wrapped in a process.env.NODE_ENV !== production to exclude it from production.
Not expose it but test the event emitter functionality and impact of the function (this is probably not ideal).
To achieve what you want, you could monkey patch the functions and test that they have been called and test 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!");
});
});

Related

Access `this` from within required object literal?

I desire to have the following type of object:
const Client = require('./Client')
let client = new Client()
client.someObject.create(...)
client.someObject.update(...)
client.someObject.delete(...)
etc.
This is very easy to accomplish doing something like this:
const Client = function () {
this.someObject = {}
this.someObject.create = function () {...}
this.someObject.update = function () {...}
this.someObject.delete = function () {...}
}
module.exports = Client
But from an organizational standpoint (and because of the massive number of functions someObject has, it would be helpful to put all the someObject stuff into it's own file and require it: require('./someObject'). However, I still need to be able to access the Client object (this) within someObject.create(), someObject.update(), etc.
this.someObject = require('./someObject')
// someObject.js
module.exports = {
create: function () {
// How do I access Client here? Can I pass it to the object literal?
}
}
I've tried to do some prototype sub module type of setup but it doesn't appear to work.
Client.prototype.someObject.create = function () { ... }
How can I separate someObject into it's own file and still access the Client this?
You'll need to provide the Client instance to someObject itself so the latter's methods can use it to reference the former.
One way you accomplish that is to define a 2nd constructor for someObject that takes the client as an argument.
const SomeObject = function (client) {
if (!client) throw new Error('Client reference is required.');
this.client = client;
};
SomeObject.prototype.create = function () {
let client = this.client;
// ...
};
// ....
module.exports = SomeObject;
const SomeObject = require('./someObject');
const Client = function () {
this.someObject = new SomeObject(this);
}
You can also get a similar result with Object.create() if you'd rather keep the object literal:
const baseline = {
create: function () {
let client = this.client;
// ...
},
// ...
};
module.exports = function createSomeObject(client) {
return Object.create(baseline, {
client: {
value: client
}
});
};
const createSomeObject = require('./someObject');
const Client = function () {
this.someObject = createSomeObject(this);
};

miss prototype functions when "new" a instance

I write a module in nodejs ,which Test.js ,code blow
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = Test;
and then, in B.js
var Test = require('./services/Test');
var test = new Test();
console.log(test.foo());
unfortunetly, I got "undefined method foo",
anyone who can Tell me what happended? thanks so much
Check your file location it should be in services directory.
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = new Test();//Test;
var test = require('./services/Test');
console.log(test.foo());
You can export the new object of Test class. try this.
Or you can use ES6 JavaScript that great.
In Test.js try moving the module.exports to before you define the prototype functions.
As below:
function Test() {
this.key = 'value';
}
module.exports = Test;
Test.prototype.foo = function () { return 'foo'; }

NodeJS prototyping with module.exports

I've made a class in my NodeJS app and used module.exports along with a require() statement to bring it into my main server script:
// ./classes/clientCollection.js
module.exports = function ClientCollection() {
this.clients = [];
}
// ./server.js
var ClientCollection = require('./classes/clientCollection.js');
var clientCollection = new ClientCollection();
Now I'd like to add functions onto my class like so:
ClientCollection.prototype.addClient = function() {
console.log("test");
}
However when I do this I get the following error:
ReferenceError: ClientCollection is not defined
How do I properly add functions to a class using prototyping in a NodeJS app?
I think that you need.
function ClientCollection (test) {
this.test = test;
}
ClientCollection.prototype.addClient = function() {
console.log(this.test);
}
module.exports = ClientCollection;
or
function ClientCollection () {
}
ClientCollection.prototype = {
addClient : function(){
console.log("test");
}
}
module.exports = ClientCollection;
For various reasons, this structure:
module.exports = function ClientCollection() {
this.clients = [];
}
does not define the symbol ClientCollection outside of the function itself so you can't refer to it elsewhere in the module to add to the prototype. So, instead, you need to define it outside and then assign it to exports:
function ClientCollection() {
this.clients = [];
}
ClientCollection.prototype.addClient = function() {
// code here
}
module.exports = ClientCollection;

Revealing Module Pattern with a constructor

I'm having a bit of trouble figuring out the best way to implement this.
I want a module that has a constructor that takes in an argument that stores it for later use within the module.
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
}
ModuleB.prototype = function() {
//private stuff/functions
function someMethod() {
moduleA.doSomething();
}
//public api
return {
someMethod : someMethod
};
}();
In some other file
//ModuleA defined elsewhere
var moduleA = new ModuleA();
//...
var module = new ModuleB(moduleA);
module.someMethod();
Now above in someMethod, moduleA is undefined, and this, is the global window object. Can someone explain how I would get access to moduleA? I don't understand what happens to this.moduleA = moduleA; after the constructor. I'm not really a javascript developer so if I'm using the wrong pattern here or something, feel free to chime in.
You are very close, but you're missing something important in your definition of someMethod.
EDIT: is is easier to tell what works and what doesn't if you change the name of the module property in ModuleB:
var ModuleA = function() {}
ModuleA.prototype = (function () {
return {
someMethod: function () {
return 'foo';
}
};
}());
var ModuleB = function(moduleA) {
this.innerModule = moduleA;
}
ModuleB.prototype = (function () {
return {
doStuff: function () {
return this.innerModule.someMethod();
}
};
}());
var moduleA = new ModuleA();
var moduleB = new ModuleB(moduleA);
console.log(moduleB.doStuff()); // prints "foo"
http://jsfiddle.net/mN8ae/1/
Try this:
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
}
// Simplifying your code, what was missin is the "this" keyword accessing the moduleA
ModuleB.prototype.someMethod = function() {
this.moduleA.doSomething();
};
var module1 = new ModuleB({
doSomething: function(){
alert('i do something');
}
});
module1.someMethod();
You would need to use call/apply to execute the method for given context.
try this code (I have modified your code)
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
};
ModuleB.prototype = function() {
//private stuff/functions
function someMethod() {
this.doSomething();
}
//public api
return {
someMethod : someMethod
}; }();
var ModuleA=function(){
this.doSomething=function(){
alert('moduleA Method');
}; };
var modA=new ModuleA(); var modB=new ModuleB(modA);
modB.someMethod.call(modA);
Thanks!

How to maintain reference to an instance, when using the setTimeout callback?

How to maintain a reference to an instance, when using the setTimeout callback? E.G:
In my ViewModel (using Knockout)
var MyVM = function () {
this.myFunc = function () {
setTimeout("this.myCallback()", 2000);
};
this.myCallback = function() { this.myObservable(true); }
}
This fails.
You can add a private field :
var MyVM = function () {
var self = this;
this.myFunc = function () {
setTimeout(self.myCallback, 2000);
};
this.myCallback = function() { self.myObservable(true); }
}
var vm = new MyVM();
Have a look at the RP Niemeyer's answer.
I hope it helps.

Categories