UNPKG

webdriverio-workflo

Version:

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

708 lines (606 loc) 26.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReporterStats = exports.TestStats = exports.SuiteStats = exports.SpecStats = exports.RunnerStats = exports.RunnableStats = undefined; var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _deepmerge = require('deepmerge'); var _deepmerge2 = _interopRequireDefault(_deepmerge); var _crypto = require('crypto'); var _crypto2 = _interopRequireDefault(_crypto); var _sanitize = require('../helpers/sanitize'); var _sanitize2 = _interopRequireDefault(_sanitize); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var RunnableStats = function () { function RunnableStats(type) { (0, _classCallCheck3.default)(this, RunnableStats); this.type = type; this.start = new Date(); this.testcaseStart = new Date(); this._duration = 0; this._specDuration = 0; this._testcaseDuration = 0; } (0, _createClass3.default)(RunnableStats, [{ key: 'complete', value: function complete() { this.end = new Date(); this._duration = this.end - this.start; } }, { key: 'getTestcaseDuration', value: function getTestcaseDuration() { return new Date() - this.testcaseStart; } }, { key: 'getSpecsDuration', value: function getSpecsDuration() { return new Date() - this.specsStart; } }, { key: 'duration', get: function get() { if (this.end) { return this._duration; } return new Date() - this.start; } }]); return RunnableStats; }(); var RunnerStats = function (_RunnableStats) { (0, _inherits3.default)(RunnerStats, _RunnableStats); function RunnerStats(runner) { (0, _classCallCheck3.default)(this, RunnerStats); var _this = (0, _possibleConstructorReturn3.default)(this, (RunnerStats.__proto__ || (0, _getPrototypeOf2.default)(RunnerStats)).call(this, 'runner')); _this.uid = ReporterStats.getIdentifier(runner); _this.cid = runner.cid; _this.capabilities = runner.capabilities; _this.sanitizedCapabilities = runner.capabilities && _sanitize2.default.caps(runner.capabilities); _this.config = runner.config; _this.specs = {}; return _this; } return RunnerStats; }(RunnableStats); var SpecStats = function (_RunnableStats2) { (0, _inherits3.default)(SpecStats, _RunnableStats2); function SpecStats(runner) { (0, _classCallCheck3.default)(this, SpecStats); var _this2 = (0, _possibleConstructorReturn3.default)(this, (SpecStats.__proto__ || (0, _getPrototypeOf2.default)(SpecStats)).call(this, 'spec')); _this2.uid = ReporterStats.getIdentifier(runner); _this2.files = runner.specs; _this2.specHash = runner.specHash; _this2.suites = {}; _this2.output = []; return _this2; } return SpecStats; }(RunnableStats); var SuiteStats = function (_RunnableStats3) { (0, _inherits3.default)(SuiteStats, _RunnableStats3); function SuiteStats(runner) { (0, _classCallCheck3.default)(this, SuiteStats); var _this3 = (0, _possibleConstructorReturn3.default)(this, (SuiteStats.__proto__ || (0, _getPrototypeOf2.default)(SuiteStats)).call(this, 'suite')); _this3.uid = ReporterStats.getIdentifier(runner); _this3.title = runner.title; _this3.tests = {}; _this3.hooks = {}; return _this3; } return SuiteStats; }(RunnableStats); var TestStats = function (_RunnableStats4) { (0, _inherits3.default)(TestStats, _RunnableStats4); function TestStats(runner) { (0, _classCallCheck3.default)(this, TestStats); var _this4 = (0, _possibleConstructorReturn3.default)(this, (TestStats.__proto__ || (0, _getPrototypeOf2.default)(TestStats)).call(this, 'test')); _this4.uid = ReporterStats.getIdentifier(runner); _this4.title = runner.title; _this4.state = ''; _this4.screenshots = []; _this4.output = []; return _this4; } return TestStats; }(RunnableStats); var HookStats = function (_RunnableStats5) { (0, _inherits3.default)(HookStats, _RunnableStats5); function HookStats(runner) { (0, _classCallCheck3.default)(this, HookStats); var _this5 = (0, _possibleConstructorReturn3.default)(this, (HookStats.__proto__ || (0, _getPrototypeOf2.default)(HookStats)).call(this, 'hook')); _this5.uid = ReporterStats.getIdentifier(runner); _this5.title = runner.title; _this5.parent = runner.parent; _this5.parentUid = runner.parentUid || runner.parent; _this5.currentTest = runner.currentTest; return _this5; } return HookStats; }(RunnableStats); var ReporterStats = function (_RunnableStats6) { (0, _inherits3.default)(ReporterStats, _RunnableStats6); function ReporterStats() { (0, _classCallCheck3.default)(this, ReporterStats); var _this6 = (0, _possibleConstructorReturn3.default)(this, (ReporterStats.__proto__ || (0, _getPrototypeOf2.default)(ReporterStats)).call(this, 'base')); _this6.runners = {}; _this6.reset(); return _this6; } (0, _createClass3.default)(ReporterStats, [{ key: 'reset', value: function reset(specs) { if (specs) { this.testcaseCounts = this.counts; this.testcaseFailures = this.failures; this.specsStart = new Date(); } else { this.testcaseCounts = { suites: 0, tests: 0, hooks: 0, passes: 0, pending: 0, failures: 0, unvalidateds: 0, brokens: 0 }; this.testcaseFailures = []; } this.counts = { suites: 0, tests: 0, hooks: 0, passes: 0, pending: 0, failures: 0, unvalidateds: 0, brokens: 0 }; this.failures = []; } }, { key: 'getTestcaseCounts', value: function getTestcaseCounts() { return this.testcaseCounts; } }, { key: 'getCounts', value: function getCounts() { return this.counts; } }, { key: 'getTestcaseFailures', value: function getTestcaseFailures() { var _this7 = this; return this.testcaseFailures.map(function (test) { test.runningBrowser = ''; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)((0, _keys2.default)(test.runner)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var pid = _step.value; var caps = test.runner[pid]; test.runningBrowser += '\nrunning'; if (caps.browserName) { test.runningBrowser += ` ${caps.browserName}`; } if (caps.version) { test.runningBrowser += ` (v${caps.version})`; } if (caps.platform) { test.runningBrowser += ` on ${caps.platform}`; } var host = _this7.runners[pid].config.host; if (host && host.indexOf('saucelabs') > -1) { test.runningBrowser += '\nCheck out job at https://saucelabs.com/tests/' + _this7.runners[pid].sessionID; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return test; }); } }, { key: 'getFailures', value: function getFailures() { var _this8 = this; return this.failures.map(function (test) { test.runningBrowser = ''; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)((0, _keys2.default)(test.runner)), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var pid = _step2.value; var caps = test.runner[pid]; test.runningBrowser += '\nrunning'; if (caps.browserName) { test.runningBrowser += ` ${caps.browserName}`; } if (caps.version) { test.runningBrowser += ` (v${caps.version})`; } if (caps.platform) { test.runningBrowser += ` on ${caps.platform}`; } var host = _this8.runners[pid].config.host; if (host && host.indexOf('saucelabs') > -1) { test.runningBrowser += '\nCheck out job at https://saucelabs.com/tests/' + _this8.runners[pid].sessionID; } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return test; }); } }, { key: 'runnerStart', value: function runnerStart(runner) { if (!this.runners[runner.cid]) { this.runners[runner.cid] = new RunnerStats(runner); } } }, { key: 'getRunnerStats', value: function getRunnerStats(runner) { if (!this.runners[runner.cid]) throw Error(`Unrecognised runner [${runner.cid}]`); return this.runners[runner.cid]; } }, { key: 'getSpecHash', value: function getSpecHash(runner) { if (!runner.specHash) { if (!runner.specs) throw Error('Cannot generate spec hash for runner with no \'specs\' key'); runner.specHash = _crypto2.default.createHash('md5').update(runner.specs.join('')).digest('hex'); } return runner.specHash; } }, { key: 'specStart', value: function specStart(runner) { var specHash = this.getSpecHash(runner); this.getRunnerStats(runner).specs[specHash] = new SpecStats(runner); } }, { key: 'getSpecStats', value: function getSpecStats(runner) { var runnerStats = this.getRunnerStats(runner); var specHash = this.getSpecHash(runner); if (!runnerStats.specs[specHash]) throw Error(`Unrecognised spec [${specHash}] for runner [${runner.cid}]`); return runnerStats.specs[specHash]; } }, { key: 'setSessionId', value: function setSessionId(runner) { this.getRunnerStats(runner).sessionID = runner.sessionID; } }, { key: 'suiteStart', value: function suiteStart(runner) { this.getSpecStats(runner).suites[ReporterStats.getIdentifier(runner)] = new SuiteStats(runner); this.counts.suites++; } }, { key: 'getSuiteStats', value: function getSuiteStats(runner, suiteTitle) { var specStats = this.getSpecStats(runner); /** * if error occurs in root level hooks we haven't created any suites yet, so * create one here if so */ if (!specStats.suites[suiteTitle]) { this.suiteStart((0, _deepmerge2.default)(runner, { title: runner.parent })); specStats = this.getSpecStats(runner); } return specStats.suites[suiteTitle]; } }, { key: 'hookStart', value: function hookStart(runner) { var suiteStat = this.getSuiteStats(runner, runner.parentUid || runner.parent); if (!suiteStat) { return; } suiteStat.hooks[ReporterStats.getIdentifier(runner)] = new HookStats(runner); } }, { key: 'hookEnd', value: function hookEnd(runner) { var hookStats = this.getHookStats(runner); if (!hookStats) { return; } hookStats.complete(); this.counts.hooks++; } }, { key: 'testStart', value: function testStart(runner) { this.getSuiteStats(runner, runner.parentUid || runner.parent).tests[ReporterStats.getIdentifier(runner)] = new TestStats(runner); } }, { key: 'getHookStats', value: function getHookStats(runner) { var suiteStats = this.getSuiteStats(runner, runner.parentUid || runner.parent); if (!suiteStats) { return; } // Errors encountered inside hooks (e.g. beforeEach) can be identified by looking // at the currentTest param (currently only applicable to the Mocha adapter). var uid = runner.currentTest || ReporterStats.getIdentifier(runner); if (!suiteStats.hooks[uid]) { uid = ReporterStats.getIdentifier(runner); } if (!suiteStats.hooks[uid]) throw Error(`Unrecognised hook [${runner.title}] for suite [${runner.parent}]`); return suiteStats.hooks[uid]; } }, { key: 'getTestStats', value: function getTestStats(runner) { var suiteStats = this.getSuiteStats(runner, runner.parentUid || runner.parent); if (!suiteStats) { return; } // Errors encountered inside hooks (e.g. beforeEach) can be identified by looking // at the currentTest param (currently only applicable to the Mocha adapter). var uid = runner.currentTest || ReporterStats.getIdentifier(runner); if (!suiteStats.tests[uid]) { uid = ReporterStats.getIdentifier(runner); } if (!suiteStats.tests[uid]) throw Error(`Unrecognised test [${runner.title}] for suite [${runner.parent}]`); return suiteStats.tests[uid]; } }, { key: 'output', value: function output(type, runner) { runner.time = new Date(); var storedRunner = (0, _deepmerge2.default)({}, runner, { clone: true }); // Remove the screenshot data to reduce RAM usage on the parent process var knownScreenshotCommands = ['saveDocumentScreenshot', 'saveViewportScreenshot', 'saveElementScreenshot']; if (type === 'screenshot') { storedRunner.data = null; } else if (type === 'result' && runner.requestOptions && runner.requestOptions.uri.path.indexOf('screenshot') !== -1) { storedRunner.body = null; } else if (type === 'aftercommand' && knownScreenshotCommands.indexOf(runner.command) !== -1) { storedRunner.result = null; } if (ReporterStats.getIdentifier(runner) && runner.parent) { this.getTestStats(runner).output.push({ type, payload: storedRunner }); } else { // Log commands, results and screenshots executed outside of a test this.getSpecStats(runner).output.push({ type, payload: storedRunner }); } } }, { key: 'testPass', value: function testPass(runner) { this.getTestStats(runner).state = 'pass'; this.counts.passes++; } }, { key: 'testPending', value: function testPending(runner) { // Pending tests don't actually start, so won't yet be registered this.testStart(runner); this.testEnd(runner); this.getTestStats(runner).state = 'pending'; this.counts.pending++; } }, { key: 'testunvalidated', value: function testunvalidated(runner) { var testStats = this.getTestStats(runner); testStats.state = 'unvalidated'; testStats.error = runner.err; this.counts.unvalidateds++; runner.unvalidated = true; this.failures.push(runner); } }, { key: 'testFail', value: function testFail(runner) { var testStats = void 0; /** * replace "Ensure the done() callback is being called in this test." with more meaningful * message */ var message = 'Ensure the done() callback is being called in this test.'; if (runner.err && runner.err.message && runner.err.message.indexOf(message) > -1) { var replacement = `The execution in the test "${runner.parent} ${runner.title}" took ` + 'too long. Try to reduce the run time or increase your timeout for ' + 'test specs (http://webdriver.io/guide/testrunner/timeouts.html).'; runner.err.message = runner.err.message.replace(message, replacement); runner.err.stack = runner.err.stack.replace(message, replacement); } message = 'For async tests and hooks, ensure "done()" is called;'; if (runner.err && runner.err.message && runner.err.message.indexOf(message) > -1) { var _replacement = 'Try to reduce the run time or increase your timeout for ' + 'test specs (http://webdriver.io/guide/testrunner/timeouts.html);'; runner.err.message = runner.err.message.replace(message, _replacement); runner.err.stack = runner.err.stack.replace(message, _replacement); } try { testStats = this.getTestStats(runner) || {}; } catch (e) { // If a test fails during the before() or beforeEach() hook, it will not yet // have been 'started', so start now this.testStart(runner); testStats = this.getTestStats(runner); } testStats.state = 'fail'; testStats.error = runner.err; this.counts.failures++; /** * check if error also happened in other runners */ var duplicateError = false; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = (0, _getIterator3.default)(this.failures), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var failure = _step3.value; if (runner.err.message !== failure.err.message || ReporterStats.getIdentifier(failure) !== ReporterStats.getIdentifier(runner)) { continue; } duplicateError = true; failure.runner[runner.cid] = runner.runner[runner.cid]; } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } if (!duplicateError) { this.failures.push(runner); } } }, { key: 'testBroken', value: function testBroken(runner) { var testStats = void 0; /** * replace "Ensure the done() callback is being called in this test." with more meaningful * message */ var message = 'Ensure the done() callback is being called in this test.'; if (runner.err && runner.err.message && runner.err.message.indexOf(message) > -1) { var replacement = `The execution in the test "${runner.parent} ${runner.title}" took ` + 'too long. Try to reduce the run time or increase your timeout for ' + 'test specs (http://webdriver.io/guide/testrunner/timeouts.html).'; runner.err.message = runner.err.message.replace(message, replacement); runner.err.stack = runner.err.stack.replace(message, replacement); } message = 'For async tests and hooks, ensure "done()" is called;'; if (runner.err && runner.err.message && runner.err.message.indexOf(message) > -1) { var _replacement2 = 'Try to reduce the run time or increase your timeout for ' + 'test specs (http://webdriver.io/guide/testrunner/timeouts.html);'; runner.err.message = runner.err.message.replace(message, _replacement2); runner.err.stack = runner.err.stack.replace(message, _replacement2); } try { testStats = this.getTestStats(runner); } catch (e) { // If a test fails during the before() or beforeEach() hook, it will not yet // have been 'started', so start now this.testStart(runner); testStats = this.getTestStats(runner); } testStats.state = 'broken'; testStats.error = runner.err; this.counts.brokens++; /** * check if error also happened in other runners */ var duplicateError = false; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = (0, _getIterator3.default)(this.failures), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var failure = _step4.value; if (runner.err.message !== failure.err.message || ReporterStats.getIdentifier(failure) !== ReporterStats.getIdentifier(runner)) { continue; } duplicateError = true; failure.runner[runner.cid] = runner.runner[runner.cid]; } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } if (!duplicateError) { this.failures.push(runner); } } }, { key: 'testEnd', value: function testEnd(runner) { this.getTestStats(runner).complete(); this.counts.tests++; if (runner.context) { this.getTestStats(runner).context = runner.context; } } }, { key: 'suiteEnd', value: function suiteEnd(runner) { this.getSuiteStats(runner, ReporterStats.getIdentifier(runner)).complete(); } }, { key: 'runnerEnd', value: function runnerEnd(runner) { this.getSpecStats(runner).complete(); } }], [{ key: 'getIdentifier', value: function getIdentifier(runner) { return runner.uid || runner.title; } }]); return ReporterStats; }(RunnableStats); exports.RunnableStats = RunnableStats; exports.RunnerStats = RunnerStats; exports.SpecStats = SpecStats; exports.SuiteStats = SuiteStats; exports.TestStats = TestStats; exports.ReporterStats = ReporterStats;