UNPKG

webdriverio-workflo

Version:

This is a customized version of webdriverio for use with workflo framework.

839 lines (677 loc) 27.7 kB
'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;