diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index a8963132..104e3d0f 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -35,6 +35,7 @@ jasmineRequire.html = function(j$) { j$.private.SymbolsView = jasmineRequire.SymbolsView(j$); j$.private.SummaryTreeView = jasmineRequire.SummaryTreeView(j$); j$.private.FailuresView = jasmineRequire.FailuresView(j$); + j$.private.PerformanceView = jasmineRequire.PerformanceView(j$); j$.private.TabBar = jasmineRequire.TabBar(j$); j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); j$.HtmlReporterV2Urls = jasmineRequire.HtmlReporterV2Urls(j$); @@ -992,6 +993,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) { const specListTabId = 'jasmine-specListTab'; const failuresTabId = 'jasmine-failuresTab'; + const perfTabId = 'jasmine-perfTab'; /** * @class HtmlReporterV2 @@ -1063,13 +1065,16 @@ jasmineRequire.HtmlReporterV2 = function(j$) { this.#tabBar = new j$.private.TabBar( [ { id: specListTabId, label: 'Spec List' }, - { id: failuresTabId, label: 'Failures' } + { id: failuresTabId, label: 'Failures' }, + { id: perfTabId, label: 'Performance' } ], tabId => { if (tabId === specListTabId) { this.#setMenuModeTo('jasmine-spec-list'); - } else { + } else if (tabId === failuresTabId) { this.#setMenuModeTo('jasmine-failure-list'); + } else { + this.#setMenuModeTo('jasmine-performance'); } } ); @@ -1165,9 +1170,13 @@ jasmineRequire.HtmlReporterV2 = function(j$) { ); summary.addResults(this.#stateBuilder.topResults); results.appendChild(summary.rootEl); + const perf = new j$.private.PerformanceView(); + perf.addResults(this.#stateBuilder.topResults); + results.appendChild(perf.rootEl); + this.#tabBar.showTab(specListTabId); + this.#tabBar.showTab(perfTabId); if (this.#stateBuilder.anyNonTopSuiteFailures) { - this.#tabBar.showTab(specListTabId); this.#tabBar.showTab(failuresTabId); this.#tabBar.selectTab(failuresTabId); } else { @@ -1495,6 +1504,79 @@ jasmineRequire.OverallStatusBar = function(j$) { return OverallStatusBar; }; +jasmineRequire.PerformanceView = function(j$) { + const createDom = j$.private.htmlReporterUtils.createDom; + const MAX_SLOW_SPECS = 20; + + class PerformanceView { + #tbody; + + constructor() { + this.#tbody = document.createElement('tbody'); + this.rootEl = createDom( + 'div', + { className: 'jasmine-performance-view' }, + createDom('h2', {}, 'Performance'), + createDom('h3', {}, 'Slowest Specs'), + createDom( + 'table', + {}, + createDom( + 'thead', + {}, + createDom( + 'tr', + {}, + createDom('th', {}, 'Duration'), + createDom('th', {}, 'Spec Name') + ) + ), + this.#tbody + ) + ); + } + + addResults(resultsTree) { + let specResults = []; + getSpecResults(resultsTree, specResults); + + specResults.sort(function(a, b) { + if (a.duration < b.duration) { + return 1; + } else if (a.duration > b.duration) { + return -1; + } else { + return 0; + } + }); + specResults = specResults.slice(0, MAX_SLOW_SPECS); + + for (const r of specResults) { + this.#tbody.appendChild( + createDom( + 'tr', + {}, + createDom('td', {}, `${r.duration}ms`), + createDom('td', {}, r.fullName) + ) + ); + } + } + } + + function getSpecResults(resultsTree, dest) { + for (const node of resultsTree.children) { + if (node.type === 'suite') { + getSpecResults(node, dest); + } else if (node.result.status !== 'excluded') { + dest.push(node.result); + } + } + } + + return PerformanceView; +}; + jasmineRequire.ResultsStateBuilder = function(j$) { 'use strict'; diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index e0596114..167639d0 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -198,11 +198,17 @@ body { color: white; } .jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list, -.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures { +.jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures, +.jasmine_html-reporter.jasmine-spec-list .jasmine-performance-view { display: none; } .jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list, -.jasmine_html-reporter.jasmine-failure-list .jasmine-summary { +.jasmine_html-reporter.jasmine-failure-list .jasmine-summary, +.jasmine_html-reporter.jasmine-failure-list .jasmine-performance-view { + display: none; +} +.jasmine_html-reporter.jasmine-performance .jasmine-results .jasmine-failures, +.jasmine_html-reporter.jasmine-performance .jasmine-summary { display: none; } .jasmine_html-reporter .jasmine-results { diff --git a/spec/html/HtmlReporterV2Spec.js b/spec/html/HtmlReporterV2Spec.js index cafebe4a..d422e817 100644 --- a/spec/html/HtmlReporterV2Spec.js +++ b/spec/html/HtmlReporterV2Spec.js @@ -275,10 +275,11 @@ describe('HtmlReporterV2', function() { reporter.initialize(); reporter.jasmineStarted({ totalSpecsDefined: 0 }); const tabs = container.querySelectorAll('.jasmine-tab'); - expect(tabs.length).toEqual(2); + expect(tabs.length).toEqual(3); expect(tabs[0].textContent).toEqual('Spec List'); expect(tabs[1].textContent).toEqual('Failures'); - checkHidden(tabs, [true, true]); + expect(tabs[2].textContent).toEqual('Performance'); + checkHidden(tabs, [true, true, true]); // Results, even failures, should not show any tabs reporter.specDone({ @@ -289,7 +290,7 @@ describe('HtmlReporterV2', function() { failedExpectations: [{}], passedExpectations: [] }); - checkHidden(tabs, [true, true]); + checkHidden(tabs, [true, true, true]); }); }); @@ -303,9 +304,9 @@ describe('HtmlReporterV2', function() { reportEvents(reporter); }); - it('shows the Spec List and Failures tabs', function() { + it('shows all three tabs', function() { const tabs = container.querySelectorAll('.jasmine-tab'); - checkHidden(tabs, [false, false]); + checkHidden(tabs, [false, false, false]); }); it('selects the Failures tab', function() { @@ -357,9 +358,9 @@ describe('HtmlReporterV2', function() { reportEvents(reporter); }); - it('does not show any tabs', function() { + it('shows the Spec List and Performance tabs', function() { const tabs = container.querySelectorAll('.jasmine-tab'); - checkHidden(tabs, [true, true]); + checkHidden(tabs, [false, true, false]); }); it('shows the spec list view', function() { @@ -443,6 +444,26 @@ describe('HtmlReporterV2', function() { }); }); }); + + it('shows the slow spec view when the Performance tab is clicked', function() { + const reporter = setup(); + reporter.initialize(); + reporter.jasmineStarted({ totalSpecsDefined: 0 }); + reporter.specDone({ + duration: 1.2, + failedExpectations: [], + passedExpectations: [] + }); + reporter.jasmineDone({}); + const tabs = container.querySelectorAll('.jasmine-tab'); + let perfLink = tabs[2].querySelector('a'); + const reporterNode = container.querySelector('.jasmine_html-reporter'); + expect(perfLink.textContent).toEqual('Performance'); + perfLink.click(); + expect(reporterNode).toHaveClass('jasmine-performance'); + expect(reporterNode.innerHTML).toContain('