webdriverio-workflo
Version:
This is a customized version of webdriverio for use with workflo framework.
839 lines (677 loc) • 27.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Cursor = exports.SYMBOLS = exports.SYMBOLS_WIN = exports.COLORS = undefined;
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _tty = require('tty');
var _tty2 = _interopRequireDefault(_tty);
var _events = require('events');
var _events2 = _interopRequireDefault(_events);
var _supportsColor = require('supports-color');
var _supportsColor2 = _interopRequireDefault(_supportsColor);
var _sanitize = require('../helpers/sanitize');
var _sanitize2 = _interopRequireDefault(_sanitize);
var _ReporterStats = require('./ReporterStats');
var _fs = require('fs');
var fs = _interopRequireWildcard(_fs);
var _path = require('path');
var path = _interopRequireWildcard(_path);
var _deepmerge = require('deepmerge');
var _deepmerge2 = _interopRequireDefault(_deepmerge);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var ISATTY = _tty2.default.isatty(1) && _tty2.default.isatty(2);
var COLORS = exports.COLORS = {
'pass': 90,
'fail': 31,
'failed': 31,
'bright pass': 92,
'bright fail': 91,
'bright yellow': 93,
'unvalidated': 35,
'broken': 93,
'pending': 36,
'suite': 0,
'error title': 0,
'browser': 0,
'error message': 31,
'error stack': 90,
'checkmark': 32,
'fast': 90,
'medium': 33,
'slow': 31,
'green': 32,
'passed': 32,
'light': 90,
'unknown': 90,
'diff gutter': 90,
'diff added': 32,
'diff removed': 31,
'step arg': 90,
'log testcase': 34
};
var SYMBOLS_WIN = exports.SYMBOLS_WIN = {
ok: '\u221A',
err: '\u00D7',
dot: '.',
error: 'F'
};
var SYMBOLS = exports.SYMBOLS = {
ok: '✓',
err: '✖',
dot: '․',
error: 'F'
};
var BaseReporter = function (_events$EventEmitter) {
(0, _inherits3.default)(BaseReporter, _events$EventEmitter);
function BaseReporter(config) {
(0, _classCallCheck3.default)(this, BaseReporter);
var _this = (0, _possibleConstructorReturn3.default)(this, (BaseReporter.__proto__ || (0, _getPrototypeOf2.default)(BaseReporter)).call(this));
_this.reporters = [];
_this.printEpilogue = true;
_this.cursor = new Cursor();
_this.stats = new _ReporterStats.ReporterStats();
_this.config = config;
_this.startedSpecs = false;
_this.currentPrintTitle = undefined;
_this.currentTestId = undefined;
_this.currentSpecId = undefined;
_this.currentCriteriaId = undefined;
_this.testcaseResultCounts = {
passing: {
count: 0,
percentage: 0
},
skipped: {
count: 0,
percentage: 0
},
unvalidated: {
count: 0,
percentage: 0
},
failing: {
count: 0,
percentage: 0
},
broken: {
count: 0,
percentage: 0
}
};
_this.specResultCounts = {
passing: {
count: 0,
percentage: 0
},
skipped: {
count: 0,
percentage: 0
},
unvalidated: {
count: 0,
percentage: 0
},
failing: {
count: 0,
percentage: 0
},
broken: {
count: 0,
percentage: 0
}
};
_this.testcaseResults = {};
_this.specResults = {};
_this.completeOuput = [];
_this.wroteCompleteOuput = false;
_this.log = function () {
var _console;
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
this.completeOuput.push({
type: 'log',
arguments: args
});
(_console = console).log.apply(_console, args);
};
_this.warn = function () {
var _console2;
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
this.completeOuput.push({
type: 'log',
arguments: args
});
(_console2 = console).warn.apply(_console2, args);
};
_this.error = function () {
var _console3;
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
this.completeOuput.push({
type: 'log',
arguments: args
});
(_console3 = console).error.apply(_console3, args);
};
_this.writeCompleteOutput = function () {
if (!this.wroteCompleteOuput) {
fs.writeFileSync(this.config.consoleReportPath, (0, _stringify2.default)(this.completeOuput), 'utf8');
this.wroteCompleteOuput = true;
}
};
_this.on('startSpecs', function (runner) {
if (!_this.startedSpecs) {
_this.startedSpecs = true;
_this.testcaseDuration = _this.stats.getTestcaseDuration();
_this.stats.reset(true);
}
});
_this.on('test:setCurrentId', function (test) {
if (_this.startedSpecs) {
var parts = test.id.split('|');
var spec = parts[0];
var criteria = parts[1];
_this.currentSpecId = spec;
_this.currentCriteriaId = criteria;
_this.currentPrintTitle = `${spec} ${test.descriptions.spec} [${criteria} - ${test.descriptions.criteria}]`;
} else {
_this.currentPrintTitle = test.id;
_this.currentTestId = test.id;
}
});
_this.on('start', function () {});
_this.on('runner:start', function (runner) {
_this.stats.runnerStart(runner);
_this.stats.specStart(runner);
});
_this.on('runner:init', function (runner) {
_this.stats.setSessionId(runner);
});
_this.on('runner:beforecommand', function (command) {
_this.stats.output('beforecommand', command);
});
_this.on('runner:command', function (command) {
_this.stats.output('command', command);
});
_this.on('runner:aftercommand', function (command) {
_this.stats.output('aftercommand', command);
});
_this.on('runner:result', function (result) {
_this.stats.output('result', result);
});
_this.on('runner:screenshot', function (screenshot) {
_this.stats.output('screenshot', screenshot);
});
_this.on('runner:log', function (log) {
_this.stats.output('log', log);
});
_this.on('suite:start', function (suite) {
_this.stats.suiteStart(suite);
});
_this.on('hook:start', function (hook) {
_this.stats.hookStart(hook);
});
_this.on('hook:end', function (hook) {
_this.stats.hookEnd(hook);
});
_this.on('test:start', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testStart(test);
});
_this.on('test:pass', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testPass(test);
_this.setResults(test, 'passed');
});
_this.on('test:fail', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testFail(test);
_this.setResults(test, 'failed');
});
_this.on('test:broken', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testBroken(test);
_this.setResults(test, 'broken');
});
_this.on('test:pending', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testPending(test);
_this.setResults(test, 'pending');
});
_this.on('test:unvalidated', function (test) {
test.id = _this.currentTestId;
test.printTitle = _this.currentPrintTitle;
_this.stats.testunvalidated(test);
_this.setResults(test, 'unvalidated');
});
_this.on('test:end', function (test) {
_this.stats.testEnd(test);
});
_this.on('suite:end', function (runner) {
_this.stats.suiteEnd(runner);
});
_this.on('error', function (runner) {
_this.printEpilogue = false;
var fmt = _this.color('error message', 'ERROR: %s');
_this.log(fmt, runner.error.message);
fmt = _this.color('bright yellow', _sanitize2.default.caps(runner.capabilities));
_this.log(fmt);
if (runner.error.stack) {
fmt = _this.color('error stack', runner.error.stack.replace(`Error: ${runner.error.message}\n`, ''));
} else {
fmt = _this.color('error stack', ' no stack available');
}
_this.log(fmt);
});
_this.on('runner:end', function (runner) {
_this.stats.runnerEnd(runner);
});
_this.on('end', function (args) {
_this.stats.complete();
_this.printEpilogue = _this.printEpilogue && !args.sigint;
// don't write execution results if execution was interrupted
if (!args.sigint) {
_this.writeResults();
}
});
return _this;
}
(0, _createClass3.default)(BaseReporter, [{
key: 'setResults',
value: function setResults(data, status) {
if (this.startedSpecs) {
if (!(this.currentSpecId in this.specResults)) {
this.specResults[this.currentSpecId] = {};
}
// add datetime field for manual results
this.specResults[this.currentSpecId][this.currentCriteriaId] = {
status: status
};
if (data.arguments && data.arguments.date) {
this.specResults[this.currentSpecId][this.currentCriteriaId].dateTime = `${data.arguments.date.value}_00-00-00`;
this.specResults[this.currentSpecId][this.currentCriteriaId].manual = true;
} else {
this.specResults[this.currentSpecId][this.currentCriteriaId].dateTime = this.config.dateTime;
}
this.specResults[this.currentSpecId][this.currentCriteriaId].resultsFolder = this.config.dateTime;
} else {
this.testcaseResults[this.currentTestId] = {
status: status,
dateTime: this.config.dateTime,
resultsFolder: this.config.dateTime
};
}
}
}, {
key: 'writeResults',
value: function writeResults() {
var latestRun = fs.readFileSync(this.config.latestRunPath, 'utf8');
var currentResultPath = path.join(this.config.resultsPath, latestRun);
var resultsFilePath = path.join(currentResultPath, 'results.json');
var results = {
testcases: this.testcaseResults,
specs: this.specResults,
browser: this.config.browserName
};
if (!fs.existsSync(currentResultPath)) {
fs.mkdirSync(currentResultPath);
}
fs.writeFileSync(resultsFilePath, (0, _stringify2.default)(results), 'utf8');
var mergedResults = {};
if (fs.existsSync(this.config.mergedResultsPath)) {
mergedResults = JSON.parse(fs.readFileSync(this.config.mergedResultsPath, 'utf8'));
fs.unlinkSync(this.config.mergedResultsPath);
}
mergedResults = (0, _deepmerge2.default)(mergedResults, results);
fs.writeFileSync(this.config.mergedResultsPath, (0, _stringify2.default)(mergedResults), 'utf8');
}
}, {
key: 'trim',
value: function trim(str) {
return str.replace(/^\s+|\s+$/g, '');
}
/**
* Color `str` with the given `type`,
* allowing colors to be disabled,
* as well as user-defined color
* schemes.
*
* @param {String} type
* @param {String} str
* @return {String}
* @api private
*/
}, {
key: 'color',
value: function color(type, str) {
if (!_supportsColor2.default.supportsColor().hasBasic) return String(str);
return `\u001b[${COLORS[type]}m${str}\u001b[0m`;
}
}, {
key: 'limit',
value: function limit(val) {
return _sanitize2.default.limit(val);
}
}, {
key: 'printTestcaseSuitesSummary',
value: function printTestcaseSuitesSummary() {
this.log('Number of Testcase Files: ' + (0, _keys2.default)(this.config.executionFilters.testcaseFiles).length);
this.log('Number of Suites: ' + (0, _keys2.default)(this.config.executionFilters.suites).length);
this.log('Number of Testcases: ' + (0, _keys2.default)(this.config.executionFilters.testcases).length);
this.log();
var fmt = this.color('error title', 'Testcases Duration: ') + this.color('error title', '%ss');
this.log(fmt, (Math.round(this.testcaseDuration / 100) / 10).toFixed(2));
this.log('==================================================================');
}
}, {
key: 'printSpecSuitesSummary',
value: function printSpecSuitesSummary() {
this.log('Number of Spec Files: ' + (0, _keys2.default)(this.config.executionFilters.specFiles).length);
this.log('Number of Features: ' + (0, _keys2.default)(this.config.executionFilters.features).length);
this.log('Number of Specs: ' + (0, _keys2.default)(this.config.executionFilters.specs).length);
this.log();
var fmt = this.color('error title', 'Specs Duration: ') + this.color('error title', '%ss');
this.log(fmt, (Math.round(this.stats.getSpecsDuration() / 100) / 10).toFixed(2));
this.log('==================================================================');
}
}, {
key: 'results',
value: function results(_results, duration) {
var fmt = void 0;
fmt = this.color('green', '%d passing') + this.color('light', ` (${_results.passing.percentage}%)`);
this.log(fmt, _results.passing.count || 0);
// pending
if (_results.skipped.count > 0) {
fmt = this.color('pending', '%d skipped') + this.color('light', ` (${_results.skipped.percentage}%)`);
this.log(fmt, _results.skipped.count);
}
// unvalidateds
if (_results.unvalidated.count > 0) {
fmt = this.color('unvalidated', '%d unvalidated') + this.color('light', ` (${_results.unvalidated.percentage}%)`);
this.log(fmt, _results.unvalidated.count);
}
// failures
if (_results.failing.count > 0) {
fmt = this.color('fail', '%d failing') + this.color('light', ` (${_results.failing.percentage}%)`);
this.log(fmt, _results.failing.count);
}
if (_results.broken.count > 0) {
fmt = this.color('broken', '%d broken') + this.color('light', ` (${_results.broken.percentage}%)`);
this.log(fmt, _results.broken.count);
}
this.log('==================================================================');
}
}, {
key: 'storeResults',
value: function storeResults(results, counts) {
var total = 0 + counts.passes + counts.pending + counts.unvalidateds + counts.failures + counts.brokens;
if (total > 0) {
results.passing.count = counts.passes;
results.passing.percentage = (counts.passes / total * 100).toFixed(1);
results.skipped.count = counts.pending;
results.skipped.percentage = (counts.pending / total * 100).toFixed(1);
results.unvalidated.count = counts.unvalidateds;
results.unvalidated.percentage = (counts.unvalidateds / total * 100).toFixed(1);
results.failing.count = counts.failures;
results.failing.percentage = (counts.failures / total * 100).toFixed(1);
results.broken.count = counts.brokens;
results.broken.percentage = (counts.brokens / total * 100).toFixed(1);
} else {
results.passing.percentage = 0;
}
}
}, {
key: 'getTestcaseResults',
value: function getTestcaseResults() {
this.storeResults(this.testcaseResultCounts, this.stats.getTestcaseCounts());
return this.testcaseResultCounts;
}
}, {
key: 'getSpecResults',
value: function getSpecResults() {
this.storeResults(this.specResultCounts, this.stats.getCounts());
return this.specResultCounts;
}
/**
* Output common epilogue used by many of
* the bundled reporters.
*
* @api public
*/
}, {
key: 'epilogue',
value: function epilogue() {
var counts = this.stats.getCounts();
var testcaseCounts = this.stats.getTestcaseCounts();
if (!this.printEpilogue) {
return;
}
this.storeResults(this.testcaseResultCounts, testcaseCounts);
this.storeResults(this.specResultCounts, counts);
if (testcaseCounts.failures || testcaseCounts.brokens || testcaseCounts.unvalidateds) {
this.listTestcaseFailures();
}
if (counts.failures || counts.brokens || counts.unvalidateds) {
this.listSpecFailures();
}
this.log('==================================================================');
this.printTestcaseSuitesSummary();
this.printSpecSuitesSummary();
this.printCoverage();
this.log('Testcase Results:\n');
this.results(this.testcaseResultCounts, this.testcaseDuration);
this.log('Spec Criteria Results:\n');
this.results(this.specResultCounts, this.stats.getSpecsDuration());
this.printEpilogue = false;
}
}, {
key: 'listFailures',
value: function listFailures(failures, specs) {
var _this2 = this;
failures.forEach(function (test, i) {
var sfmt = _this2.color('error title', '%s) %s:\n');
var title = test.printTitle;
_this2.log(sfmt, i + 1, title);
var self = _this2;
if (test.errs && test.errs.length > 0) {
test.errs.forEach(function (err, j) {
var errMessageColor = typeof err.matcherName === 'undefined' && err.stack ? 'bright yellow' : 'error message';
var efmt = self.color(errMessageColor, '%s') + self.color('error stack', '\n%s\n');
self.log(efmt, err.message, err.stack);
});
} else if (test.unvalidated) {
var efmt = _this2.color('unvalidated', '%s\n');
if (test.errs && test.errs.length > 0) {
test.errs.forEach(function (err, j) {
self.log(efmt, err.message);
});
} else {
_this2.log(efmt, test.err.message);
}
} else {
// should not be used any longer7
var errMessageColor = !test.err.matcherName && !specs ? 'bright yellow' : 'error message';
var _efmt = self.color(errMessageColor, '%s') + self.color('error stack', '\n%s\n');
_this2.log(_efmt, _this2.trim(test.err.message), test.err.stack);
}
});
}
/**
* Outut the given failures as a list
*/
}, {
key: 'listSpecFailures',
value: function listSpecFailures() {
this.log('==================================================================\n');
this.log('Spec Failures: ');
this.log();
this.listFailures(this.stats.getFailures(), true);
}
}, {
key: 'listTestcaseFailures',
value: function listTestcaseFailures() {
this.log('==================================================================\n');
this.log('Testcase Failures: ');
this.log();
this.listFailures(this.stats.getTestcaseFailures());
}
}, {
key: 'printCoverage',
value: function printCoverage() {
var printObject = this.config.printObject;
this.log('Criteria Coverage: ');
this.log();
this.log(`${printObject['Automated Criteria'].count} automated ${printObject['Automated Criteria'].percentage}`);
this.log(`${printObject['Manual Criteria'].count} manual ${printObject['Manual Criteria'].percentage}`);
this.log(`${printObject['Uncovered Criteria'].count} unvalidated ${printObject['Uncovered Criteria'].percentage}`);
this.log('==================================================================');
}
}, {
key: 'add',
value: function add(reporter) {
this.reporters.push(reporter);
}
// Although BaseReporter is an eventemitter, handleEvent() is called instead of emit()
// so that every event can be propagated to attached reporters
}, {
key: 'handleEvent',
value: function handleEvent() {
for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
args[_key4] = arguments[_key4];
}
if (this.listeners(args[0]).length) {
this.emit.apply(this, args);
}
if (this.reporters.length === 0) {
return;
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(this.reporters), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var reporter = _step.value;
/**
* skip reporter if
* - he isn't an eventemitter
* - event is not registered
*/
if (typeof reporter.emit !== 'function' || !reporter.listeners(args[0]).length) {
continue;
}
reporter.emit.apply(reporter, args);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
/**
* Default color map.
*/
}, {
key: 'colors',
get: function get() {
return COLORS;
}
/**
* Default symbol map.
*/
}, {
key: 'symbols',
get: function get() {
/**
* With node.js on Windows: use symbols available in terminal default fonts
*/
if (process.platform === 'win32') {
return SYMBOLS_WIN;
}
return SYMBOLS;
}
}]);
return BaseReporter;
}(_events2.default.EventEmitter);
/**
* Expose some basic cursor interactions
* that are common among reporters.
*/
var Cursor = function () {
function Cursor() {
(0, _classCallCheck3.default)(this, Cursor);
}
(0, _createClass3.default)(Cursor, [{
key: 'hide',
value: function hide() {
ISATTY && process.stdout.write('\u001b[?25l');
}
}, {
key: 'show',
value: function show() {
ISATTY && process.stdout.write('\u001b[?25h');
}
}, {
key: 'deleteLine',
value: function deleteLine() {
ISATTY && process.stdout.write('\u001b[2K');
}
}, {
key: 'beginningOfLine',
value: function beginningOfLine() {
ISATTY && process.stdout.write('\u001b[0G');
}
}, {
key: 'CR',
value: function CR() {
if (ISATTY) {
this.deleteLine();
this.beginningOfLine();
} else {
process.stdout.write('\r');
}
}
}, {
key: 'isatty',
get: function get() {
return ISATTY;
}
}]);
return Cursor;
}();
exports.default = BaseReporter;
exports.Cursor = Cursor;