Merge branch 'slow-reporter' into 6.0
This commit is contained in:
@@ -24,6 +24,7 @@ jasmineRequire.AlertsView = function(j$) {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: remove this once HtmlReporterV2 doesn't use it
|
||||
addFailureToggle(onClickFailures, onClickSpecList) {
|
||||
const failuresLink = createDom(
|
||||
'a',
|
||||
@@ -46,14 +47,20 @@ jasmineRequire.AlertsView = function(j$) {
|
||||
return false;
|
||||
};
|
||||
|
||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-spec-list', [
|
||||
createDom('span', {}, 'Spec List | '),
|
||||
failuresLink
|
||||
]);
|
||||
this.#createAndAdd('jasmine-menu jasmine-bar jasmine-failure-list', [
|
||||
specListLink,
|
||||
createDom('span', {}, ' | Failures ')
|
||||
]);
|
||||
this.rootEl.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||
)
|
||||
);
|
||||
this.rootEl.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
addGlobalFailure(failure) {
|
||||
|
||||
@@ -142,16 +142,52 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
results.appendChild(summary.rootEl);
|
||||
|
||||
if (this.#stateBuilder.anyNonTopSuiteFailures) {
|
||||
this.#alerts.addFailureToggle(
|
||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
||||
);
|
||||
|
||||
this.#addFailureToggle();
|
||||
this.#setMenuModeTo('jasmine-failure-list');
|
||||
this.#failures.show();
|
||||
}
|
||||
}
|
||||
|
||||
#addFailureToggle() {
|
||||
const onClickFailures = () => this.#setMenuModeTo('jasmine-failure-list');
|
||||
const onClickSpecList = () => this.#setMenuModeTo('jasmine-spec-list');
|
||||
const failuresLink = createDom(
|
||||
'a',
|
||||
{ className: 'jasmine-failures-menu', href: '#' },
|
||||
'Failures'
|
||||
);
|
||||
let specListLink = createDom(
|
||||
'a',
|
||||
{ className: 'jasmine-spec-list-menu', href: '#' },
|
||||
'Spec List'
|
||||
);
|
||||
|
||||
failuresLink.onclick = function() {
|
||||
onClickFailures();
|
||||
return false;
|
||||
};
|
||||
|
||||
specListLink.onclick = function() {
|
||||
onClickSpecList();
|
||||
return false;
|
||||
};
|
||||
|
||||
this.#alerts.addBar(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||
[createDom('span', {}, 'Spec List | '), failuresLink]
|
||||
)
|
||||
);
|
||||
this.#alerts.addBar(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||
[specListLink, createDom('span', {}, ' | Failures ')]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#find(selector) {
|
||||
return this.#getContainer().querySelector(
|
||||
'.jasmine_html-reporter ' + selector
|
||||
|
||||
@@ -3,6 +3,10 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
||||
|
||||
const { createDom, noExpectations } = j$.private.htmlReporterUtils;
|
||||
|
||||
const specListTabId = 'jasmine-specListTab';
|
||||
const failuresTabId = 'jasmine-failuresTab';
|
||||
const perfTabId = 'jasmine-perfTab';
|
||||
|
||||
/**
|
||||
* @class HtmlReporterV2
|
||||
* @classdesc Displays results and allows re-running individual specs and suites.
|
||||
@@ -31,6 +35,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
||||
// Sub-views
|
||||
#alerts;
|
||||
#statusBar;
|
||||
#tabBar;
|
||||
#progress;
|
||||
#banner;
|
||||
#failures;
|
||||
@@ -68,6 +73,25 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
||||
this.#statusBar = new j$.private.OverallStatusBar(this.#urlBuilder);
|
||||
this.#statusBar.showRunning();
|
||||
this.#alerts.addBar(this.#statusBar.rootEl);
|
||||
|
||||
this.#tabBar = new j$.private.TabBar(
|
||||
[
|
||||
{ id: specListTabId, label: 'Spec List' },
|
||||
{ id: failuresTabId, label: 'Failures' },
|
||||
{ id: perfTabId, label: 'Performance' }
|
||||
],
|
||||
tabId => {
|
||||
if (tabId === specListTabId) {
|
||||
this.#setMenuModeTo('jasmine-spec-list');
|
||||
} else if (tabId === failuresTabId) {
|
||||
this.#setMenuModeTo('jasmine-failure-list');
|
||||
} else {
|
||||
this.#setMenuModeTo('jasmine-performance');
|
||||
}
|
||||
}
|
||||
);
|
||||
this.#alerts.addBar(this.#tabBar.rootEl);
|
||||
|
||||
this.#progress = new ProgressView();
|
||||
this.#banner = new j$.private.Banner(
|
||||
this.#queryString.navigateWithNewParam.bind(this.#queryString),
|
||||
@@ -158,15 +182,17 @@ 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.#alerts.addFailureToggle(
|
||||
() => this.#setMenuModeTo('jasmine-failure-list'),
|
||||
() => this.#setMenuModeTo('jasmine-spec-list')
|
||||
);
|
||||
|
||||
this.#setMenuModeTo('jasmine-failure-list');
|
||||
this.#failures.show();
|
||||
this.#tabBar.showTab(failuresTabId);
|
||||
this.#tabBar.selectTab(failuresTabId);
|
||||
} else {
|
||||
this.#tabBar.selectTab(specListTabId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +231,6 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
|
||||
this.rootEl.value = this.rootEl.value + 1;
|
||||
|
||||
if (result.status === 'failed') {
|
||||
// TODO: also a non-color indicator
|
||||
this.rootEl.classList.add('failed');
|
||||
}
|
||||
}
|
||||
|
||||
98
src/html/PerformanceView.js
Normal file
98
src/html/PerformanceView.js
Normal file
@@ -0,0 +1,98 @@
|
||||
jasmineRequire.PerformanceView = function(j$) {
|
||||
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||
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',
|
||||
{},
|
||||
createDom(
|
||||
'thead',
|
||||
{},
|
||||
createDom(
|
||||
'tr',
|
||||
{},
|
||||
createDom('th', {}, 'Duration'),
|
||||
createDom('th', {}, 'Spec Name')
|
||||
)
|
||||
),
|
||||
this.#tbody
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
addResults(resultsTree) {
|
||||
const specResults = [];
|
||||
getSpecResults(resultsTree, specResults);
|
||||
|
||||
if (specResults.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
specResults.sort(function(a, b) {
|
||||
if (a.duration < b.duration) {
|
||||
return 1;
|
||||
} else if (a.duration > b.duration) {
|
||||
return -1;
|
||||
} else {
|
||||
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) {
|
||||
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;
|
||||
};
|
||||
77
src/html/TabBar.js
Normal file
77
src/html/TabBar.js
Normal file
@@ -0,0 +1,77 @@
|
||||
jasmineRequire.TabBar = function(j$) {
|
||||
const createDom = j$.private.htmlReporterUtils.createDom;
|
||||
|
||||
class TabBar {
|
||||
#tabs;
|
||||
#onSelectTab;
|
||||
|
||||
// tabSpecs should be an array of {id, label}.
|
||||
// All tabs are initially not visible and not selected.
|
||||
constructor(tabSpecs, onSelectTab) {
|
||||
this.#onSelectTab = onSelectTab;
|
||||
this.#tabs = [];
|
||||
this.#tabs = tabSpecs.map(ts => new Tab(ts, () => this.selectTab(ts.id)));
|
||||
|
||||
this.rootEl = createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar' },
|
||||
this.#tabs.map(t => t.rootEl)
|
||||
);
|
||||
}
|
||||
|
||||
showTab(id) {
|
||||
for (const tab of this.#tabs) {
|
||||
if (tab.rootEl.id === id) {
|
||||
tab.setVisibility(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectTab(id) {
|
||||
for (const tab of this.#tabs) {
|
||||
tab.setSelected(tab.rootEl.id === id);
|
||||
}
|
||||
|
||||
this.#onSelectTab(id);
|
||||
}
|
||||
}
|
||||
|
||||
class Tab {
|
||||
#spec;
|
||||
#onClick;
|
||||
|
||||
constructor(spec, onClick) {
|
||||
this.#spec = spec;
|
||||
this.#onClick = onClick;
|
||||
this.rootEl = createDom(
|
||||
'span',
|
||||
{ id: spec.id, className: 'jasmine-tab jasmine-hidden' },
|
||||
this.#createLink()
|
||||
);
|
||||
}
|
||||
|
||||
setVisibility(visible) {
|
||||
this.rootEl.classList.toggle('jasmine-hidden', !visible);
|
||||
}
|
||||
|
||||
setSelected(selected) {
|
||||
if (selected) {
|
||||
this.rootEl.textContent = this.#spec.label;
|
||||
} else {
|
||||
this.rootEl.textContent = '';
|
||||
this.rootEl.appendChild(this.#createLink());
|
||||
}
|
||||
}
|
||||
|
||||
#createLink() {
|
||||
const link = createDom('a', { href: '#' }, this.#spec.label);
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
this.#onClick();
|
||||
});
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
return TabBar;
|
||||
};
|
||||
@@ -280,15 +280,25 @@ body {
|
||||
}
|
||||
|
||||
// simplify toggle control between the two menu bars
|
||||
// TODO: clean this up once HtmlReporter is removed
|
||||
&.jasmine-spec-list {
|
||||
.jasmine-bar.jasmine-menu.jasmine-failure-list,
|
||||
.jasmine-results .jasmine-failures {
|
||||
.jasmine-results .jasmine-failures,
|
||||
.jasmine-performance-view {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.jasmine-failure-list {
|
||||
.jasmine-bar.jasmine-menu.jasmine-spec-list,
|
||||
.jasmine-summary,
|
||||
.jasmine-performance-view {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.jasmine-performance {
|
||||
.jasmine-results .jasmine-failures,
|
||||
.jasmine-summary {
|
||||
display: none;
|
||||
}
|
||||
@@ -464,3 +474,26 @@ body {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jasmine-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ 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$);
|
||||
j$.HtmlReporterV2 = jasmineRequire.HtmlReporterV2(j$);
|
||||
|
||||
Reference in New Issue
Block a user