UNPKG

wdio-spec-reporter

Version:

A WebdriverIO plugin. Report results in 'spec' format.

400 lines (330 loc) 14.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _events = require('events'); var _events2 = _interopRequireDefault(_events); var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk); var _humanizeDuration = require('humanize-duration'); var _humanizeDuration2 = _interopRequireDefault(_humanizeDuration); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var DURATION_OPTIONS = { units: ['m', 's'], round: true, spacer: '' /** * Initialize a new `spec` test reporter. * * @param {Runner} runner * @api public */ }; var SpecReporter = function (_events$EventEmitter) { _inherits(SpecReporter, _events$EventEmitter); function SpecReporter(baseReporter, config) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; _classCallCheck(this, SpecReporter); var _this = _possibleConstructorReturn(this, (SpecReporter.__proto__ || Object.getPrototypeOf(SpecReporter)).call(this)); _this.chalk = _chalk2.default; _this.baseReporter = baseReporter; _this.config = config; _this.options = options; _this.shortEnglishHumanizer = _humanizeDuration2.default.humanizer({ language: 'shortEn', languages: { shortEn: { h: function h() { return 'h'; }, m: function m() { return 'm'; }, s: function s() { return 's'; }, ms: function ms() { return 'ms'; } } } }); _this.errorCount = 0; _this.indents = {}; _this.suiteIndents = {}; _this.specs = {}; _this.results = {}; _this.on('runner:start', function (runner) { this.suiteIndents[runner.cid] = {}; this.indents[runner.cid] = 0; this.specs[runner.cid] = runner.specs; this.results[runner.cid] = { passing: 0, pending: 0, failing: 0 }; }); _this.on('suite:start', function (suite) { this.suiteIndents[suite.cid][suite.uid] = ++this.indents[suite.cid]; }); _this.on('test:pending', function (test) { this.results[test.cid].pending++; }); _this.on('test:pass', function (test) { this.results[test.cid].passing++; }); _this.on('test:fail', function (test) { this.results[test.cid].failing++; }); _this.on('suite:end', function (suite) { this.indents[suite.cid]--; }); _this.on('runner:end', function (runner) { this.printSuiteResult(runner); }); _this.on('end', function () { this.printSuitesSummary(); }); return _this; } _createClass(SpecReporter, [{ key: 'indent', value: function indent(cid, uid) { var indents = this.suiteIndents[cid][uid]; return indents === 0 ? '' : Array(indents).join(' '); } }, { key: 'getSymbol', value: function getSymbol(state) { var symbols = this.baseReporter.symbols; var symbol = '?'; // in case of an unknown state switch (state) { case 'pass': symbol = symbols.ok; break; case 'pending': symbol = '!!'; break; case 'fail': this.errorCount++; symbol = this.errorCount + ')'; break; } return symbol; } }, { key: 'getColor', value: function getColor(state) { var color = null; // in case of an unknown state switch (state) { case 'pass': case 'passing': color = 'green'; break; case 'pending': color = 'cyan'; break; case 'fail': case 'failing': color = 'red'; break; } return color; } }, { key: 'getBrowserCombo', value: function getBrowserCombo(caps) { var verbose = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var device = caps.deviceName; var browser = caps.browserName || caps.browser; var version = caps.version || caps.platformVersion || caps.browser_version; var platform = caps.os ? caps.os + ' ' + caps.os_version : caps.platform || caps.platformName; /** * mobile capabilities */ if (device) { var program = (caps.app || '').replace('sauce-storage:', '') || caps.browserName; var executing = program ? `executing ${program}` : ''; if (!verbose) { return `${device} ${platform} ${version}`; } return `${device} on ${platform} ${version} ${executing}`.trim(); } if (!verbose) { return (browser + ' ' + (version || '') + ' ' + (platform || '')).trim(); } return browser + (version ? ` (v${version})` : '') + (platform ? ` on ${platform}` : ''); } }, { key: 'getResultList', value: function getResultList(cid, suites) { var preface = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; var output = ''; for (var specUid in suites) { // Remove "before all" tests from the displayed results if (specUid.indexOf('"before all"') === 0) { continue; } var spec = suites[specUid]; var indent = this.indent(cid, specUid); var specTitle = suites[specUid].title; if (specUid.indexOf('"before all"') !== 0) { output += `${preface} ${indent}${specTitle}\n`; } for (var testUid in spec.tests) { var test = spec.tests[testUid]; var testTitle = spec.tests[testUid].title; if (test.state === '') { continue; } output += preface; output += ' ' + indent; output += this.chalk[this.getColor(test.state)](this.getSymbol(test.state)); output += ' ' + testTitle + '\n'; } output += preface.trim() + '\n'; } return output; } }, { key: 'getSummary', value: function getSummary(states, duration) { var preface = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; var output = ''; var displayedDuration = false; for (var state in states) { var testCount = states[state]; var testDuration = ''; /** * don't display 0 passing/pending of failing test label */ if (testCount === 0) { continue; } /** * set duration */ if (!displayedDuration) { testDuration = ' (' + this.shortEnglishHumanizer(duration, DURATION_OPTIONS) + ')'; } output += preface + ' '; output += this.chalk[this.getColor(state)](testCount); output += ' ' + this.chalk[this.getColor(state)](state); output += testDuration; output += '\n'; displayedDuration = true; } return output; } }, { key: 'getFailureList', value: function getFailureList(failures, preface) { var _this2 = this; var output = ''; failures.forEach(function (test, i) { var title = typeof test.parent !== 'undefined' ? test.parent + ' ' + test.title : test.title; output += `${preface.trim()}\n`; output += `${preface} ${i + 1}) ${title}:\n`; output += `${preface} ${_this2.chalk.red(test.err.message)}\n`; if (test.err.stack) { var stack = test.err.stack.split(/\n/g).map(function (l) { return `${preface} ${_this2.chalk.gray(l)}`; }).join('\n'); output += `${stack}\n`; } else { output += `${preface} ${_this2.chalk.gray('no stack available')}\n`; } }); return output; } }, { key: 'getJobLink', value: function getJobLink(results, preface) { if (!results.config.host) { return ''; } var output = ''; if (results.config.host.indexOf('saucelabs.com') > -1) { output += `${preface.trim()}\n`; output += `${preface} Check out job at https://saucelabs.com/tests/${results.sessionID}\n`; return output; } return output; } }, { key: 'getSuiteResult', value: function getSuiteResult(runner) { var cid = runner.cid; var stats = this.baseReporter.stats; var results = stats.runners[cid]; var preface = `[${this.getBrowserCombo(results.capabilities, false)} #${cid}]`; var specHash = stats.getSpecHash(runner); var spec = results.specs[specHash]; var combo = this.getBrowserCombo(results.capabilities); var failures = stats.getFailures().filter(function (f) { return f.cid === cid || Object.keys(f.runner).indexOf(cid) > -1; }); /** * don't print anything if no specs where executed */ if (Object.keys(spec.suites).length === 0) { return ''; } this.errorCount = 0; var output = ''; output += '------------------------------------------------------------------\n'; /** * won't be available when running multiremote tests */ if (results.sessionID) { output += `${preface} Session ID: ${results.sessionID}\n`; } output += `${preface} Spec: ${this.specs[cid]}\n`; /** * won't be available when running multiremote tests */ if (combo) { output += `${preface} Running: ${combo}\n`; } output += `${preface}\n`; output += this.getResultList(cid, spec.suites, preface); output += `${preface}\n`; output += this.getSummary(this.results[cid], spec._duration, preface); output += this.getFailureList(failures, preface); output += this.getJobLink(results, preface); output += `${preface}\n`; return output; } }, { key: 'printSuiteResult', value: function printSuiteResult(runner) { console.log(this.getSuiteResult(runner)); } }, { key: 'getSuitesSummary', value: function getSuitesSummary(specCount) { var output = '\n\n==================================================================\n'; output += 'Number of specs: ' + specCount; return output; } }, { key: 'printSuitesSummary', value: function printSuitesSummary() { var specCount = Object.keys(this.baseReporter.stats.runners).length; /** * no need to print summary if only one runner was executed */ if (specCount === 1) { return; } var epilogue = this.baseReporter.epilogue; console.log(this.getSuitesSummary(specCount)); epilogue.call(this.baseReporter); } }]); return SpecReporter; }(_events2.default.EventEmitter); exports.default = SpecReporter; module.exports = exports['default'];