Jasmine spies only detect calls on methods called on Node.js exports object - node.js

I'm trying to spy on dependencies in a Node.js module from within a Jasmine spec, and I'm encountering some weird behaviour.
Jasmine spies on a method that resides in an object exposed by the exports object in the module. When I call the spied-on method in the module using
exports.umap()
the spy detects it. But when I call it in the module using a variable name I assigned to the same method
var umap = exports.umap
umap()
the spy doesn't detect it.
This seems weird to me given that var umap refers to the same method as exports.umap. Anyone have any ideas why this is? Code below.
(The whole reason I'm doing this is that I want to stub my module's dependencies without the need to design the module as a class and use dependency injection.)
// mapper.js
exports.umap = require('underscore').map;
var umap = exports.umap;
function map () {
return exports.umap([1,2,3], function(el) {console.log(el);return el * 2});
// umap() goes unnoticed by the spy
// return umap([1,2,3], function(el) {console.log(el);return el * 2});
}
exports.map = map;
.
// mapper_spec.js
var mapper = require ('../../lib/mapper');
var map = mapper.map;
describe('mapper', function() {
describe('map', function() {
it('calls umap', function() {
var mapped;
spyOn(mapper, 'umap').and.callThrough();
mapped = mapper.map();
expect(mapper.umap).toHaveBeenCalled();
expect(mapped).toEqual([2,4,6]);
});
});
});
UPDATE
I'm still curious about this issue, however https://www.npmjs.org/package/proxyquire made my whole "spying-on-things-attached-to-export-object" strategy moot.

Related

What is exports.install in node js?

Hi I found a framework where they use a lot this pattern.
exports.install = function(){
//code
}
but usually you see this pattern in nodejs
module.exports = {
//code
}
Is this the same thing or is this something else ?
exports is the object corresponding to module.exports before you do anything to it. I think it's due to some legacy code, but basically folks use module.exports if they want to replace the whole object with their own object or a function, while they use exports if they just want to hang functions off the module. It's a little confusing at first, but essentially exports.install just means that calling code would do something like:
const mod = require('that-module');
mod.install(params, callback); // call that function
The framework you're looking at is probably using it as part of a bootstrapping process, afaik it doesn't have significance to the node engine itself.
Yes, it is the same thing. You can use one of 2 ways to setup your code.
The different thing is memory. They point to same memory. You can think exports like a variable and you can not use this way to export your module:
Given this module:
// test.js
exports = {
// you can not use this way to export module.
// because at this time, `exports` points to another memory region
// and it did not lie on same memory with `module.exports`
sayHello: function() {
console.log("Hello !");
}
}
The following code will get the error: TypeError: test.sayHello is not a function
// app.js
var test = require("./test");
test.sayHello();
// You will get TypeError: test.sayHello is not a function
The correct way you must use module.exports to export your module:
// test.js
module.exports = {
// you can not use this way to export module.
sayHello: function() {
console.log("Hello !");
}
}
// app.js
var test = require("./test");
test.sayHello();
// Console prints: Hello !
So, it just is style of developer.

Un-requiring node ShouldJS

My node app has a fairly large test suite that depends on ShouldJS module. The problem is that the library blocks assigning .should properties on objects, but my test suite needs to spin up a server that needs to be mockable (i.e. run in the same process as my test suite) and dynamically build ElasticSearch queries, that need to set .should property on Objects.
I tried to un-require ShouldJS using an approach described here. But that didn't help - see example script below. Is there a workaround or an alternative approach?
Example:
require('should');
var objBefore = {};
objBefore.should = 'should1'; // doesn't get assigned!
objBefore['should'] = 'should2'; // doesn't get assigned!
console.log('Before:', objBefore);
Object.keys(require.cache).forEach(function(path) {
if (path.indexOf('/node_modules/should/') === -1) return;
console.log('Un-requiring path', path);
delete require.cache[path];
});
var objAfter = {};
objAfter.should = 'should1'; // doesn't get assigned!
objAfter['should'] = 'should2'; // doesn't get assigned!
console.log('After:', objAfter);
// still has shouldJS stuff
console.log('objAfter.should:', objAfter.should);
which gives this:
Before: {}
Un-requiring path /my/path/node_modules/should/index.js
Un-requiring path /my/path/node_modules/should/lib/should.js
...
Un-requiring path /my/path/node_modules/should/lib/ext/contain.js
Un-requiring path /my/path/node_modules/should/lib/ext/promise.js
After: {}
objAfter.should: Assertion { obj: {}, anyOne: false, negate: false, params: { actual: {} } }
None of the .should properties are getting assigned.
There's a way to turn ShouldJS should getter on and off:
require('should');
(1).should.be.equal(1);
// turn off ShouldJS should getter
// and use should as a function
var should = require('should').noConflict();
should(0).be.equal(0);
// turn on ShouldJS should getter
should.extend();
require('should');
(1).should.be.equal(1);
Here's what the official Readme says:
It is also possible to use should.js without getter (it will not even try to extend Object.prototype), just require('should/as-function'). Or if you already use version that auto add getter, you can call .noConflict function.
Results of (something).should getter and should(something) in most situations are the same

Mocking constructor functions in node

How do other node developers who use sinon mock out constructor calls within their unit tests? For example, suppose I have some function foo
function foo() {
var dependency = new Dependency(args);
// do stuff with dependency
}
exports.module.foo = foo;
and in a separate test file I have some test in which I want to verify what the Dependency constructor is called with (args), and I need to control what it returns
it('should call Dependency constructor with bar', function() {
var foo = require('myModule').foo
var DependencyMock; //code to make the mock
foo();
expect(DependencyMock.calledWith(bar)).to.equal(true);
});
The problem is that sinon can only mock functions attached to an object, so we have to attach the constructor to an object before it can be mocked.
What I've been doing is just making an object to attach the constructor to in the module making the constructor call, calling the constructor as a method of that object, then exporting the object to use it in tests:
var Dependency = require('path/to/dependency');
var namespace = {
Dependency: Dependency
}
function foo() {
var dependency = new namespace.Dependency(args);
// do stuff with dependency
}
exports.moduole.foo = foo;
exports.module.namespace = namespace;
testfile:
it('should call Dependency constructor with bar', function() {
var foo = require('myModule').foo;
var namespace = require('myModule').namespace;
var DependencyMock = sinon.mock(namespace, 'Dependency').returns(0);
foo();
expect(DependencyMock.calledWith(bar)).to.equal(true);
});
This works, but it feels really clunky to expose an object on my module just for the sake of testing it.
Any tips?
I think it's worth asking why you'd want to mock a constructor of a dependency instead of injecting that dependency?
Consider your example code:
// in "foo.js"
function foo() {
var dependency = new Dependency(args);
// do stuff with dependency
}
exports.module.foo = foo;
If Dependency is required for foo to work you can inject it as an argument of foo:
// in "foo.js"
function foo(dependency) {
// do stuff with dependency
}
exports.module.foo = foo;
// in "bar.js"
var foo = require('./foo.js')(new Dependency(args));
With this change it's now trivial to inject any Test Double in your tests (to find out more about JavaScript Test Doubles have a look at my article on the subject).
This approach makes the dependencies of your function/module explicit, but requires you to wire them up at some point (here: require('./foo.js')(new Dependency(args));).
If you didn't want to wire things up manually there's another approach you can take using rewire and replacing constructor with factory method:
// in "dependency.js"
module.exports= function(args) {
return new Dependency(args);
}
// in "foo.js"
var dependency = require('./dependency');
function foo() {
var dep = dependency(args);
// do stuff with dependency
}
exports.module.foo = foo;
and in your test:
var rewire = require("rewire"),
foo = rewire("../lib/foo.js");
it('should call dependency... ', function() {
foo.__set__("dependency", /* some spy */ );
foo();
});
Hope this helps!
Jan
I used a workaround for this:
// Keep a reference to your dependancy class.
const dependencyClass = Dependency;
let item = new Dependency();
// Replace class with a stub.(optionally return an item.
Dependency = sinon.stub(Dependency, 'constructor').returns(item);
// Call your code that you expect the class constructor to be called.
foo();
assert.isTrue(Dependency.calledWithNew());
assert.equal(1, Dependency.callCount);
// Restore class reference.
Dependency = dependencyClass;
Additionally, in the above case, an item is returned, so the user can have access to the dependency for further testing.
eg.
assert.equal(item.someValue, 10);
You can have other problems using this, eg defined properties will no longer be available for the class.
I agree with Jan Molek, use this in case you cannot change the code.
Not tried, but this could work: stub the constructor function of Dependency and let it return a mock.
var constructor = sinon.stub(Dependency.prototype, "constructor");
constructor.returns(sinon.mock(Dependency));
I encountered a similar problem with modules that expose functions rather than objects - this was my solution. Just putting this here as another way to go about tackling the issue but I must say solving the problem via better design, as Jan Molak suggested, seems like a better approach.

nodeJS proxyquire overwrite specific function of a require

I am currently testing a module in isolation using proxquire to overwrite a require of this module.
Overwriting a path of a require works fine with proxyquire. For example:
var bar = require('./bar');
But can you use proxyquire also to overwrite just a specific function of a module which is required in the module to test? So something like:
var bar = require('./foo').bar();
I need to stay at proxyquire for this since I am using it for mocking a http-request happening in another layer of the architecture. But in case of the test I need to mock the time for "now" in the module as well.
So currently I have this:
var uraStub = sendMockRequest(paramListOfCheckin, queryList);
var setNowStub = function(){ return 1425998221000; };
var checkin = proxyquire('../src/logic/logicHandlerModules/checkin', {
'../../persistence/ura' : uraStub,
'./checkin.setNow' : setNowStub
});
checkin.checkin(...)
The implementation of setNow is:
var setNow = function(){
return new Date().getTime();
};
var checkin = function (...) {
var now = require('./checkin').setNow();
Obviousley './checkin.setNow' : setNowStub in proxyquire doesn't work, since this is the wrong path. But using './checkin'.setNow() : setNowStub also doesn't work because of wrong syntaxis in the object-definition.
Any suggestions?
Thanks in advance!
What you are looking for is the noCallThru() and callThru() methods. https://github.com/thlorenz/proxyquire#preventing-call-thru-to-original-dependency
By default proxyRequire will call through to the mocked dependency which will allow you to pick the methods that you want to overwrite with your own custom function.
So if a dependency in the path '../foo' has a method bar() and fooBar() you would be able to mock out just bar by doing.
proxyquire.callThru();
var fooFunc = proxyquire('../foo', {
bar: () => return 'bar'
})
Now bar() will hit your custom overwritten funtion while fooBar() will be called as normal.

nodejs module unit test method gets called in private class

I'm trying to unit test that a method gets called in my module. The class and method are private and not exposed using module.exports. The modules I'm using for the tests are: mocha, rewire, assert, sinon.spy. The call I want to test is my error method, this currently throws an error, but might change later - so I don't want to test that an error is thrown, just test that class.error() gets called. Not sure how to procede and have tried numerous tuts online.
The class is (currently accessed in tests using rewire):
var MyClass = function MyClass(o){
var self = this
if(!o || typeof o !== 'object')
self.error('No configuration passed to MyClass')
}
MyClass.prototype.error = function(msg){
throw Error(msg)
}
My test currently, which is not working:
it('Constructs MyClass', function(done){
//check constructs normally (this passes and works)
var actual = obj.__get__("MyClass.config")
assert.deepEqual(actual, config)
/**
* check calls error method
*/
//stub class.error ?
//construct class without config
//check if class.error is called
done()
})
In pseudo code, what I'm hoping to do is:
var stub = stub(MyClass)
->do('construct', null) //no config passed
->didCall('error') //check error method is called
This may be a duplicate of: Mocking modules in Node.js for unit testing
But it is throwing an error me: Object #<Object> has no method 'expect'
To solve it I imported the private class constructor using rewire, then I overrode the error method, setting it as a sinon.spy. I construct the class, then check if the spy was called:
//check calls error method if no config passed
var obj = rewire('./path/to/my/module')
, MyClass = obj.__get__("MyClass")
, spy = sinon.spy()
MyClass.prototype.error = spy
var foo = new MyClass()
assert.equal(spy.called, true)
done()

Resources