jasmine2-protractor-utils
Version:
Utilities for Protractor with jasmine2 [HTML Reports, Screenshot, Browser Console log and more]
364 lines (299 loc) • 13.8 kB
JavaScript
var q = require('q');
var fs = require('fs');
var fse = require('fs-extra');
var mkdirp = require('mkdirp');
var jasmine2Reporter = require('./reporter/jasmine2_reporter.js');
/**
* This plugin does few things:
* 1. Takes a screenshot for each jasmine expect/matcher failure
* 2. Takes a screenshot for each test/spec failure
* 3. Genrates a HTML report
* 4. Marks the test as failure if browser console log has error - Chrome only //TODO
*
* exports.config = {
* plugins: [{
* package: 'jasmine2-protractor-utils',
* screenshotOnExpectFailure: {Boolean} (Default - false),
* screenshotOnSpecFailure: {Boolean} (Default - false),
* screenshotPath: {String} (Default - 'reports/screenshots')
* clearFoldersBeforeTest: {Boolean} (Default - false),
* htmlReportDir: {String} (Default - './reports/htmlReports')
* failTestOnErrorLog: {
* failTestOnErrorLogLevel: {Number}, (Default - 900)
* excludeKeywords: {A JSON Array}
* }
* }]
* };
* @author Abhishek Swain
* @blog www.qaautomationsimplified.com
* @created December 01 2015
*/
var protractorUtil = function () {
};
/**
* Takes a screenshot for each expect/matcher failure
*
* @param {Object} context The plugin context object
* @return {!webdriver.promise.Promise.<R>} A promise
*/
protractorUtil.takeScreenshotOnExpectFail = function (context) {
if (context.config.screenshotOnExpectFailure) {
return global.browser.getProcessedConfig().then(function (config) {
if (config.capabilities.name) {
var configName = config.capabilities.name + "-";
}
//Takes screen shot for expect failures
var originalAddExpectationResult = jasmine.Spec.prototype.addExpectationResult;
jasmine.Spec.prototype.addExpectationResult = function () {
var self = this;
if (!arguments[0]) {
// take screenshot
global.browser.takeScreenshot().then(function (png) {
var fileName = (configName ? configName : "") + (config.capabilities.browserName + '-' + self.result.fullName + '-' + 'expect failure-' + protractorUtil.index++).replace(/[\/\\]/g, ' ');
if (fileName.length > 245) {
fileName = ((configName ? configName : "") + (config.capabilities.browserName + '-' + self.result.fullName).replace(/[\/\\]/g, ' ')).substring(0, 230) + '-' + 'expect failure-' + protractorUtil.index++;
}
if (context.config.screenshotPath) {
if (((context.config.screenshotPath.charAt(context.config.screenshotPath.length - 1)) != '/') || ((context.config.screenshotPath.charAt(context.config.screenshotPath.length - 1)) != '\\')) {
var screenshotPathUserSupplied = context.config.screenshotPath + '/';
}
}
var stream = fs.createWriteStream((screenshotPathUserSupplied ? screenshotPathUserSupplied.replace('./', '') : 'reports/screenshots/') + fileName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
}, function (err) {
console.log('Error while taking screenshot - ' + err.message);
});
}
return originalAddExpectationResult.apply(this, arguments);
};
});
}
};
/**
* Takes a screenshot for each jasmine spec (it) failure
*
* @param {Object} context The plugin context object
* @return {!webdriver.promise.Promise.<R>} A promise
*/
protractorUtil.takeScreenshotOnSpecFail = function (context) {
if (context.config.screenshotOnSpecFailure) {
return global.browser.getProcessedConfig().then(function (config) {
if (config.capabilities.name) {
var configName = config.capabilities.name + "-";
}
jasmine.getEnv().addReporter((function () {
return{
specDone: function (result) {
if (result.failedExpectations.length > 0) {
// take screenshot
browser.takeScreenshot().then(function (png) {
var fileName = (configName ? configName : "") + (config.capabilities.browserName + '-' + result.fullName).replace(/[\/\\]/g, ' ');
if (fileName.length > 245) {
fileName = ((configName ? configName : "") + (config.capabilities.browserName + '-' + result.fullName).replace(/[\/\\]/g, ' ')).substring(0, 230);
}
if (context.config.screenshotPath) {
if (((context.config.screenshotPath.charAt(context.config.screenshotPath.length - 1)) != '/') || ((context.config.screenshotPath.charAt(context.config.screenshotPath.length - 1)) != '\\')) {
var screenshotPathUserSupplied = context.config.screenshotPath + '/';
}
}
var stream = fs.createWriteStream((screenshotPathUserSupplied ? screenshotPathUserSupplied.replace('./', '') : 'reports/screenshots/') + fileName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
}, function (err) {
console.log('Error while taking screenshot - ' + err.message);
});
}
}
};
})());
});
}
};
/**
* Generates HTML report for tests
*
* @param {Object} context The plugin context object
* @return {!webdriver.promise.Promise.<R>} A promise
*/
protractorUtil.generateHTMLReport = function (context) {
return global.browser.getProcessedConfig().then(function (config) {
if (context.config.htmlReportDir) {
return global.browser.getProcessedConfig().then(function (config) {
var screenshotLocation = context.config.screenshotPath ? context.config.screenshotPath : '.reports/screenshots';
jasmine.getEnv().addReporter(new jasmine2Reporter(context.config.htmlReportDir, screenshotLocation, config));
});
}
else {
return global.browser.getProcessedConfig().then(function (config) {
var screenshotLocation = context.config.screenshotPath ? context.config.screenshotPath : '.reports/screenshots';
jasmine.getEnv().addReporter(new jasmine2Reporter('./reports/htmlReports', screenshotLocation, config));
});
}
});
};
/**
* Fails the test/spec if browser has console logs
*
* @param {Object} context The plugin context object
* @return {!webdriver.promise.Promise.<R>} A promise
*/
protractorUtil.failTestOnErrorLog = function (context) {
if (context.config.failTestOnErrorLog) {
return global.browser.getProcessedConfig().then(function (config) {
beforeEach(function () {
/*
* A Jasmine custom matcher
*/
var matchers = {
toEqualBecause: function () {
return {
compare: function (actual, expected, custMsg) {
var result = {
pass: jasmine.pp(actual) === jasmine.pp(expected),
message: 'Expected ' + jasmine.pp(actual) + ' to equal ' + jasmine.pp(expected) + ' Because: ' + custMsg
};
return result;
}
};
} };
global.jasmine.addMatchers(matchers);
});
afterEach(function () {
/*
* Verifies that console has no error logs, if error log is there test is marked as failure
*/
global.browser.manage().logs().get('browser').then(function (browserLogs) {
// browserLogs is an array of objects with level and message fields
if (browserLogs) {
browserLogs.forEach(function (log) {
var logLevel = context.config.failTestOnErrorLog.failTestOnErrorLogLevel ? context.config.failTestOnErrorLog.failTestOnErrorLogLevel : 900;
var flag = false;
if (log.level.value > logLevel) { // it's an error log
if (context.config.failTestOnErrorLog.excludeKeywords) {
context.config.failTestOnErrorLog.excludeKeywords.forEach(function (keyword) {
if (log.message.search(keyword) > -1) {
flag = true;
}
});
}
expect(log.level.value > logLevel && flag).toEqualBecause(true, 'Error logs present in console:' + require('util').inspect(log));
}
});
}
});
});
});
}
};
/**
* Appends this index number to screenshot name , in order to get a screenshot for each expect failure
* @type {number}
*/
protractorUtil.index = 0;
/**
* Creates the screenshot storage folder
* Calls relevant methods to achieve the desired tasks
*/
protractorUtil.prototype.setup = function () {
var self = this;
if (!this.config.screenshotPath) {
//creates reports folder if does not exist
// var reportsDir = './reports';
// if (!fs.existsSync(reportsDir)) {
// fs.mkdirSync(reportsDir);
// }
if (this.config.clearFoldersBeforeTest) {
try {
fse.removeSync('./reports/screenshots');
} catch (err) {
console.error(err);
}
}
if (!this.config.disableScreenshot) {
//creates screenshots folder if does not exist
var screenshotDir = './reports/screenshots';
mkdirp.sync(screenshotDir, function (err) {
if (err) console.error(err);
else console.log(htmlReportsDir + ' folder created!');
});
}
}
else {
if (this.config.clearFoldersBeforeTest) {
try {
fse.removeSync(this.config.screenshotPath);
} catch (err) {
console.error(err);
}
}
mkdirp.sync(this.config.screenshotPath, function (err) {
if (err) console.error(err);
else console.log(self.config.screenshotPath + ' folder created!');
});
}
if (!this.config.htmlReportDir) {
//creates htmlReports folder if does not exist
var htmlReportsDir = './reports/htmlReports';
if (this.config.clearFoldersBeforeTest) {
try {
fse.removeSync(htmlReportsDir);
} catch (err) {
console.error(err);
}
}
if (!this.config.disableHTMLReport) {
mkdirp.sync(htmlReportsDir, function (err) {
if (err) console.error(err);
else console.log(htmlReportsDir + ' folder created!');
});
}
}
else {
if (this.config.clearFoldersBeforeTest) {
try {
fse.removeSync(this.config.htmlReportDir);
} catch (err) {
console.error(err);
}
}
mkdirp.sync(this.config.htmlReportDir, function (err) {
if (err) console.error(err);
else console.log(self.config.htmlReportDir + ' folder created!');
});
}
if (!this.config.disableScreenshot) {
protractorUtil.takeScreenshotOnExpectFail(this);
protractorUtil.takeScreenshotOnSpecFail(this);
}
protractorUtil.failTestOnErrorLog(this);
if (!this.config.disableHTMLReport) {
protractorUtil.generateHTMLReport(this);
}
};
/**
* Increases the index by one after each spec has run
*/
protractorUtil.prototype.postTest = function () {
protractorUtil.index = 0;
};
protractorUtil.prototype.postResults = function () {
var self = this;
return global.browser.getProcessedConfig().then(function (config) {
var htmlDir = self.config.htmlReportDir ? self.config.htmlReportDir : './reports/htmlReports';
var files = fs.readdirSync(htmlDir);
var finalSuites = [];
files.forEach(function (file, index) {
if ((file.search('.json') > -1) && (file.toString() !== 'data.json')) {
var contents = fs.readFileSync(htmlDir + '/' + file).toString();
finalSuites = finalSuites.concat(JSON.parse(contents.replace('data = ', '')).suites);
}
});
var resultToWrite = 'data = ' + '{ suites:' + JSON.stringify(finalSuites) + '}';
if (finalSuites.length > 0) {
fs.writeFileSync(htmlDir + '/data.json', resultToWrite, 'utf-8');
}
});
};
var protractorUtill = new protractorUtil();
module.exports = protractorUtill;