Mocking an anonymous module call in Jasmine using requireJs - javascript

Current unit testing setup:
Jasmine 2.1
RequireJs 2.1.15
Chutzpah 3.2.6
In our code base we have a number of modules which are loaded in through requireJs to abstract out functionality. For example communications which abstracts away calls to the server. However these modules return an anonymous function:
define(['jquery'], function ($) {
return function (method, link, payload) {
// code removed as not required for question
return $.ajax({
type: method,
url: link,
data: payload
});
};
})
This is then imported through requireJs/AMD loading by other modules and used in the following way:
var promise = communicator("GET", "/url/to/my/webapi", {});
I currently have a mock module which gets imported for the unit tests bypassing the $.ajax call and returns a promise however I really want to test in my unit tests that it has been called or not and the correct values have been passed in etc. I have tried looking at spies however as it doesn't expose a named function on the module I am unable to use this method as far as I can tell.
How can I go about setting up expectations/mocking an anonymous AMD returned function?
EDIT
Example of usage to aid with clarity:
define(['communicator'], function (communicator) {
var vm = function (id) {
var self = this;
self.Id = id
self.submitForm = function () {
var data = { };
var promise = communicator("PUT", "/url/to/web/api", data);
promise.done(function (message) {
});
promise.fail(function (error) {
});
};
};
return {
initialise: function (params) {
var viewModel = new vm(params.Id);
return viewModel;
}
};
});
I want to be able to test the submitForm function (simplified for question purposes) and want to mock the communicator dependency without defining a stubbed additional module in the testing project require.js setup.

I'm not sure exactly what you need to test, but you could spyOn $.ajax and create your own promise...
window.spyOn($, "ajax").and.callFake(function() {
var d = $.Deferred();
d.resolve(true);
return d.promise();
});
expect($.ajax).toHaveBeenCalled();
// other expects...

In the end I went with changing the module to have specific methods on which could then be spied on. I have other modules which are of the same pattern though so will continue on my quest.

Related

How to sinon spy module export utility functions

In javascript (ES6), I have a utility module which just contains some functions, and then in the end of the file, I export them like so:
module.exports = {
someFunction1,
someFunction2,
someFunction3,
}
Then I want to write unit tests for those functions. Some of the functions depend on each other; they call each other in a way, that for example, someFunction1 might call someFunction2. There's no circular problems.
Everything works well, until I need to spy that one of the functions is called. How can I do it? Currently I'm using Chai and Sinon.
In the test file, I have imported the whole file as a module:
const wholeModule = require('path/to/the/js/file')
And finally, my test looks like following:
it('should call the someFunction2', (done) => {
const spy = sinon.spy(wholeModule, 'someFunction2')
wholeModule.someFunction1() // someFunction2 is called inside someFunction1
assert(spy.calledOnce, 'someFunction2 should be called once')
done()
})
The problem is, that the test fails, because in someFunction1, the someFunction2 function is used directly. I apply the spy to the module object's function. But that's a different object. Here's an example of the someFunction1:
function someFunction1() {
someFunction2()
return 2;
}
I know the reason why it won't work, but I don't know what would be the best practise in this case to make it work? Please help!
You can use rewire module. Here is an example:
Source code:
function someFunction1() {
console.log('someFunction1 called')
someFunction2();
}
function someFunction2() {
console.log('someFunction2 called')
}
module.exports = {
someFunction1: someFunction1,
someFunction2: someFunction2
}
Test case:
'use strict';
var expect = require('chai').expect;
var rewire = require('rewire');
var sinon = require('sinon');
var funcs = rewire('../lib/someFunctions');
it('should call the someFunction2', () => {
var someFunction2Stub = sinon.stub();
funcs.__set__({
someFunction2: someFunction2Stub,
});
someFunction2Stub.returns(null);
funcs.someFunction1();
expect(someFunction2Stub.calledOnce).to.equal(true);
});
As you are already aware this happens because you are stubbing the exported reference not the actual method in the module. It works in any module that includes the one you are replacing since they include the exported references but when inside the same module it's just calling the local function.
The easiest solution I've found is just to call the reference:
function someFunction1() {
this.someFunction2()
return 2;
}

How to spy on a method inside a dependent module using jasmine-node

I am trying to write jasmine tests for a module-(say moduleA) which 'requires' another module-(moduleB).
======> moduleB.js
function moduleBFunction(){
console.log('function inside moduleB is called');
}
======> moduleA.js
var moduleB = require('./moduleB');
function moduleAfunction(input){
if(input){
moduleB.moduleBFunction()
}
}
I want to write a jasmine test case that tests when i call moduleAfunction, is it calling moduleBfunction or not. I tried to write a test using spyOn(). but i am not sure how can i mock a method inside a dependent module. I did some research and found i might be able to use 'rewire' module for this purpose like below
var moduleB = require('../moduleB');
moduleB.__set__('moduleBfunction', moduleBfunctionSpy);
moduleA.__set__('moduleB', moduleB);
it('should call moduleBfunction', function(){
moduleA.moduleAfunction()
expect(moduleB.moduleBfunction()).toHaveBeenCalled()
});
but I feel there should be a simpler way.
Please suggest.
I recommend sinon.js
var sinon = require('sinon')
var moduleA = require('../moduleA')
var moduleB = require('../moduleB')
it('should call moduleBfunction', function() {
var stub = sinon.stub(moduleB, 'moduleBfunction').returns()
moduleA.moduleAfunction()
expect(moduleB.moduleBfunction.calledOnce)
stub.restore()
})
You can easily fake many different behaviours like:
stub throws
stub returns a certain value
stub yields (mimicking async callback)
stub works restricted with just for certain input arguments
Don't forget to restore each stub before executing the next test. It's best to use sandboxes and afterEach / beforeEach
describe('tests which require some fakes', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
})
afterEach(function() {
sandbox.restore()
})
})

How do I test a function which returns a function using Mocha, Sinon, and Chai?

I have a function which returns another function of the same name. Inside the second function, functions from other modules are being used. I just want to test whether the functions from other modules are being called.
Here is some code to clarify what I mean:
exports.getCache = function (model) {
return function getCache (req, res){
//some code
key = utils.uniqueKey(model, id)
//some code
res.json(result);
}
}
I want to check if uniqueKey is being called and if res.json is being called.
Any help at all is appreciated, thanks!
You can simply write:
sinon.spy(utils, 'uniqueKey')
in your test file, probably inside beforeEach function. Then it should be easy to check with chai.expect function whenever it was called:
expect(utils.uniqueKey.called).to.be.true();
expect(utils.uniqueKey.calledWith({modelValue: 'value'}, 'someId')).to.be.true();
where {modelValue: 'value'} and 'someId' are the actual values of model and id variables.
To make your component testable you have to make its dependencies injectable. As I see your code depends on utils. To properly mock this you can't just require('utils'), you have to implement some way to wire up dependencies. Using some DI library, or just extend public interface of your component:
var utils;
module.exports.dependencies = function (_utils) {
utils = _utils;
};
module.exports.getCache = function (model) {
key = utils.uniqueKey(model, id);
};
Then in productive code before using bootstrap your component calling component.dependencies(require('utils')). In test case you can pass there a spy: component.dependencies(spy);

Stub out module function

Edit: Being a little bit more precise.
I want to test usecases for a Github API wrapper extension, that our team has created. For testing, we don't want to use API wrapper extension directly, so we want to stub out its functions. All calls to the API wrapper should be stubbed out for the tests, not just creating a clone stub.
I have a module "github" in Node.js:
module.exports = function(args, done) {
...
}
And I am requiring it like this:
var github = require('../services/github');
Now, I would like to stub out github(...) using Sinon.js:
var stub_github = sinon.stub(???, "github", function (args, callback) {
console.log("the github(...) call was stubbed out!!");
});
But sinon.stub(...) expects from me to pass an object and a method and does not allow me to stub out a module that is a function.
Any ideas?
There might be a way to accomplish this in pure Sinon, but I suspect it would be pretty hacky. However, proxyquire is a node library that is designed for solving these sort of issues.
Supposing you want to test some module foo that makes use of the github module; you'd write something like:
var proxyquire = require("proxyquire");
var foo = proxyquire(".foo", {"./github", myFakeGithubStub});
where myFakeGithubStub can be anything; a complete stub, or the actual implementation with a few tweaks, etc.
If, in the above example, myFakeGithubStub has a property "#global" set as true, (i.e. by executing myFakeGithubStub["#global"] = true) then the github module will be replaced with the stub not only in the foo module itself, but in any module that the foo module requires. However, as stated in the proxyquire documentation on the global option, generally speaking this feature is a sign of poorly designed unit tests and should be avoided.
I found that this worked for me...
const sinon = require( 'sinon' );
const moduleFunction = require( 'moduleFunction' );
// Required modules get added require.cache.
// The property name of the object containing the module in require.cache is
// the fully qualified path of the module e.g. '/Users/Bill/project/node_modules/moduleFunction/index.js'
// You can get the fully qualified path of a module from require.resolve
// The reference to the module itself is the exports property
const stubbedModule = sinon.stub( require.cache[ require.resolve( 'moduleFunction' ) ], 'exports', () => {
// this function will replace the module
return 'I\'m stubbed!';
});
// sidenote - stubbedModule.default references the original module...
You have to make sure that you stub the module (as above) before it's required elsewhere...
// elsewhere...
const moduleFunction = require( 'moduleFunction' );
moduleFunction(); // returns 'I'm stubbed!'
Simplest solution is to refactor your module:
instead of this:
module.exports = function(args, done) {
...
}
do this:
module.exports = function(){
return module.exports.github.apply(this, arguments);
};
module.exports.github = github;
function github(args, done) {
...
}
Now you can require it with:
const github = require('../services/github.js');
//or
const github = require('../services/github.js').github;
To stub:
const github = require('../services/github.js');
let githubStub = sinon.stub(github, 'github', function () {
...
});
If you are doing
var github = require('../services/github');
in global scope, then you can using 'global' as the object and 'github' as the method to be stubbed out.
var stub_github = sinon.stub(global, "github", function (args, callback) {
console.log("the github(...) call was stubbed out!!");
});

Can I add a method to a requirejs module used as dependency in another module and have it available every time the module is loaded as dependency?

If I have a module like this:
define([
'app'
, 'text!index.html!strip'
, 'css!index'
],
function (App, source) {
var response = {};
App.newMethod = function (foo) {
console.log("foo ="+foo);
};
// return response object
return response;
}
);
I'm wondering how to add methods to a module that is used as a dependency in another module. Sure I can add methods to the object, but will these also update the App object when it is called from another module?
Question:
Is there a way to add methods to a module, which is loaded as a dependency and have these methods available on all modules, which require this dependency?
Short answer:
Yes. The module needs to be an object/instance (not a class) and it will work with requirejs.
Long answer:
When you require a module as a dependence for the first time Requirejs generates an object, and for the next times you requires the module Requirejs will return the object it generated the first time. So all the times you require a module you get always the same reference of the object.
With
define([], function () {
var app = {
//my methods.
};
return app;
});
and
define(['app'], function (app) {
app.newMethod = function (){
// ...
};
});
you can use app like this:
define(['app'], function (app) {
app.newMethod();
});
But injecting methods from one object to an other is a really bad practice. If you need something from an object just add it when creating the object, not by injection.
define([], function () {
var app = {
newMethod: function () {
// ...
},
// my methods.
};
return app;
});
For example if object A injects a new method that will be used in object B, but B is called when A is not loaded then there would be an error Object #<Object> has no method 'newMethod'

Categories

Resources