Automation testing using wd library - node.js

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

Related

How to test for an event to have been fired and its value?

I couldn't find any working examples to test for whether an event was emitted and whether the emitted value is as expected.
Here is the class that emits messages and its parent:
const EventEmitter = require('events').EventEmitter;
class FileHandler extends EventEmitter {
constructor() {
super();
}
canHandle(filePath) {
emit('not super type');
}
parseFile(filePath) {
emit('supper parsing failed');
}
whoAmI() {
return this.emit('who',"FileHandler");
}
}
module.exports = FileHandler;
//diff file
const FileHandler = require('./FileHandler');
class FileHandlerEstedamah extends FileHandler {
constructor() {
super();
}
canHandle(filePath) {
this.emit('FH_check','fail, not my type');
}
parseFile(filePath) {
this.emit('FH_parse','success');
}
}
module.exports = FileHandlerEstedamah;
Here is my current test code:
var sinon = require('sinon');
var chai = require('chai');
const FileHandlerEstedamah = require("../FileHandlerEstedamah");
describe('FH_parse', function() {
it('should fire an FH_parse event', function(){
const fhe = new FileHandlerEstedamah();
var fhParseSpy = sinon.spy();
fhe.on('FH_parse',fhParseSpy);
fhe.parseFile("path");
//I tried a large number of variants of expect, assert, etc to no avail.
});
});
I expected this to be straightforward but somehow I am missing something.
Thank you,
Jens
You can assert the spy was called once and called with expected arguments as below
sinon.assert.calledOnce(fhParseSpy);
sinon.assert.calledWith(fhParseSpy, 'success');
You almost nearly there. To check the value, we must call done() after that in mocha to tell that our test is finish.
The code
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');
const FileHandlerEstedamah = require("../FileHandlerEstedamah");
describe('FH_parse', function() {
it('should fire an FH_parse event', function(done){ // specify done here
const fhe = new FileHandlerEstedamah();
fhe.on('FH_parse', (data) => {
assert.equal(data, 'success'); // check the value expectation here
done(); // hey mocha, I'm finished with this test
});
fhe.parseFile("path");
});
});
Hope it helps

Best way to pass data to a Mocha test that's run programmatically?

Trying to solve a problem where I can't seem to pass dynamically gathered data to Mocha tests.
Here is the logic of my application:
Client submits their Github url. Request is made to Express/Node application.
Express/Node application takes repo and username and makes request to Github API for data and adds the content of the files to an object as base64.
The object with the files are passed to the relevant test files and then executed.
The results are processed and preliminary grades are created. These are then sent back to the client.
Here is what a test file can look like:
const chai = require('chai');
const chaiSubset = require('chai-subset');
chai.use(chaiSubset);
const expect = chai.expect;
const base64 = require('base-64');
const HTML_CONTENT = require('../../00-sandbox-files/basic-portfolio-solution.json').html;
const CSS_CONTENT = require('../../00-sandbox-files/basic-portfolio-solution.json').css;
const decodedCSS = base64.decode(CSS_CONTENT[1].content);
const cheerio = require('cheerio');
const juice = require('juice');
let decodedHTMLcontact;
let decodedHTMLindex;
let decodedHTMLportfolio;
for (const obj in HTML_CONTENT) {
if (HTML_CONTENT[obj].path == "contact.html") {
decodedHTMLcontact = base64.decode(HTML_CONTENT[obj].content);
} else if (HTML_CONTENT[obj].path == "index.html") {
decodedHTMLindex = base64.decode(HTML_CONTENT[obj].content);
} else if (HTML_CONTENT[obj].path == "portfolio.html") {
decodedHTMLportfolio = base64.decode(HTML_CONTENT[obj].content);
}
}
tests = function (html, css) {
describe('HTML Elements tests that should pass for contact.html', function () {
let $ = cheerio.load(decodedHTMLcontact);
describe('HTML Elements that should exist in contact.html', function () {
it('should contain a header element', function () {
expect($('body').find('header').length).to.equal(1);
});
it('should contain a section element', function () {
expect($('body').find('section').length).to.equal(1);
});
it('should contain several anchor elements', function () {
expect($('nav').find('a').length).to.be.at.least(3, 'You need an additional anchor elements for your navigation elements');
});
it('should contain an h1 element', function () {
expect($('body').find('h1').length).to.equal(1);
});
it('should contain a form element', function () {
expect($('body').find('form').length).to.equal(1);
});
it('should contain a footer element', function () {
expect($('body').find('footer').length).to.equal(1);
});
});
Here is the execution file for the Mocha tests:
const Mocha = require('mocha');
// Instantiate a Mocha instance.
const mocha = new Mocha();
const HW_PORTFOLIO_PATH = './server/05-run-testing-suite/HW-Week1-portfolio-wireframe/HW-1-portfolio.js';
function homeworkRouter(contentObj, repo) {
switch (repo) {
case "Basic-Portfolio":
mocha.addFile(HW_PORTFOLIO_PATH);
break;
case "HW-Wireframe":
mocha.addFile('./server/05-run-testing-suite/HW-Week1-portfolio-wireframe/HW-1-wireframe.js');
break;
default:
console.log("No homework provided");
break;
}
}
module.exports = {
// Run the tests and have info about what can be returned
runTests: function(contentObj, repo) {
homeworkRouter(contentObj, repo);
console.log("Content Object", contentObj);
console.log("Repo", repo);
mocha.run()
.on('fail', function (test, err) {
console.log('Test fail');
console.log(err);
})
.on('end', function () {
console.log('All done');
});
}
}
Solutions we've come up with involve using vm(), setting data into globals, and/or building up and tearing down files. I'd like a solution that it's much more efficient and doesn't pollute global.

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.

NodeJS - How to test index.js without module.exports

I'm testing my NodeJs project using Mocha and I have a file, index.js that is the main file without module.exports that is run like a CLI
index.js
// CLI tools
var bluebird = require('bluebird');
var gigatool = require('./lib/gigatool');
var debug = require('debug')('index');
var size = 20;
var page = process.env.BATCH;
var startDate = process.env.START;
var dataDir = process.env.DATADIR;
debug(page, startDate, dataDir);
// requires parameters
if (!process.env.BATCH) {
throw new Error('BATCH environment variable is needed');
}
tool = gigatool(size, page, dataDir);
bluebird.all([tool.clean(startDate), tool.continuous()])
.finally(function(){
process.exit(0);
});
test.js
'use strict';
var chai = require('chai');
var fs = require('fs');
var noop = require('lodash.noop');
var rimraf = require('rimraf');
var async = require('async');
var rimraf = require('rimraf');
var expect = chai.expect;
describe.only('Integration', function() {
var dataDir = './countries';
var path = dataDir + '/Albania';
describe('clean run', function() {
this.timeout(10000);
before(function() {
process.env.BATCH = 1;
process.env.DEBUG = '*';
require('../../index');
});
after(function(done) {
// rimraf(dataDir, done);
});
});
});
if I run require('./index'), it will run the module and then continue to move forward, how can i wait for it to end before i run test cases?
Note: It is calling some apis
You need to test your whole application at once, this is still testing but hardly "unit" testing unless your code is a unit ("the unix way"). For this reason your code should start with:
var Promise= require("bluebird");
var exec= Promise.promisify(require("child_process").exec);
var run = function(args){
return exec("node", ["../../index.js"].concat(args)).get("stdout");
};
Which would make your tests test the actual inputs on the file:
describe('your code', function() {
it('should work with params a,b', function(){
return run(['a','b']).then(function(out){ // note the Mocha promise syntax
assert.equal(out, 'your expected stdout');
});
});
});
Unfortunately, there is no way to unit test individual aspects of a CLI Node script as you have it. Instead, what I've done in the past is have conditional execution based on whether the script was used via require or called from the command line:
// index.js
var foo = require('foo');
var bar = require('bar');
// ...
// determine if this script is being required as a module or is CLI
var IS_EXECUTING = (require.main === module);
var methods = {
init: function(args) {
methods.auditArgs(args);
methods.doSomeStuff(arg1, arg2);
methods.doOtherStuff();
},
auditArgs: function(args) {/* ... */},
doSomeStuff: function(arg1, arg2) {/* ... */},
// ...
};
// At the bottom we either begin execution or return a function which can
// be called in a test harness when ready...
if (IS_EXECUTING) {
methods.init(process.argv);
} else {
module.exports = function (mockMethods) {
// you could have some code here to mock out provided methods
// for example:
methods.auditArgs = mockMethods.auditArgs || methods.auditArgs;
// then return the "API" for this script...
return methods;
};
}
In your test harness then you would simply require the file and when ready, use it like you would any other module. But when called from the command line the code will just execute normally:
// in test.js
'use strict';
var chai = require('chai');
// ...
var appFactory = require('index');
var expect = chai.expect;
describe('initialization', function() {
var app;
beforeEach(function() {
app = appFactory({
auditArgs = chai.spy(function() { });
// other mock method implementations, spies, etc
});
});
it('should call necessary methods on init', function() {
expect(app.auditArgs).to.have.been.called(1);
// ...
});
});

How to spy on a property that is not exported

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

Resources