unit-testing functions in module - javascript

Ok, I'm making a serious stab at learning about unit testing for the first time, I'm using Mocha & Sinon.
So hypothetical dumb module, contains functions foo and bar. Foo depends on bar.
(function() {
var bar = function(callback) {
if (willOfTheGods) {
callback('err', null);
} else
callback(null, 'hurrah');
}
var foo = function() {
bar(function(err, res) {
//blah deh blah
});
}
module.exports = {
bar: bar,
foo: foo
}
})();
I want to stub bar so I can test foo.
This seems logical from the Sinon docs ...
var myModule = require('../myModule');
sinon.stub(myModule, 'bar')
myModule.bar.callsArgWith(0, ['err', null]);
but it only works if I call bar in the test itself.
myModule.bar(function(err, result){
console.log('err, result');
});
When I call myModule.foo it still uses the original 'unstubbed one'.
It seems like creating a stub just creates a new local variable for that
function rather than stubbing it in the module.
Or am I missing something completely - or just doing the wrong thing?

Ok, Some research revealed that stubbing like this is only replacing the value of the module.exports property not the underlying function. So I need to use something like rewire to actually get inside the module.
So now if I drop the Sinon stub and just do:
var myModule = rewire('../myModule');
myModule.__set__('bar', function(callback){
callback('err', null);
});
it works ... kind of. It only works if I remove the self executing function wrapping from myModule, ie remove (function(){ ... })();. My understanding was that was a best-practice ... but maybe only in the browser? Whole different question there I guess.

Related

"this" is not returning module.exports

With the code below using Node.js v11.13.0, I receive the error that this.say is not a function.
/* utils.js */
module.exports = {
test: function() {
this.say('Hello.');
},
say: function(text) {
console.log(text);
}
};
/* index.js */
const {test} = require('./utils.js');
test();
When I log this with the function declared using function() {, it seems to return the global environmental object created by Node.js. If I use an arrow function instead, it returns an empty object.
Why isn't this returning module.exports?
The code is only an example, I'm not actually using it.
This has since been resolved by properly using module.exports instead. Part of the confusion behind this question was the fact that Visual Studio Code says this in my function should be module.exports. If I needed to use it multiple times I'd create a class, but I see no use now.
Thank you for the clarification and suggestions.
First off: why are you trying to do this? You're in Node, so there is literally no reason for any of your code to look up what the node construct is. It should only care about being able to find the things you wrote.
Secondly, you're declaring a plain object, not a class instance, so the this keyword will never point to that variable. It can only ever point to the owner of whatever the current execution scope is.
If you want to return module.exports, then just... do. Either directly, which would be weird, or by at least capturing your export as a real thing first:
const mything = {
test: function() {
mything.say("hello");
},
say(text) {
console.log(text);
}
};
module.exports = mything;
But from your code, that's not what you want. What you want is a real class:
class MyThing {
test() {
this.say('Hello.');
}
say(text) {
console.log(text);
}
};
module.exports = MyThing;
Which you should then call as:
const MyThing = require("./my-thing.js");
let mything = new MyThing();
mything.test();

Best way to test IIFE (Immediately Invoked Function Expression)

So I have an existing application which uses IIFEs extensively in the browser. I'm trying to introduce some unit testing into the code and keep with the pattern of IIFE for new updates to the code base. Except, I'm having trouble even writing a test which gives me a handle to the code. For example I see this type of logic all over the code base:
var Router = (function (router) {
router.routeUser = function(user) {
console.log("I'm in! --> " + user)
};
return router;
})(Router || {});
Then the JS file is included in a script tag in the markup:
<script src="js/RouteUser.js"></script>
and called like this in the production code:
Router.routeUser(myUser)
So my question is, how do I write a test which tests the method routeUser? I've tried this in my Mocha Test:
var router = require('../../main/resources/public/js/RouteUser');
suite('Route User Tests', function () {
test('Route The User', function () {
if (!router)
throw new Error("failed!");
else{
router.routeUser("Me")
}
});
});
But I get an exception:
TypeError: router.routeUser is not a function
at Context.<anonymous> (src\test\js\RouteUser.test.js:8:20)
Then I tried returning the method, which gives the same error:
var Router = (function (router) {
return {
routeUser: function (user) {
console.log("I'm in! --> " + user)
}
}
}
)(Router || {});
Can anyone point me the right direction here?
It sounds that...
you have a codebase of scripts that are only used in the browser context (usage of IIFE suggests this)
you'd like to introduce browserless unit tests (Jest, Mocha?) using node.js (good idea!)
but you probably don't want to migrate the whole codebase to a different coding style at this moment in time (can be a lot of work depending on the size of your codebase)
Given these assumptions, the problem is that you want your code to...
act as a script when used on production (set global window.Router etc)
act as a module when used in unit tests so that you can require() it in unit tests
UMD
UMD, or universal module definition, used to be a common way to write code so that it can work in multiple environments. Interesting approach, but very cumbersome, and I like to think UMD is a thing of the past nowadays...
I'll leave it here for completeness.
Just take UMD's idea
If the only thing you want for now to make a specific script act as a module too, so that it's importable in tests, you could do a small tweak:
var Router = (function (router) {
router.routeUser = function(user) {
console.log("I'm in! --> " + user)
};
if (typeof exports === "object") {
module.exports = router;
// now the Mocha tests can import it!
}
return router;
})(Router || {});
Long term solution
In the long run, you can get lots of benefits by rewriting all your code to use ONLY modules and use a tool like webpack to package it for you. The above idea is a small step in your direction that gives you one specific benefit (testability). But it is not a long term solution and you'll have some trouble handling dependencies (what if your Router expects some globals to be in place?)
If you intend to run your Mocha tests in the browser, you do not have to alter your existing code.
Let's walk through the IIFE pattern, because based on your code, I think you may misunderstand how it works. The basic shape is this:
var thing = (function() {
return 1;
})();
console.log(thing) // '1'
It's a var declaration setting thing equal to the value on the right side of the equals sign. On the right, the first set of parens wraps a function. Then, a second set of parens sits right next to it, at the end. The second set invokes the function expression contained in the first set of parens. That means the return value of the function will be the right-side value in the var statement. So thing equals 1.
In your case, that means that the outer Router variable is set equal to the router variable returned by your function. That means you can access it as Router in your tests, after including the script in the DOM:
suite('Route User Tests', function () {
test('Route The User', function () {
if (!Router) // <- Notice the capital 'R'
throw new Error("failed!");
else {
Router.routeUser("Me") // <- capital 'R'
}
});
});
If you intend to run your tests with node, see Kos's answer.

Node.js how should I unit test a function calling other functions

I want to unit test a module I've built.
To give an impression of what it looks like pretty much..
MyModule:
function MyModule(...) {
var self = this;
MyModule.init.call(self, ...);
}
util.inherits(MyModule, MySuperModule);
MyModule.init = function(...) {
...
};
MyModule.prototype.logic = function(..., done) {
calls fnA, fnB, fnC, fnD conditionally
done(...)
};
MyModule.prototype.fnA = function(...) {
...
};
MyModule.prototype.fnB = function(...) {
...
};
MyModule.prototype.fnC = function(...) {
...
};
MyModule.prototype.fnD = function(...) {
...
};
MySuperModule:
function MySuperModule(...) {
...
}
MySuperModule.prototype,fn = function(..., done) {
var self = this;
...
self.logic(..., function done(...) {
...
done(...)
});
}
Now MyModule.logic() is never called explicitly by a user, it is only invoked MySuperModule.fn().
Same goes for all other MyModule functions which are called conditionally based on the given parameters being passed through the delegating chain.
My questions are as follow:
Do I need to test all MyModule functions separately or just test MySuperModule.fn() with different parameters covering all possible scenarios
I know I need to test function in isolation (which if I do my previous question is wrong to ask because than I won't really have tested MyModule functions at all), how would I do that with the MySuperModule.fn(), because its done() callback is being called with arguments dependent on what the MyModule.logic() done() callback was called with, which is again, dependent on the arguments supplied to MySuperModule.fn() arguments.
It really depends how you're injecting MyModule on MySuperModule. But first of all I would point out that in unit tests you have to test MyModule separately and MySuperModule with a Mocked version from MyModule and all other dependencies. This is because you don't want to test MyModule twice, no need for that.
So to create stubs there is a library called Sinon.JS which works really fine.
So if for any reason you just want to make a spy to MyModule, which means you are just attaching a listener to MyModule (it is applied to MyModule methods) which counts and tells if a given method is ever called and how.
var MyModuleMethodASpy = sinon.spy(MyModulem 'MethodA');
MySuperModule.someMethod();
assert(MyModuleMethodASpy.called)
So this code creates a spy, triggers some method on MySuperModule and checks if MyModule.MethodA() is ever called.
You can create stubs as well if you want to control what dependencies return on specific methods eg :
var MyModuleStub = sinon.stub(MyModule, 'MethodA').returns([...somedata]);
In my view you should certainly be testing the individual functions, regardless of whether or not they're called directly by a user.
The purpose of unit testing is to try to ensure that the individual units of your test do what they're expected to do. If you're (relatively) sure that your individual functions/units behave as expected, you can have more confidence that they'll work nicely with each other.
It's hard to really glean from your code snippets the nature of your module, so suggesting how to implement your tests is difficult. However, it seems like what you're asking is how to verify whether your done/callback function is called and with which arguments.
For that I would recommend using a stub. I usually use sinon but I'm sure other similar tools are available.
var sinon = require( "sinon" );
var should = require( "chai" ).should();
var yourModule = require( "your-module" );
var doneStub = sinon.stub();
yourModule.yourFunction( ..., doneStub );
doneStub.should.have.been.called;
var args = doneStub.getCall( 0 ).args;
args[ 0 ].should.be.eql( ... );
// etc etc
You should also consider using a test runner, I like mocha!
You should do progressive testing. You should test each and every function.
Here how can you proceed.
Write test case for parent function. Mock the inner function where it is calling. You can use sinon library for mocking.
For second question, you can use sinon mock's yield functionality to mock any callback function and you can specify also which output you want from that callback. In this way you can test your function for multiple custom output with different scenario.

Test that a function calls another function in an ES6 module with Sinon.js

I want to test that a function in an ES6 module calls another function using Sinon.js. Here's the basic layout of what I'm doing:
foo.js
export function bar() {
baz();
}
export function baz() {
...
}
test.js
import sinon from 'sinon';
import * as Foo from '.../foo';
describe('bar', function() {
it('should call baz', function() {
let spy = sinon.spy(Foo, 'baz');
spy.callCount.should.eql(0);
Foo.bar();
spy.calledOnce.should.eql(true);
});
});
But the spy does not pick up the call to baz(). Is there some other way I can set up the module or the test to allow sinon to pick this up? My alternative is to make some basic assertion on something baz does, but I obviously don't want to be doing that.
From what I've seen online I'm wondering if this is even possible with the code laid out as-is or if I need to restructure it to get what I want.
You're right in thinking this isn't possible with the way the module is currently structured.
When the code is executed, the baz reference inside function bar is resolved against the local implementation. You can't modify that since outside of the module code there's no access to the internals.
You do have access to exported properties, but you can't mutate these and so you can't affect the module.
One way to change that is using code like this:
let obj = {};
obj.bar = function () {
this.baz();
}
obj.baz = function() {
...
}
export default obj;
Now if you override baz in the imported object you will affect the internals of bar.
Having said that, that feels pretty clunky. Other methods of controlling behaviors exist such as dependency injection.
Also, you should consider whether or not you actually care if baz was called. In standard "black-box testing", you don't care how something is done, you only care what side effects it generated. For that, test if the side effects you expected happened and that nothing else was done.

Node.js, Mocha, make globals in closures available

I am currently setting up some mocha tests using Node and in general they work. I now came across a problem I am not able to resolve.
I have a JS file containing the following: MyClass.js
(General CoffeeScript output for class MyClass + constructor: ->)
EDIT: This is browser code, I just want to use Node to test it. (Is that even desirable?)
(function() {
window.MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
}).call(this);
I now require MyClass.js in my test file. Once I run it, it directly throws an error
Testfile:
var myclass = require('MyClass.js');
...
describe('MyClass', function() { ... });
Error:
ReferenceError: window is not defined.
So far, I understand why this is happening, window does not exist in Node. But I cannot come up with a solution. I actually do not need the real window object specifically, so I thought mocking it would be enough. But it is not...
var window = {},
myclass = require('myclass.js');
...
describe('MyClass', function() { ... });
This command is also not helping: $ mocha --globals window
I still end up with the same error.
Any idea is much appreciated!
You don't actually want the window object, what you want is the global object. Here is some code that can get it in the browser (in which case it will be the same as 'window') or in node (in which case it will be the same as 'global').
var global = Function('return this')();
Then set things on that rather than on 'window'.
Note: there are other ways of getting the global object, but this has the benefit that it will work inside strict mode code too.
With following code you can use your class-like object in web-browser environment and Node.js without modification. (Sorry, I don't know how to translate that to CoffeeScript)
(function (exports) {
var MyClass = (function() {
function MyClass() {
// Do something cool here
}
return MyClass;
})();
exports(MyClass);
})(function (exported) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = exported;
} else if (typeof window !== 'undefined') {
window.MyClass = exported;
} else {
throw new Error('unknown environment');
}
});
As you already have a scope which doesn't pollute global name-space, you could reduce it to:
(function (exports) {
function MyClass() {
// Do something cool here
}
exports(MyClass);
})(function (exported) {
// see above
});
I'm not an expert in AMD, require.js and other module loaders, but I think it should be easy to extend this pattern to support other environments as well.
Edit
In a comment you said that the above solution is not working when translated back to CoffeeScript. Therefore, I suggest another solution. I haven't tried it but maybe this could be a way to solve your problem:
global.window = {}; // <-- should be visible in your myclass.js
require('myclass.js');
var MyClass = global.window.MyClass;
describe('MyClass', function() {
var my = new MyClass();
...
});
It's a horrible piece of code, but if it works, maybe for testing purposes it's sufficient.
Due to the module loading behaviour of node.js this only works if your require('myclass.js') is the first require of this file in the node process. But in case of testing with Mocha this should be true.
1) What you are looking for is the module.exports to expose things in Node:
http://openmymind.net/2012/2/3/Node-Require-and-Exports/
2) Also you don't need IIFE in Node, you can drop the (function() {...
3) You can alway look at some popular Node repo on Github to see examples, look at the Mocha code since you're using it, you'll learn a thing or two.
Something like jsdom is lighter than PhantomJS and yet provides quite a few things you need to test code that expects to be running with a proper window. I've used it with great success to test code that navigates up and down the DOM tree.
You ask:
This is browser code, I just want to use Node to test it. (Is that even desirable?)
It is very desirable. There's a point at which a solution like jsdom won't cut it but as long as your code is within the limit of what jsdom handles, might as well use it and keep the cost of launching a test environment to the minimum needed.
#hgoebl: As I'm not the OP, I can not add his original CoffeeScript code, but here is my example:
pubsub.coffee:
window.PubSub = window.PubSub || {}
PubSub.subscribe = ( subject, callback )->
now the test:
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
PubSub.subscribe 1, 2
what works for me up to now is:
window.PubSub = window.PubSub || {}
window.PubSub.subscribe = ( subject, callback )->
and the test:
`window = {}`
assert = require "assert"
pubsub = require './pubsub.coffee'
describe "pubsub.http interface", ->
it "should perform a http request", ->
window.PubSub.subscribe 1, 2
The main drawback of the solution, is that I have to explicitly mention the window object in the implementation and the test. User code executed in a browser should be able to omit it.
I now came up with an other solution:
window = window || exports
window.PubSub = window.PubSub || {}
PubSub = PubSub || window.PubSub
PubSub.subscribe = ( subject, callback )->
and then in the test, simply requiring the PubSub namespace:
PubSub = require( './pubsub.coffee' ).PubSub
And finally, the solution from kybernetikos applied looks like this:
global = `Function('return this')()`
global.PubSub = global.PubSub || {}
PubSub.subscribe = ( subject, callback )->
As now, the PubSub namespace is in the global namespace, just a simple require is needed in the file that contains the mocha tests:
require( './pubsub.coffee' )

Categories

Resources