UNPKG

protractor-beautiful-reporter

Version:

An npm module and which generates your Protractor test reports in HTML (angular) with screenshots

513 lines (441 loc) 16.2 kB
var app = angular.module('reportingApp', []); //<editor-fold desc="global helpers"> var isValueAnArray = function (val) { return Array.isArray(val); }; var getSpec = function (str) { var describes = str.split('|'); return describes[describes.length - 1]; }; var checkIfShouldDisplaySpecName = function (prevItem, item) { if (!prevItem) { item.displaySpecName = true; } else if (getSpec(item.description) !== getSpec(prevItem.description)) { item.displaySpecName = true; } }; var getParent = function (str) { var arr = str.split('|'); str = ""; for (var i = arr.length - 2; i > 0; i--) { str += arr[i] + " > "; } return str.slice(0, -3); }; var getShortDescription = function (str) { return str.split('|')[0]; }; var countLogMessages = function (item) { if ((!item.logWarnings || !item.logErrors) && item.browserLogs && item.browserLogs.length > 0) { item.logWarnings = 0; item.logErrors = 0; for (var logNumber = 0; logNumber < item.browserLogs.length; logNumber++) { var logEntry = item.browserLogs[logNumber]; if (logEntry.level === 'SEVERE') { item.logErrors++; } if (logEntry.level === 'WARNING') { item.logWarnings++; } } } }; var convertTimestamp = function (timestamp) { var d = new Date(timestamp), yyyy = d.getFullYear(), mm = ('0' + (d.getMonth() + 1)).slice(-2), dd = ('0' + d.getDate()).slice(-2), hh = d.getHours(), h = hh, min = ('0' + d.getMinutes()).slice(-2), ampm = 'AM', time; if (hh > 12) { h = hh - 12; ampm = 'PM'; } else if (hh === 12) { h = 12; ampm = 'PM'; } else if (hh === 0) { h = 12; } // ie: 2013-02-18, 8:35 AM time = yyyy + '-' + mm + '-' + dd + ', ' + h + ':' + min + ' ' + ampm; return time; }; var defaultSortFunction = function sortFunction(a, b) { if (a.sessionId < b.sessionId) { return -1; } else if (a.sessionId > b.sessionId) { return 1; } if (a.timestamp < b.timestamp) { return -1; } else if (a.timestamp > b.timestamp) { return 1; } return 0; }; //</editor-fold> app.controller('ScreenshotReportController', ['$scope', '$http', 'TitleService', function ($scope, $http, titleService) { var that = this; var clientDefaults = {};//'<Client Defaults Replacement>'; $scope.searchSettings = Object.assign({ description: '', allselected: true, passed: true, failed: true, pending: true, withLog: true }, clientDefaults.searchSettings || {}); // enable customisation of search settings on first page hit this.warningTime = 1400; this.dangerTime = 1900; this.totalDurationFormat = clientDefaults.totalDurationFormat; this.showTotalDurationIn = clientDefaults.showTotalDurationIn; var initialColumnSettings = clientDefaults.columnSettings; // enable customisation of visible columns on first page hit if (initialColumnSettings) { if (initialColumnSettings.displayTime !== undefined) { // initial settings have be inverted because the html bindings are inverted (e.g. !ctrl.displayTime) this.displayTime = !initialColumnSettings.displayTime; } if (initialColumnSettings.displayBrowser !== undefined) { this.displayBrowser = !initialColumnSettings.displayBrowser; // same as above } if (initialColumnSettings.displaySessionId !== undefined) { this.displaySessionId = !initialColumnSettings.displaySessionId; // same as above } if (initialColumnSettings.displayOS !== undefined) { this.displayOS = !initialColumnSettings.displayOS; // same as above } if (initialColumnSettings.inlineScreenshots !== undefined) { this.inlineScreenshots = initialColumnSettings.inlineScreenshots; // this setting does not have to be inverted } else { this.inlineScreenshots = false; } if (initialColumnSettings.warningTime) { this.warningTime = initialColumnSettings.warningTime; } if (initialColumnSettings.dangerTime) { this.dangerTime = initialColumnSettings.dangerTime; } } this.chooseAllTypes = function () { var value = true; $scope.searchSettings.allselected = !$scope.searchSettings.allselected; if (!$scope.searchSettings.allselected) { value = false; } $scope.searchSettings.passed = value; $scope.searchSettings.failed = value; $scope.searchSettings.pending = value; $scope.searchSettings.withLog = value; }; this.isValueAnArray = function (val) { return isValueAnArray(val); }; this.getParent = function (str) { return getParent(str); }; this.getSpec = function (str) { return getSpec(str); }; this.getShortDescription = function (str) { return getShortDescription(str); }; this.hasNextScreenshot = function (index) { var old = index; return old !== this.getNextScreenshotIdx(index); }; this.hasPreviousScreenshot = function (index) { var old = index; return old !== this.getPreviousScreenshotIdx(index); }; this.getNextScreenshotIdx = function (index) { var next = index; var hit = false; while (next + 2 < this.results.length) { next++; if (this.results[next].screenShotFile && !this.results[next].pending) { hit = true; break; } } return hit ? next : index; }; this.getPreviousScreenshotIdx = function (index) { var prev = index; var hit = false; while (prev > 0) { prev--; if (this.results[prev].screenShotFile && !this.results[prev].pending) { hit = true; break; } } return hit ? prev : index; }; this.convertTimestamp = convertTimestamp; this.round = function (number, roundVal) { return (parseFloat(number) / 1000).toFixed(roundVal); }; this.passCount = function () { var passCount = 0; for (var i in this.results) { var result = this.results[i]; if (result.passed) { passCount++; } } return passCount; }; this.pendingCount = function () { var pendingCount = 0; for (var i in this.results) { var result = this.results[i]; if (result.pending) { pendingCount++; } } return pendingCount; }; this.failCount = function () { var failCount = 0; for (var i in this.results) { var result = this.results[i]; if (!result.passed && !result.pending) { failCount++; } } return failCount; }; this.totalDuration = function () { var sum = 0; for (var i in this.results) { var result = this.results[i]; if (result.duration) { sum += result.duration; } } return sum; }; this.passPerc = function () { return (this.passCount() / this.totalCount()) * 100; }; this.pendingPerc = function () { return (this.pendingCount() / this.totalCount()) * 100; }; this.failPerc = function () { return (this.failCount() / this.totalCount()) * 100; }; this.totalCount = function () { return this.passCount() + this.failCount() + this.pendingCount(); }; var results = [];//'<Results Replacement>'; this.sortSpecs = function () { this.results = results.sort(defaultSortFunction/*<Sort Function Replacement>*/); }; this.setTitle = function () { var title = $('.report-title').text(); titleService.setTitle(title); }; // is run after all test data has been prepared/loaded this.afterLoadingJobs = function () { this.sortSpecs(); this.setTitle(); }; this.loadResultsViaAjax = function () { $http({ url: './combined.json', method: 'GET' }).then(function (response) { var data = null; if (response && response.data) { if (typeof response.data === 'object') { data = response.data; } else if (response.data[0] === '"') { //detect super escaped file (from circular json) data = CircularJSON.parse(response.data); //the file is escaped in a weird way (with circular json) } else { data = JSON.parse(response.data); } } if (data) { results = data; that.afterLoadingJobs(); } }, function (error) { console.error(error); }); }; if (clientDefaults.useAjax) { this.loadResultsViaAjax(); } else { this.afterLoadingJobs(); } }]); app.filter('bySearchSettings', function () { return function (items, searchSettings) { var filtered = []; if (!items) { return filtered; // to avoid crashing in where results might be empty } var prevItem = null; for (var i = 0; i < items.length; i++) { var item = items[i]; item.displaySpecName = false; var isHit = false; //is set to true if any of the search criteria matched countLogMessages(item); // modifies item contents var hasLog = searchSettings.withLog && item.browserLogs && item.browserLogs.length > 0; if (searchSettings.description === '' || (item.description && item.description.toLowerCase().indexOf(searchSettings.description.toLowerCase()) > -1)) { if (searchSettings.passed && item.passed || hasLog) { isHit = true; } else if (searchSettings.failed && !item.passed && !item.pending || hasLog) { isHit = true; } else if (searchSettings.pending && item.pending || hasLog) { isHit = true; } } if (isHit) { checkIfShouldDisplaySpecName(prevItem, item); filtered.push(item); prevItem = item; } } return filtered; }; }); //formats millseconds to h m s app.filter('timeFormat', function () { return function (tr, fmt) { if(tr == null){ return "NaN"; } switch (fmt) { case 'h': var h = tr / 1000 / 60 / 60; return "".concat(h.toFixed(2)).concat("h"); case 'm': var m = tr / 1000 / 60; return "".concat(m.toFixed(2)).concat("min"); case 's' : var s = tr / 1000; return "".concat(s.toFixed(2)).concat("s"); case 'hm': case 'h:m': var hmMt = tr / 1000 / 60; var hmHr = Math.trunc(hmMt / 60); var hmMr = hmMt - (hmHr * 60); if (fmt === 'h:m') { return "".concat(hmHr).concat(":").concat(hmMr < 10 ? "0" : "").concat(Math.round(hmMr)); } return "".concat(hmHr).concat("h ").concat(hmMr.toFixed(2)).concat("min"); case 'hms': case 'h:m:s': var hmsS = tr / 1000; var hmsHr = Math.trunc(hmsS / 60 / 60); var hmsM = hmsS / 60; var hmsMr = Math.trunc(hmsM - hmsHr * 60); var hmsSo = hmsS - (hmsHr * 60 * 60) - (hmsMr*60); if (fmt === 'h:m:s') { return "".concat(hmsHr).concat(":").concat(hmsMr < 10 ? "0" : "").concat(hmsMr).concat(":").concat(hmsSo < 10 ? "0" : "").concat(Math.round(hmsSo)); } return "".concat(hmsHr).concat("h ").concat(hmsMr).concat("min ").concat(hmsSo.toFixed(2)).concat("s"); case 'ms': var msS = tr / 1000; var msMr = Math.trunc(msS / 60); var msMs = msS - (msMr * 60); return "".concat(msMr).concat("min ").concat(msMs.toFixed(2)).concat("s"); } return tr; }; }); function PbrStackModalController($scope, $rootScope) { var ctrl = this; ctrl.rootScope = $rootScope; ctrl.getParent = getParent; ctrl.getShortDescription = getShortDescription; ctrl.convertTimestamp = convertTimestamp; ctrl.isValueAnArray = isValueAnArray; ctrl.toggleSmartStackTraceHighlight = function () { var inv = !ctrl.rootScope.showSmartStackTraceHighlight; ctrl.rootScope.showSmartStackTraceHighlight = inv; }; ctrl.applySmartHighlight = function (line) { if ($rootScope.showSmartStackTraceHighlight) { if (line.indexOf('node_modules') > -1) { return 'greyout'; } if (line.indexOf(' at ') === -1) { return ''; } return 'highlight'; } return ''; }; } app.component('pbrStackModal', { templateUrl: "pbr-stack-modal.html", bindings: { index: '=', data: '=' }, controller: PbrStackModalController }); function PbrScreenshotModalController($scope, $rootScope) { var ctrl = this; ctrl.rootScope = $rootScope; ctrl.getParent = getParent; ctrl.getShortDescription = getShortDescription; /** * Updates which modal is selected. */ this.updateSelectedModal = function (event, index) { var key = event.key; //try to use non-deprecated key first https://developer.mozilla.org/de/docs/Web/API/KeyboardEvent/keyCode if (key == null) { var keyMap = { 37: 'ArrowLeft', 39: 'ArrowRight' }; key = keyMap[event.keyCode]; //fallback to keycode } if (key === "ArrowLeft" && this.hasPrevious) { this.showHideModal(index, this.previous); } else if (key === "ArrowRight" && this.hasNext) { this.showHideModal(index, this.next); } }; /** * Hides the modal with the #oldIndex and shows the modal with the #newIndex. */ this.showHideModal = function (oldIndex, newIndex) { const modalName = '#imageModal'; $(modalName + oldIndex).modal("hide"); $(modalName + newIndex).modal("show"); }; } app.component('pbrScreenshotModal', { templateUrl: "pbr-screenshot-modal.html", bindings: { index: '=', data: '=', next: '=', previous: '=', hasNext: '=', hasPrevious: '=' }, controller: PbrScreenshotModalController }); app.factory('TitleService', ['$document', function ($document) { return { setTitle: function (title) { $document[0].title = title; } }; }]); app.run( function ($rootScope, $templateCache) { //make sure this option is on by default $rootScope.showSmartStackTraceHighlight = true; //'<templates replacement>'; });