node.js unit testing mock dependency - javascript

I have a question on using proxyquire (or any other suggestions on how to test the following code)
If i have the following file to test:
var path = require('path');
module.exports = function (conf) {
var exported = {};
exported.getIssue = function (issueId, done) {
...
...
};
return exported;
};
How do i pass in the 'conf' variable while using proxyquire to mock 'path; var?
Is there any other way to do this if not using proxyquire?

You simply have to pass conf variable to the module/function required via proxyquire. Proxyquire has meaning to to do the same CommonJs require stuff, but with the possibility of mocking and stubing some modules. So you should act the same.
var pathMock = {
someMethod = function() {}
};
var confMock = {
someMethod = function() {}
};
spyOn(pathMock, 'someMethod').and.callThrough();
spyOn(confMock, 'someMethod').and.callThrough();
module = proxyquire('../path/to/module', {
path: pathMock
});
it('do some test', function(done) {
module(conf).getIssue();
expect(pathMock.someMethod).toHaveBeenCalled;
expect(confMock.someMethod).toHaveBeenCalled;
});

Related

Accept argument in node_module require

I am creating a node module and I am hoping to force the user to pass an argument during module require.
Like this:
const sample = require('sample-module')('username')
Inside my sample-module, I have declared the public functions like this (these are imports from other files):
module.exports = {
addNewFolder: folderHandler.addNewFolder,
printToFile: printHandler.printToFile,
deleteFolder: folderHandler.deleteFolder
// more functions
}
// Here I want to add a function that will accept the argument passed.
function setUserName(name) {
// some handling here, in this case, 'name' is 'username' as we passed in during require
}
How can I do this?
Lastly, I prefer to require using like this:
const sample = require('sample-module')('username')
Rather than:
const sample = require('sample-module')
sample.setUserName('username')
Help anyone? Thanks!
You can change module.exports to function like this
const test = (arg) => {
console.log(arg);
};
module.exports = function (requireArg) {
return {
test: test(requireArg),
};
};
then require it
const { test } = require('./test')('apple');

Using proxyquire in a browserify factor bundle

Stuck with this one.
I am using laravel elxir with tsify to generate my js. I run the typescript through factor-bundle to split common js modules into a seperate files. I don't think though that will be a problem in this case because everything is in a spec.js
spec.ts
/// <reference path="../../../typings/index.d.ts" />
import "jasmine-jquery";
// #start widgets
import "./widgets/common/widget-factory/test";
factory-widget/index.ts
export class WidgetFactory {
.... this contains a require call to browser.service which i need to mock
}
factory-widget/test.ts
...
import {WidgetFactory} from "./index";
const proxyRequire = require("proxyquire");
it("should output the factory items", ()=> {
proxyRequire('./widgets/browser.service/index',{
"#global": true,
});
}
browser-service.ts
...
export class BrowserService implements IBrowserService{
//details
}
Getting an error Uncaught TypeError: require.resolve is not a function on line 262.
Here is the code ( yeah it's over 20,000 lines ) how else are you supposed to debug this stuff . ¯_(ツ)_/¯
I've looked at Stubbing with proxyquire. I am not holding my breath getting an answer on this one.
Edit: 06-09-2016
Proxquire is needed to overide the require call in the boot method of the WidgetFactory class
In factory-widget/index.ts:
boot(output = true):any {
let required = {};
if (this._sorted.length) {
this._sorted.forEach((key)=> {
if (output) {
console.log(`${this._path}${key}/index`);
// this is where is need to overide the call to require.
required[key] = require(`${this._path}${key}/index`);
}
});
this._sorted.forEach((key)=> {
let dependencies = {},
module = this._factory[key];
if (module.hasOwnProperty(this.dependencyKey)) {
module[this.dependencyKey].map((key)=> {
dependencies[_.camelCase(key)] = this.isService(module) ? new required[key] : key;
});
}
if (this.isTag(module)) {
if (output) {
document.addEventListener("DOMContentLoaded", ()=> {
riot.mount(key, dependencies);
});
}
//console.log(key,dependencies);
}
else {
}
})
}
}
I've added a proxyquireify example to the tsify GitHub repo. It's based on the simple example in the proxyquireify README.md.
The significant parts are the re-definition of require to call proxyquire in foo-spec.ts:
const proxyquire = require('proxyquireify')(require);
require = function (name) {
const stubs = {
'./bar': {
kinder: function () { return 'schokolade'; },
wunder: function () { return 'wirklich wunderbar'; }
}
};
return proxyquire(name, stubs);
} as NodeRequire;
and the configuration of the proxyquire plugin in build.js:
browserify()
.plugin(tsify)
.plugin(proxyquire.plugin)
.require(require.resolve('./src/foo-spec.ts'), { entry: true })
.bundle()
.pipe(process.stdout);
If you build the bundle.js and run it under Node.js, you should see that the message written to the console includes strings returned by the functions in the stubbed ./bar module.

Cannot access variables outside scope in browser context

Using protractor for angular e2e tests. I have a scope problem with the addMockModule. The spec states:
The JavaScript to load the module. Note that this will be executed in
the browser context, so it cannot access variables from outside its
scope.
https://angular.github.io/protractor/#/api?view=Protractor.prototype.addMockModule
browser.addMockModule('modName', function() {
angular.module('modName', []).value('foo', 'bar');
});
Problem: I am trying to pass another function Mockr to my mock module. I want to set and get a mock id.
steps.js
var mockData = require('../../mocks/data.js');
var Mockr = require('../../mocks/mockr.js');
var steps = function() {
this.Before(function(scenario, done) {
browser.addMockModule('httpBackEndMock', mockData.module, Mockr );
done();
});
};
module.exports = steps;
data.js
exports.module = function ( Mockr ) {
angular.module('httpBackEndMock', ['ngMockE2E'])
.run(function($httpBackend) {
// cannot access Mockr here...
// since this is in browser context scope,
// how can I access Mockr???
// like: Mockr.getMockId();
});
};
mockr.js
module.exports = {
id: 5,
setMockId: function(id) {
module.exports.id = id;
},
getMockId: function() {
return module.exports.id;
}
};

Node JS call a "local" function within module.exports

How do you call a function from within another function in a module.exports declaration?
I have MVC structure node js project and a controller called TestController.js. I want to access method within controller, but using this keyword gives below error:
cannot call method getName of undefined
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
this.getName(data);
},
getName : function(data) {
// code
}
}
How do I access methods within controller?
I found the solution :-)
"use strict"
var self = module.exports = {
myName : function(req, res, next) {
// accessing method within controller
self.getName(data);
},
getName : function(data) {
// code
}
}
You can access the getName function trough module.exports. Like so:
"use strict"
module.exports = {
myName : function(req, res, next) {
// accessing method within controller
module.exports.getName(data);
},
getName : function(data) {
// code
}
}
Maybe you could do it like this. It reduce nesting. And all your export is done at the end of your file.
"use strict";
var _getName = function() {
return 'john';
};
var _myName = function() {
return _getName();
};
module.exports = {
getName : _getName,
myName : _myName
};
If you want to use the function locally AND in other files...
function myFunc(){
return 'got it'
}
module.exports.myFunc = myFunc;
I know the answer is already accepted, but I feel the need to add my two cents on the issue.
Node modules have a "Singletonic" nature, when inside the module, you are the module.
In my opinion, at least design pattern wise, inner module methods can be accessed more cleanly, without the need for this or a copy of self for that matter.
Using this, could be dangerous, if one happens to send the separate methods around and forgets to use .bind.
Using a copy of self, is redundant, we already are inside a Singleton behaving module, why keep a reference to yourself when you can avoid that?
Consider these instead:
Option 1
// using "exports."
exports.utilityMethod = (..args) => {
// do stuff with args
}
exports.doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
exports.utility(someParam)
}
Option 2
// using module.exports
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
// either this
module.exports = {
utility,
doSomething,
}
// or
module.exports = {
customNameForUtility: utility,
customNameForDoSomething: doSomething
}
This works the same for es6 modules:
Option 1 (ES6)
export const utilityMethod = (..args) => {
// do stuff with args
}
export const doSomething = (someParam) => {
// this always refers to the module
// no matter what context you are in
utility(someParam)
}
Option 2 (ES6)
const utility = (..args) => {
// do stuff with args
}
const doSomething = (someParam) => {
// Inside the module, the utility method is available
// to all members
utility(someParam)
}
export default {
doSomething,
utility
}
// or
export {
doSomething,
utility
}
Again, this is just an opinion, but it looks cleaner, and is more consistent across different implementations, and not a single this/self is used.

ES6: Save variable into module scope

I'd like to know if and how it's possible to save the following config into my modules scope (think of the block below as one module):
var config = null;
var mySingleton = {
init: function(config) {
config = config; // Naming conflict!
},
printConfig: function() {
console.log(config); // Undefined!
}
};
export { mySingleton };
Unfortunately, a naming conflict occurs. I'd need something like module.config = config;.
Note: I'm using the es6-module-transpiler.
No. It's a simple variable, and not a global one (where it would be accessible as a property of the global object), so it just is shadowed and not available "namespaced".
You need to use a different name to resolve conflicts, which should be trivial and will cause no effects outside the module:
var config = null;
var mySingleton = {
init: function(conf) {
config = conf;
},
printConfig: function() {
console.log(config);
}
};
export { mySingleton };

Categories

Resources