Node.js - Pass context through to nested objects in function properties - javascript

I need to make a cleanly name-spaced module in Node.js, break it up into sub-modules via require() and pass the root context/scope all the way to the methods in the name-spaces.
// index.js
var SDK = function(data){
this.data = data;
};
SDK.prototype.Utilities = require('./utilities');
module.exports = function(data) {
return new SDK(data);
};
// utilities.js
module.exports = {
callAPI: function() {
console.log(this.data);
}
};
// Use-case (somewhere in the node.js app...)
var SDK = require('./index')("this is some data");
SDK.Utilities.callAPI();
// Should return "this is some data"
For example:
this in SDK needs to be accessible in SDK.Utilities.callAPI();, like below. Utilities is the name-space I'm referring to.
I'm aware of javascript bind() and call() techniques, but I'm not sure how to use them in this particular case.

You should use apply or call
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
these run the function with the given this scope.

Related

Mocking an anonymous module call in Jasmine using requireJs

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.

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!!");
});

how to mock object created via require

I'm new to node.js and in most code I've seen I don't see IoC/DI style constructor injection of dependencies.
Instead, typically the node.js extension require() is used to create local vars allowing access to external modules' exports.
But when writing unit-tests ( that isolate single layer/function ), how to mock the modules accessed via vars created with require ?
/helpers/dataHelper.js
var dataModel = require('../models/dataModel.js');
var getFormattedDataForRegion = function(region, callback) {
var data = {};
// validate region
// query dataModel
// async.map format data items
// callback(data);
}
/tests/dataHelperTests.js
describe('dataHelper', function(){
it('getFormattedDataForRegion returns expected response', function(done){
var expectedData = {};
// populate expectedData
// **** need some way to mock dataModel *****
dataHelper.getFormattedDataForRegion("west", function(data){
expect(data).to.eql(expectedData);
done();
});
});
This is done with proxyquire.
I personally don't like the technique, but it's the best way that I've found to respect the "node way" and still be able to test easily. You'd do:
var proxyquire = require('proxyquire'),
dataModelMock = require('./mocks/dataModel');
proxyquire('path/to/helpers/dataHelper.js', { '../models/dataModel.js': dataModelMock });

Node.JS allow access to run certain modules within Sandbox Module

I am running Node.JS Sandbox module to create a Child Process and I need to be able to have my String Based Javascript access certain functions and Modules of Node. Right now, the Sandbox module is blocking all access to Node API's and functions outside of the Sandbox.
Example
function GetAccessTo() {
return "I want to call this function"
}
var str = "GetAccessTo();"
var s = new Sandbox();
s.run(str, function (output) {
output.result;
});
To add methods to the context , go to Shovel.js and add methods to var contextand you will be able to call from your Javascript String
Like this:
s.run("hi('something',function(result){return result})", function (output) {
logic = output.result;
});
var context = Script.createContext();
context.hi = function(a,b) {
c="hi"
return b(c)};

Is it Ok to make the exports object a function in CommonJS?

In the case the a CommonJS module only need to return one function, is it good practice to assign it directly to the exports object? (as opposed to assigning it as the only attribute of the exports object)
For example (imaginary log.js module):
module.exports = function(text){console.log(text);}
usage:
var log = require('./log');
log('something');
Yes. I often use this practice myself. It's also a good fit with the revealing module pattern, e.g.:
module.exports = function(db) {
return {
get: function(id, callback) {
// db.get(...)
},
save: function(obj, callback) {
// db.save(...)
}
}
};
It's also widely used in connect (e.g. csrf module) and express (e.g. route).

Categories

Resources