diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 104e3d0f..b7029468 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -1509,14 +1509,17 @@ jasmineRequire.PerformanceView = function(j$) { const MAX_SLOW_SPECS = 20; class PerformanceView { + #summary; #tbody; constructor() { this.#tbody = document.createElement('tbody'); + this.#summary = document.createElement('div'); this.rootEl = createDom( 'div', { className: 'jasmine-performance-view' }, createDom('h2', {}, 'Performance'), + this.#summary, createDom('h3', {}, 'Slowest Specs'), createDom( 'table', @@ -1537,9 +1540,13 @@ jasmineRequire.PerformanceView = function(j$) { } addResults(resultsTree) { - let specResults = []; + const specResults = []; getSpecResults(resultsTree, specResults); + if (specResults.length === 0) { + return; + } + specResults.sort(function(a, b) { if (a.duration < b.duration) { return 1; @@ -1549,6 +1556,25 @@ jasmineRequire.PerformanceView = function(j$) { return 0; } }); + + this.#populateSumary(specResults); + this.#populateTable(specResults); + } + + #populateSumary(specResults) { + const total = specResults.map(r => r.duration).reduce((a, b) => a + b, 0); + const mean = total / specResults.length; + const median = specResults[Math.floor(specResults.length / 2)].duration; + this.#summary.appendChild( + document.createTextNode(`Mean spec run time: ${mean.toFixed(0)}ms`) + ); + this.#summary.appendChild(document.createElement('br')); + this.#summary.appendChild( + document.createTextNode(`Median spec run time: ${median}ms`) + ); + } + + #populateTable(specResults) { specResults = specResults.slice(0, MAX_SLOW_SPECS); for (const r of specResults) { diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 167639d0..24cf47dd 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -337,4 +337,15 @@ body { .jasmine-tab + .jasmine-tab:before { content: " | "; +} + +.jasmine-performance-view h2, .jasmine-performance-view h3 { + margin-top: 1em; + margin-bottom: 1em; +} +.jasmine-performance-view table { + border-spacing: 5px; +} +.jasmine-performance-view th, .jasmine-performance-view td { + text-align: left; } \ No newline at end of file diff --git a/spec/html/PerformanceViewSpec.js b/spec/html/PerformanceViewSpec.js index 3da3e359..63e5f873 100644 --- a/spec/html/PerformanceViewSpec.js +++ b/spec/html/PerformanceViewSpec.js @@ -44,6 +44,42 @@ describe('PerformanceView', function() { expect(subject.textContent).not.toContain('spec 0'); }); + it('shows mean and median run times for an odd number of specs', function() { + const stateBuilder = new privateUnderTest.ResultsStateBuilder(); + const subject = new privateUnderTest.PerformanceView(); + + stateBuilder.specDone({ duration: 1 }); + stateBuilder.specDone({ duration: 2 }); + stateBuilder.specDone({ duration: 5 }); + subject.addResults(stateBuilder.topResults); + + expect(subject.rootEl.textContent).toContain('Mean spec run time: 3ms'); + expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms'); + }); + + it('shows mean and median run times for an even number of specs', function() { + const stateBuilder = new privateUnderTest.ResultsStateBuilder(); + const subject = new privateUnderTest.PerformanceView(); + + stateBuilder.specDone({ duration: 1 }); + stateBuilder.specDone({ duration: 3 }); + stateBuilder.specDone({ duration: 10 }); + stateBuilder.specDone({ duration: 2 }); + subject.addResults(stateBuilder.topResults); + + expect(subject.rootEl.textContent).toContain('Mean spec run time: 4ms'); + expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms'); + }); + + it('copes with 0 specs', function() { + const stateBuilder = new privateUnderTest.ResultsStateBuilder(); + const subject = new privateUnderTest.PerformanceView(); + + expect(function() { + subject.addResults(stateBuilder.topResults); + }).not.toThrow(); + }); + it('filters out excluded specs', function() { const stateBuilder = new privateUnderTest.ResultsStateBuilder(); stateBuilder.specDone({ @@ -65,5 +101,7 @@ describe('PerformanceView', function() { const rows = Array.from(subject.rootEl.querySelectorAll('tbody tr')); const names = rows.map(r => r.querySelectorAll('td')[1].textContent); expect(names).toEqual(['spec C', 'spec A']); + expect(subject.rootEl.textContent).toContain('Mean spec run time: 3ms'); + expect(subject.rootEl.textContent).toContain('Median spec run time: 2ms'); }); }); diff --git a/src/html/PerformanceView.js b/src/html/PerformanceView.js index fddc5eff..5f1f2948 100644 --- a/src/html/PerformanceView.js +++ b/src/html/PerformanceView.js @@ -3,14 +3,17 @@ jasmineRequire.PerformanceView = function(j$) { const MAX_SLOW_SPECS = 20; class PerformanceView { + #summary; #tbody; constructor() { this.#tbody = document.createElement('tbody'); + this.#summary = document.createElement('div'); this.rootEl = createDom( 'div', { className: 'jasmine-performance-view' }, createDom('h2', {}, 'Performance'), + this.#summary, createDom('h3', {}, 'Slowest Specs'), createDom( 'table', @@ -31,9 +34,13 @@ jasmineRequire.PerformanceView = function(j$) { } addResults(resultsTree) { - let specResults = []; + const specResults = []; getSpecResults(resultsTree, specResults); + if (specResults.length === 0) { + return; + } + specResults.sort(function(a, b) { if (a.duration < b.duration) { return 1; @@ -43,6 +50,25 @@ jasmineRequire.PerformanceView = function(j$) { return 0; } }); + + this.#populateSumary(specResults); + this.#populateTable(specResults); + } + + #populateSumary(specResults) { + const total = specResults.map(r => r.duration).reduce((a, b) => a + b, 0); + const mean = total / specResults.length; + const median = specResults[Math.floor(specResults.length / 2)].duration; + this.#summary.appendChild( + document.createTextNode(`Mean spec run time: ${mean.toFixed(0)}ms`) + ); + this.#summary.appendChild(document.createElement('br')); + this.#summary.appendChild( + document.createTextNode(`Median spec run time: ${median}ms`) + ); + } + + #populateTable(specResults) { specResults = specResults.slice(0, MAX_SLOW_SPECS); for (const r of specResults) { diff --git a/src/html/_HTMLReporter.scss b/src/html/_HTMLReporter.scss index d6a285fb..e804397f 100644 --- a/src/html/_HTMLReporter.scss +++ b/src/html/_HTMLReporter.scss @@ -482,3 +482,18 @@ body { .jasmine-tab + .jasmine-tab:before { content: ' | '; } + +.jasmine-performance-view { + h2, h3 { + margin-top: 1em; + margin-bottom: 1em; + } + + table { + border-spacing: 5px; + } + + th, td { + text-align: left; + } +}