How to spy on a property that is not exported - node.js

I have a module "sitescollection" like this:
var site = require('./site'); // <- this should be stubbed
var sitesCollection = function(spec) {
var that = {};
that.sites = {};
that.findOrCreateById = function(id) {
if (typeof(that.sites[id]) == "undefined") {
that.sites[id] = site({id: id}); // <- its used here
}
return that.sites[id];
};
return that;
};
module.exports = sitesCollection;
so within sitescollection, site is a module that is not exported. But inside the code, i use it. Now i'm writing jasmine specs for #findOrCreateById().
I want to spec my the findOrCreateBy() function. But i want to stub the site() function, because the spec should be independent from the implementation. Where do i have to create the spyed method on?
var sitescollection = require('../../lib/sitescollection');
describe("#findOrCreateById", function() {
it("should return the site", function() {
var sites = sitescollection();
mysite = { id: "bla" };
// Here i want to stub the site() method inside the sitescollection module.
// spyOn(???,"site").andRetur(mysite);
expect(sites.findOrCreateById(mysite.id)).toEqual(mysite);
});
});

You can achieve this using https: //github.com/thlorenz/proxyquire
var proxyquire = require('proxyquire');
describe("#findOrCreateById", function() {
it("should return the site", function() {
// the path '../../lib/sitescollection' is relative to this test file
var sitesCollection = proxyquire('../../lib/sitescollection', {
// the path './site' is relative to sitescollection, it basically
// should be an exact match for the path passed to require in the
// file you want to test
'./site': function() {
console.log('fake version of "./site" is called');
}
});
// now call your sitesCollection, which is using your fake './site'
var sites = sitesCollection();
var mysite = {
id: "bla"
};
expect(sites.findOrCreateById(mysite.id)).toEqual(mysite);
});
});

Related

Automation testing using wd library

I am working with wd library for automation testing that includes mocha as well.
Here is my code
require('colors');
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
chai.should();
var header = require('../pages/header.js');
var wd;
try {
wd = require('wd');
} catch( err ) {
wd = require('../../lib/main');
}
chaiAsPromised.transferPromiseness = wd.transferPromiseness;
describe('mocha spec examples', function() {
this.timeout(10000);
// returning promises and chai-as-promised is the best way
describe("using promises and chai-as-promised", function() {
var browser;
before(function() {
browser = wd.promiseChainRemote();
return browser
.init({browserName:'chrome'})
.setWindowSize(1366, 1024, function(err){
});
});
beforeEach(function() {
return browser.get("http://admc.io/wd/test-pages/guinea-pig.html");
// return browser.get("http://google.com.au");
});
after(function() {
});
it("Validate the Location of Header image", function() {
return console.log(browser.elementByClassName('i_am_a_class')
.parentElement.getAttribute("outerHTML"));
//.getAttribute("outerHTML")
//.then(console.log.bind(console));
});
});
});
I am able to get the element by class name, but I need to get the parent element of the element found as well.
You need XPath and use /.. to get parent.
it("Validate the Location of Header image", function() {
return console.log(browser.elementByXpath('//*[#class="i_am_a_class"]/..').getAttribute("outerHTML"));

How to stub a nodejs "required" constructor using sinon?

I'm writing unit tests for a method that uses the email-templates module like this:
var EmailTemplate = require('email-templates').EmailTemplate;
module.exports = {
sendTemplateEmail: function (emailName, data, subject, to, from) {
var template = new EmailTemplate(__dirname + "/../emails/" + emailName);
data.from = FROM;
data.host = config.host;
return template.render(data)
.then(function (result) {
return mailer.sendEmail(subject, to, from, result.html, result.text);
})
.then(function () {
log.info(util.format("Sent %s email to %s. data=%s", emailName, to, JSON.stringify(data)));
return Promise.resolve();
})
.catch(function (err) {
return Promise.reject(new InternalError(err, "Error sending %s email to %s. data=%s", emailName, to, JSON.stringify(data)));
});
}
};
The unit test looks like this:
var assert = require("assert"),
sinon = require("sinon"),
Promise = require("bluebird"),
proxyquire = require("proxyquire");
describe('mailer#sendTemplateEmail', function () {
var templates,
template;
beforeEach(function() {
templates = {
EmailTemplate: function(path) {}
};
template = {
render: function(data) {}
};
sinon.stub(templates, "EmailTemplate").returns(template);
});
it("should reject immediately if template.render fails", function () {
const TO = {email: "user1#example.com", first: "User"};
const FROM = {email: "user2#example.com", first: "User"};
const EMAIL_NAME = "results";
const SUBJECT = "Results are in!";
const DATA = {
week: 10,
season: "2015"
};
var err = new Error("error");
var mailer = proxyquire("../src/mailer", {
"email-templates": templates
});
sinon.stub(template, "render").returns(Promise.reject(err));
return mailer.sendTemplateEmail(EMAIL_NAME, DATA, SUBJECT, TO, FROM)
.then(function () {
assert.fail("Expected a rejected promise.");
})
.catch(function (err) {
assert(err.message === "error");
assert(mailer.sendEmail.notCalled);
});
});
};
The problem I'm encountering is on the first line of the sendTemplateEmail function which instantiates a new EmailTemplate object. The EmailTemplate constructor being called points to the non-stub EmailTemplate function defined in the beforeEach, rather than the sinon stub created on the last line of the beforeEach. If I evaluate the require('email-templates').EmailTemplate statement, however, it correctly points to the sinon stub. I'd prefer not to have to change my code to call the require statement inline like:
var template = new require('email-templates').EmailTemplate(__dirname + "/../emails/" + emailName);
Is there any way to accomplish the stub the way I'm intending?
You can inject your dependency when you construct your mailer - exp:
function mailer(options) {
options = options || {};
this.email_template = options.email_template;
}
Then in the sendTemplateEmail function - use the email_template member.
Also - not sure about your mailer code - but if you need your mailer to act as a singleton in your code (and it isn't already) - you can add this to your mailer:
module.exports = {
getInstance: function(emailTemplate) {
if(this.instance === null){
this.instance = new mailer(emailTemplate);
}
return this.instance;
}
}
Then when you require your mailer you can use the syntax:
var template = new require('email-templates').EmailTemplate(__dirname + "/../emails/" + emailName);
var mail = mailer.getInstance(template);
This way your application (unit test framework or your actual/real-world application) will determine the type of mailer that will be used for the lifetime of the process.

Ember blueprint that injects environment config?

I'm relatively new to Ember and was wondering if there is a way to create a blueprint/generator that would inject a new value into the environment config while maintaining all existing configuration. Is there some Ember magic that allows an existing file to act as the blueprint template? My ideal implementation would look something like this:
ember g platform foo
// config/environment.js
module.exports = function(environment) {
var ENV = {
// Existing config values here...
APP: {
platforms: {
foo: 'abc123' // Generator injects the 'foo' platform and a GUID
}
};
// Existing environment-specific settings here...
return ENV;
};
Is this something that would be more easily accomplished using Node's fs.readFile() and fs.writeFile()? If so, how could I parse environment.js?
No there's no existing magic in Ember to my knowledge sorry. When you generate a route, something very similar to what you are talking about happens but the code is rather complex. The ember generate route new_route function has a call to this function
function addRouteToRouter(name, options) {
var routerPath = path.join(options.root, 'app', 'router.js');
var source = fs.readFileSync(routerPath, 'utf-8');
var routes = new EmberRouterGenerator(source);
var newRoutes = routes.add(name, options);
fs.writeFileSync(routerPath, newRoutes.code());
}
which then exectutes interpreter level like code to add the router and revert it back to code:
module.exports = EmberRouterGenerator;
var recast = require('recast');
var traverse = require('es-simpler-traverser');
var Scope = require('./scope');
var DefineCallExpression = require('./visitors/define-call-expression.js');
var findFunctionExpression = require('./helpers/find-function-expression');
var hasRoute = require('./helpers/has-route');
var newFunctionExpression = require('./helpers/new-function-expression');
var resourceNode = require('./helpers/resource-node');
var routeNode = require('./helpers/route-node');
function EmberRouterGenerator(source, ast) {
this.source = source;
this.ast = ast;
this.mapNode = null;
this.scope = new Scope();
this.visitors = {
CallExpression: new DefineCallExpression(this.scope, this)
};
this._ast();
this._walk();
}
EmberRouterGenerator.prototype.clone = function() {
var route = new EmberRouterGenerator(this.source);
return route;
};
EmberRouterGenerator.prototype._ast = function() {
this.ast = this.ast || recast.parse(this.source);
};
EmberRouterGenerator.prototype._walk = function() {
var scope = this.scope;
var visitors = this.visitors;
traverse(this.ast, {
exit: function(node) {
var visitor = visitors[node.type];
if (visitor && typeof visitor.exit === 'function') {
visitor.exit(node);
}
},
enter: function(node) {
var visitor = visitors[node.type];
if (visitor && typeof visitor.enter === 'function') {
visitor.enter(node);
}
}
});
};
EmberRouterGenerator.prototype.add = function(routeName, options) {
if (typeof this.mapNode === 'undefined') {
throw new Error('Source doesn\'t include Ember.map');
}
var route = this.clone();
var routes = route.mapNode.arguments[0].body.body;
route._add.call(
route,
routeName.split('/'),
routes,
options
);
return route;
};
EmberRouterGenerator.prototype._add = function(nameParts, routes, options) {
options = options || {};
var parent = nameParts[0];
var name = parent;
var children = nameParts.slice(1);
var route = hasRoute(parent, routes);
if (!route) {
if (options.type === 'resource') {
route = resourceNode(name, options);
routes.push(route);
} else {
route = routeNode(name, options);
routes.push(route);
}
}
if (children.length > 0) {
var routesFunction = findFunctionExpression(route.expression.arguments);
if (!routesFunction) {
routesFunction = newFunctionExpression();
route.expression.arguments.push(routesFunction);
}
this._add(children, routesFunction.body.body, options);
}
};
EmberRouterGenerator.prototype.remove = function(routeName) {
if (typeof this.mapNode === 'undefined') {
throw new Error('Source doesn\'t include Ember.map');
}
var route = this.clone();
var routes = route.mapNode.arguments[0].body.body;
var newRoutes = route._remove.call(
route,
routeName.split('/'),
routes
);
if (newRoutes) {
route.mapNode.arguments[0].body.body = newRoutes;
}
return route;
};
EmberRouterGenerator.prototype._remove = function(nameParts, routes) {
var parent = nameParts[0];
var name = parent;
var children = nameParts.slice(1);
var route = hasRoute(parent, routes);
var newRoutes;
if (children.length > 0) {
var routesFunction = route.expression && findFunctionExpression(route.expression.arguments);
if (routesFunction) {
newRoutes = this._remove(children, routesFunction.body.body);
if (newRoutes) {
routesFunction.body.body = newRoutes;
}
return routes;
}
} else {
if (route) {
routes = routes.filter(function(node) {
return node !== route;
});
return routes;
} else {
return false;
}
}
};
EmberRouterGenerator.prototype.code = function(options) {
options = options || { tabWidth: 2, quote: 'single' };
return recast.print(this.ast, options).code;
};
So then there's the alternative, which involves reading the file, adding in your new environment in the correct place after parsing the file correctly, and then writing the stream back. The complexity of what you are wanting to do probably outweighs the time it would take to do this manually IMO. If this is something you are doing often, maybe consider writing a script in another language that's better(read as more people use it for this) at textual file manipulation

Initialize a module when it's required

I have a module with some initialization code inside. The init should be performed when the module is loaded. At the moment I'm doing it like this:
// in the module
exports.init = function(config) { do it }
// in main
var mod = require('myModule');
mod.init(myConfig)
That works, but I'd like to be more concise:
var mod = require('myModule').init('myConfig')
What should init return in order to keep mod reference working?
You can return this, which is a reference to exports in this case.
exports.init = function(init) {
console.log(init);
return this;
};
exports.myMethod = function() {
console.log('Has access to this');
}
var mod = require('./module.js').init('test'); //Prints 'test'
mod.myMethod(); //Will print 'Has access to this.'
Or you could use a constructor:
module.exports = function(config) {
this.config = config;
this.myMethod = function() {
console.log('Has access to this');
};
return this;
};
var myModule = require('./module.js')(config);
myModule.myMethod(); //Prints 'Has access to this'

How to use requires to return constructor functions that have dependencies

How do you correctly use Require.js to load a module that returns a constructor function that has require dependencies?
My problem seems to be a scope issue, I have seen some modules that are available within the returned constructor like "durandal/app" and I dont see how they are scoped any different than the modules I have defined.
This example is modified from Durandal Creating a Module docs
define([**someothermodule**, "durandal/app"], function(**someothermodule**, app){
var backend = function(username, password){
this.username = username;
this.password = password;
someothermodule.whatever(); <--someothermodule is not defined
app.whatever(); <-- this is in scope
};
backend.prototype.getCustomers = function(){
//do some ajax and return a promise
};
return backend;
});
define([backend], function(backend){
return {
customers:ko.observableArray([]),
activate:function(){
var that = this;
var service = new backend('username', 'password');
return service.getCustomers().then(function(results){
that.customers(results);
});
}
};
});
Someothermodule:
define([], function(){
var whatever = function(){
alert("whatever");
};
return {
whatever: whatever
};
});
index in the example above has two issues. a) in define [backend] is used instead of ['backend'] and b) ko is used without defining it. Both probably copy/paste errors.
Assuming that someothermodule lives in the same directory as index.js it's sufficient to define it like
define(['./someothermodule', ...], function( someothermodule, ... )
Here's the complete example:
backend.js
/*globals define*/
define(['./someothermodule', 'durandal/app', 'jquery'], function( someothermodule, app, $ ) {
"use strict";
var backend = function( username, password ) {
this.username = username;
this.password = password;
this.whatever = someothermodule.whatever();
app.trigger('whatever', this.whatever);
};
backend.prototype.getCustomers = function() {
//do some ajax and return a promise
return $.getJSON('app/so/19551060/fixtures/customer.json');
};
return backend;
});
someothermodule.js
/*globals define*/
define(function(){
"use strict";
var whatever = function(){
return 'whatever return value';
};
return {
whatever: whatever
};
});
index.js
/*globals define*/
define(['./backend', 'knockout'], function(backend, ko){
"use strict";
return {
customers:ko.observableArray([]),
activate:function(){
var that = this;
var service = new backend('username', 'password');
return service.getCustomers().then(function(results){
that.customers(results);
});
}
};
});
Live version available at: http://dfiddle.github.io/dFiddle-2.0/#so/19551060

Resources