HtmlReporterV2: replace dots with progress bar

This commit is contained in:
Steve Gravrock
2025-10-09 12:22:24 -07:00
parent 9b3cc08818
commit 86387c9068
10 changed files with 260 additions and 229 deletions
+91 -61
View File
@@ -618,9 +618,11 @@ jasmineRequire.Banner = function(j$) {
class Banner { class Banner {
#navigateWithNewParam; #navigateWithNewParam;
#omitHideDisabled;
constructor(navigateWithNewParam) { constructor(navigateWithNewParam, omitHideDisabled) {
this.#navigateWithNewParam = navigateWithNewParam; this.#navigateWithNewParam = navigateWithNewParam;
this.#omitHideDisabled = omitHideDisabled;
this.rootEl = createDom( this.rootEl = createDom(
'div', 'div',
{ className: 'jasmine-banner' }, { className: 'jasmine-banner' },
@@ -638,55 +640,53 @@ jasmineRequire.Banner = function(j$) {
} }
#optionsMenu(config) { #optionsMenu(config) {
const optionsMenuDom = createDom( const items = [
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom( createDom(
'div', 'div',
{ className: 'jasmine-payload' }, { className: 'jasmine-stop-on-failure' },
createDom('input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-stop-on-failure' }, { className: 'jasmine-label', for: 'jasmine-fail-fast' },
createDom('input', { 'stop execution on spec failure'
className: 'jasmine-fail-fast', )
id: 'jasmine-fail-fast', ),
type: 'checkbox' createDom(
}), 'div',
createDom( { className: 'jasmine-throw-failures' },
'label', createDom('input', {
{ className: 'jasmine-label', for: 'jasmine-fail-fast' }, className: 'jasmine-throw',
'stop execution on spec failure' id: 'jasmine-throw-failures',
) type: 'checkbox'
), }),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-throw-failures' }, { className: 'jasmine-label', for: 'jasmine-throw-failures' },
createDom('input', { 'stop spec on expectation failure'
className: 'jasmine-throw', )
id: 'jasmine-throw-failures', ),
type: 'checkbox' createDom(
}), 'div',
createDom( { className: 'jasmine-random-order' },
'label', createDom('input', {
{ className: 'jasmine-label', for: 'jasmine-throw-failures' }, className: 'jasmine-random',
'stop spec on expectation failure' id: 'jasmine-random-order',
) type: 'checkbox'
), }),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-random-order' }, { className: 'jasmine-label', for: 'jasmine-random-order' },
createDom('input', { 'run tests in random order'
className: 'jasmine-random', )
id: 'jasmine-random-order', )
type: 'checkbox' ];
}),
createDom( if (!this.#omitHideDisabled) {
'label', items.push(
{ className: 'jasmine-label', for: 'jasmine-random-order' },
'run tests in random order'
)
),
createDom( createDom(
'div', 'div',
{ className: 'jasmine-hide-disabled' }, { className: 'jasmine-hide-disabled' },
@@ -701,7 +701,14 @@ jasmineRequire.Banner = function(j$) {
'hide disabled tests' 'hide disabled tests'
) )
) )
) );
}
const optionsMenuDom = createDom(
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' }, items)
); );
const failFastCheckbox = optionsMenuDom.querySelector( const failFastCheckbox = optionsMenuDom.querySelector(
@@ -734,14 +741,16 @@ jasmineRequire.Banner = function(j$) {
this.#navigateWithNewParam('random', !config.random); this.#navigateWithNewParam('random', !config.random);
}; };
const hideDisabled = optionsMenuDom.querySelector( if (!this.#omitHideDisabled) {
'#jasmine-hide-disabled' const hideDisabled = optionsMenuDom.querySelector(
); '#jasmine-hide-disabled'
hideDisabled.checked = config.hideDisabled; );
// TODO: backfill tests for this! hideDisabled.checked = config.hideDisabled;
hideDisabled.onclick = () => { // TODO: backfill tests for this!
this.#navigateWithNewParam('hideDisabled', !config.hideDisabled); hideDisabled.onclick = () => {
}; this.#navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
}
const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
@@ -1004,7 +1013,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
// Sub-views // Sub-views
#alerts; #alerts;
#symbols; #progress;
#banner; #banner;
#failures; #failures;
@@ -1038,16 +1047,17 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
this.#stateBuilder = new j$.private.ResultsStateBuilder(); this.#stateBuilder = new j$.private.ResultsStateBuilder();
this.#alerts = new j$.private.AlertsView(this.#urlBuilder); this.#alerts = new j$.private.AlertsView(this.#urlBuilder);
this.#symbols = new j$.private.SymbolsView(); this.#progress = new ProgressView();
this.#banner = new j$.private.Banner( this.#banner = new j$.private.Banner(
this.#queryString.navigateWithNewParam.bind(this.#queryString) this.#queryString.navigateWithNewParam.bind(this.#queryString),
true
); );
this.#failures = new j$.private.FailuresView(this.#urlBuilder); this.#failures = new j$.private.FailuresView(this.#urlBuilder);
this.#htmlReporterMain = createDom( this.#htmlReporterMain = createDom(
'div', 'div',
{ className: 'jasmine_html-reporter' }, { className: 'jasmine_html-reporter' },
this.#banner.rootEl, this.#banner.rootEl,
this.#symbols.rootEl, this.#progress.rootEl,
this.#alerts.rootEl, this.#alerts.rootEl,
this.#failures.rootEl this.#failures.rootEl
); );
@@ -1056,6 +1066,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineStarted(options) { jasmineStarted(options) {
this.#stateBuilder.jasmineStarted(options); this.#stateBuilder.jasmineStarted(options);
this.#progress.start(options.totalSpecsDefined);
} }
suiteStarted(result) { suiteStarted(result) {
@@ -1072,7 +1083,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
specDone(result) { specDone(result) {
this.#stateBuilder.specDone(result); this.#stateBuilder.specDone(result);
this.#symbols.append(result, this.#config); this.#progress.specDone(result, this.#config);
if (noExpectations(result)) { if (noExpectations(result)) {
const noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
@@ -1092,6 +1103,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineDone(doneResult) { jasmineDone(doneResult) {
this.#stateBuilder.jasmineDone(doneResult); this.#stateBuilder.jasmineDone(doneResult);
this.#progress.rootEl.style.visibility = 'hidden';
this.#alerts.addDuration(doneResult.totalTime); this.#alerts.addDuration(doneResult.totalTime);
this.#banner.showOptionsMenu(this.#config); this.#banner.showOptionsMenu(this.#config);
@@ -1157,6 +1169,25 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
} }
} }
class ProgressView {
constructor() {
this.rootEl = createDom('progress', { value: 0 });
}
start(totalSpecsDefined) {
this.rootEl.max = totalSpecsDefined;
}
specDone(result) {
this.rootEl.value = this.rootEl.value + 1;
if (result.status === 'failed') {
// TODO: also a non-color indicator
this.rootEl.classList.add('failed');
}
}
}
class UrlBuilder { class UrlBuilder {
#queryString; #queryString;
#getSuiteById; #getSuiteById;
@@ -1237,8 +1268,7 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
stopOnSpecFailure: this.queryString.getParam('stopOnSpecFailure'), stopOnSpecFailure: this.queryString.getParam('stopOnSpecFailure'),
stopSpecOnExpectationFailure: this.queryString.getParam( stopSpecOnExpectationFailure: this.queryString.getParam(
'stopSpecOnExpectationFailure' 'stopSpecOnExpectationFailure'
), )
hideDisabled: this.queryString.getParam('hideDisabled')
}; };
const random = this.queryString.getParam('random'); const random = this.queryString.getParam('random');
+21
View File
@@ -1,4 +1,25 @@
@charset "UTF-8"; @charset "UTF-8";
progress {
width: 100%;
}
progress[value] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
progress[value]::-webkit-progress-value, progress[value]::-moz-progress-bar {
background: #007069;
}
.failed progress[value]::-webkit-progress-value, .failed progress[value]::-moz-progress-bar {
background: #ca3a11;
}
progress.failed[value]::-webkit-progress-value, progress.failed[value]::-moz-progress-bar {
background: #ca3a11;
}
body { body {
overflow-y: scroll; overflow-y: scroll;
} }
+3
View File
@@ -3452,6 +3452,8 @@ getJasmineRequireObj().Configuration = function(j$) {
specFilter: function() { specFilter: function() {
return true; return true;
}, },
// TODO: remove hideDisabled when HtmlReporter is removed
/** /**
* Whether reporters should hide disabled specs from their output. * Whether reporters should hide disabled specs from their output.
* Currently only supported by Jasmine's HTMLReporter * Currently only supported by Jasmine's HTMLReporter
@@ -3459,6 +3461,7 @@ getJasmineRequireObj().Configuration = function(j$) {
* @since 3.3.0 * @since 3.3.0
* @type Boolean * @type Boolean
* @default false * @default false
* @deprecated
*/ */
hideDisabled: false, hideDisabled: false,
/** /**
+31 -106
View File
@@ -35,7 +35,7 @@ describe('HtmlReporterV2', function() {
expect(container.querySelector('div.jasmine-alert')).toBeTruthy(); expect(container.querySelector('div.jasmine-alert')).toBeTruthy();
expect(container.querySelector('div.jasmine-results')).toBeTruthy(); expect(container.querySelector('div.jasmine-results')).toBeTruthy();
expect(container.querySelector('ul.jasmine-symbol-summary')).toBeTruthy(); expect(container.querySelector('progress')).toBeTruthy();
// title banner // title banner
const banner = container.querySelector('.jasmine-banner'); const banner = container.querySelector('.jasmine-banner');
@@ -72,7 +72,7 @@ describe('HtmlReporterV2', function() {
reporter.initialize(); reporter.initialize();
}); });
it('should log warning to the console and print a special symbol when empty spec status is passed', function() { it('logs a warning to the console when the spec passed', function() {
reporter.specDone({ reporter.specDone({
status: 'passed', status: 'passed',
fullName: 'Some Name', fullName: 'Some Name',
@@ -83,11 +83,9 @@ describe('HtmlReporterV2', function() {
expect(console.warn).toHaveBeenCalledWith( expect(console.warn).toHaveBeenCalledWith(
"Spec 'Some Name' has no expectations." "Spec 'Some Name' has no expectations."
); );
const specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute('class')).toEqual('jasmine-empty');
}); });
it('should log error to the console and print a failure symbol when empty spec status is failed', function() { it('logs an error to the console when the spec failed', function() {
reporter.specDone({ reporter.specDone({
status: 'failed', status: 'failed',
fullName: 'Some Name', fullName: 'Some Name',
@@ -98,64 +96,32 @@ describe('HtmlReporterV2', function() {
expect(console.error).toHaveBeenCalledWith( expect(console.error).toHaveBeenCalledWith(
"Spec 'Some Name' has no expectations." "Spec 'Some Name' has no expectations."
); );
const specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute('class')).toEqual('jasmine-failed');
}); });
}); });
it('reports the status symbol of a excluded spec', function() { it('updates the progress bar', function() {
const reporter = setup();
reporter.initialize();
reporter.specDone({
id: 789,
status: 'excluded',
fullName: 'symbols should have titles',
passedExpectations: [],
failedExpectations: []
});
const specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute('class')).toEqual('jasmine-excluded');
expect(specEl.getAttribute('id')).toEqual('spec_789');
expect(specEl.getAttribute('title')).toEqual(
'symbols should have titles'
);
});
it('reports the status symbol of a pending spec', function() {
const reporter = setup();
reporter.initialize();
reporter.specDone({
id: 789,
status: 'pending',
passedExpectations: [],
failedExpectations: []
});
const specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute('class')).toEqual('jasmine-pending');
expect(specEl.getAttribute('id')).toEqual('spec_789');
});
it('reports the status symbol of a passing spec', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
const progress = container.querySelector('progress');
reporter.specDone({ reporter.specDone({
id: 123, id: 123,
status: 'passed', status: 'passed',
passedExpectations: [{ passed: true }], failedExpectations: [],
failedExpectations: [] passedExpectations: []
}); });
expect(progress.getAttribute('value')).toEqual('1');
const statuses = container.querySelector('.jasmine-symbol-summary'); reporter.specDone({
const specEl = statuses.querySelector('li'); id: 345,
expect(specEl.getAttribute('class')).toEqual('jasmine-passed'); status: 'passed',
expect(specEl.getAttribute('id')).toEqual('spec_123'); failedExpectations: [],
passedExpectations: []
});
expect(progress.getAttribute('value')).toEqual('2');
}); });
it('reports the status symbol of a failing spec', function() { it('changes the progress bar status if the spec failed', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
@@ -166,9 +132,8 @@ describe('HtmlReporterV2', function() {
passedExpectations: [] passedExpectations: []
}); });
const specEl = container.querySelector('.jasmine-symbol-summary li'); const progress = container.querySelector('progress');
expect(specEl.getAttribute('class')).toEqual('jasmine-failed'); expect(progress).toHaveClass('failed');
expect(specEl.getAttribute('id')).toEqual('spec_345');
}); });
}); });
@@ -177,7 +142,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.specDone({ reporter.specDone({
status: 'passed', status: 'passed',
fullName: 'a spec with a deprecation', fullName: 'a spec with a deprecation',
@@ -218,7 +183,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -254,7 +219,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -273,7 +238,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -298,7 +263,7 @@ describe('HtmlReporterV2', function() {
spyOn(console, 'error'); spyOn(console, 'error');
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.suiteStarted({ id: 1 }); reporter.suiteStarted({ id: 1 });
reporter.specDone({ reporter.specDone({
id: 1, id: 1,
@@ -322,7 +287,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ totalTime: 100 }); reporter.jasmineDone({ totalTime: 100 });
@@ -340,7 +305,7 @@ describe('HtmlReporterV2', function() {
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.suiteStarted({ reporter.suiteStarted({
id: 1, id: 1,
description: 'A Suite', description: 'A Suite',
@@ -471,7 +436,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ {
@@ -503,7 +468,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ message: 'load error', globalErrorType: 'load' }, { message: 'load error', globalErrorType: 'load' },
@@ -533,7 +498,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ {
@@ -658,46 +623,6 @@ describe('HtmlReporterV2', function() {
}); });
}); });
describe('UI for hiding disabled specs', function() {
it('should be unchecked if not hiding disabled specs', function() {
const reporter = setup();
env.configure({ hideDisabled: false });
reporter.initialize();
reporter.jasmineDone({});
const disabledUI = container.querySelector('.jasmine-disabled');
expect(disabledUI.checked).toBe(false);
});
it('should be checked if hiding disabled', function() {
const reporter = setup();
env.configure({ hideDisabled: true });
reporter.initialize();
reporter.jasmineDone({});
const disabledUI = container.querySelector('.jasmine-disabled');
expect(disabledUI.checked).toBe(true);
});
it('should not display specs that have been disabled', function() {
const reporter = setup();
env.configure({ hideDisabled: true });
reporter.initialize();
reporter.specDone({
id: 789,
status: 'excluded',
fullName: 'symbols should have titles',
passedExpectations: [],
failedExpectations: []
});
const specEl = container.querySelector('.jasmine-symbol-summary li');
expect(specEl.getAttribute('class')).toEqual(
'jasmine-excluded-no-display'
);
});
});
describe('UI for running tests in random order', function() { describe('UI for running tests in random order', function() {
it('should be unchecked if not randomizing', function() { it('should be unchecked if not randomizing', function() {
const reporter = setup(); const reporter = setup();
@@ -1194,7 +1119,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'passed', overallStatus: 'passed',
failedExpectations: [] failedExpectations: []
@@ -1210,7 +1135,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'failed', overallStatus: 'failed',
failedExpectations: [] failedExpectations: []
@@ -1226,7 +1151,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({}); reporter.jasmineStarted({ totalSpecsDefined: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'incomplete', overallStatus: 'incomplete',
incompleteReason: 'because nope', incompleteReason: 'because nope',
-1
View File
@@ -2,7 +2,6 @@ describe('HtmlReporterV2Urls', function() {
describe('#configFromCurrentUrl', function() { describe('#configFromCurrentUrl', function() {
passesThroughQueryParam('stopOnSpecFailure'); passesThroughQueryParam('stopOnSpecFailure');
passesThroughQueryParam('stopSpecOnExpectationFailure'); passesThroughQueryParam('stopSpecOnExpectationFailure');
passesThroughQueryParam('hideDisabled');
passesThroughQueryParam('random'); passesThroughQueryParam('random');
ignoresEmpty('random'); ignoresEmpty('random');
passesThroughQueryParam('seed'); passesThroughQueryParam('seed');
+3
View File
@@ -73,6 +73,8 @@ getJasmineRequireObj().Configuration = function(j$) {
specFilter: function() { specFilter: function() {
return true; return true;
}, },
// TODO: remove hideDisabled when HtmlReporter is removed
/** /**
* Whether reporters should hide disabled specs from their output. * Whether reporters should hide disabled specs from their output.
* Currently only supported by Jasmine's HTMLReporter * Currently only supported by Jasmine's HTMLReporter
@@ -80,6 +82,7 @@ getJasmineRequireObj().Configuration = function(j$) {
* @since 3.3.0 * @since 3.3.0
* @type Boolean * @type Boolean
* @default false * @default false
* @deprecated
*/ */
hideDisabled: false, hideDisabled: false,
/** /**
+63 -54
View File
@@ -5,9 +5,11 @@ jasmineRequire.Banner = function(j$) {
class Banner { class Banner {
#navigateWithNewParam; #navigateWithNewParam;
#omitHideDisabled;
constructor(navigateWithNewParam) { constructor(navigateWithNewParam, omitHideDisabled) {
this.#navigateWithNewParam = navigateWithNewParam; this.#navigateWithNewParam = navigateWithNewParam;
this.#omitHideDisabled = omitHideDisabled;
this.rootEl = createDom( this.rootEl = createDom(
'div', 'div',
{ className: 'jasmine-banner' }, { className: 'jasmine-banner' },
@@ -25,55 +27,53 @@ jasmineRequire.Banner = function(j$) {
} }
#optionsMenu(config) { #optionsMenu(config) {
const optionsMenuDom = createDom( const items = [
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom( createDom(
'div', 'div',
{ className: 'jasmine-payload' }, { className: 'jasmine-stop-on-failure' },
createDom('input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-stop-on-failure' }, { className: 'jasmine-label', for: 'jasmine-fail-fast' },
createDom('input', { 'stop execution on spec failure'
className: 'jasmine-fail-fast', )
id: 'jasmine-fail-fast', ),
type: 'checkbox' createDom(
}), 'div',
createDom( { className: 'jasmine-throw-failures' },
'label', createDom('input', {
{ className: 'jasmine-label', for: 'jasmine-fail-fast' }, className: 'jasmine-throw',
'stop execution on spec failure' id: 'jasmine-throw-failures',
) type: 'checkbox'
), }),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-throw-failures' }, { className: 'jasmine-label', for: 'jasmine-throw-failures' },
createDom('input', { 'stop spec on expectation failure'
className: 'jasmine-throw', )
id: 'jasmine-throw-failures', ),
type: 'checkbox' createDom(
}), 'div',
createDom( { className: 'jasmine-random-order' },
'label', createDom('input', {
{ className: 'jasmine-label', for: 'jasmine-throw-failures' }, className: 'jasmine-random',
'stop spec on expectation failure' id: 'jasmine-random-order',
) type: 'checkbox'
), }),
createDom( createDom(
'div', 'label',
{ className: 'jasmine-random-order' }, { className: 'jasmine-label', for: 'jasmine-random-order' },
createDom('input', { 'run tests in random order'
className: 'jasmine-random', )
id: 'jasmine-random-order', )
type: 'checkbox' ];
}),
createDom( if (!this.#omitHideDisabled) {
'label', items.push(
{ className: 'jasmine-label', for: 'jasmine-random-order' },
'run tests in random order'
)
),
createDom( createDom(
'div', 'div',
{ className: 'jasmine-hide-disabled' }, { className: 'jasmine-hide-disabled' },
@@ -88,7 +88,14 @@ jasmineRequire.Banner = function(j$) {
'hide disabled tests' 'hide disabled tests'
) )
) )
) );
}
const optionsMenuDom = createDom(
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' }, items)
); );
const failFastCheckbox = optionsMenuDom.querySelector( const failFastCheckbox = optionsMenuDom.querySelector(
@@ -121,14 +128,16 @@ jasmineRequire.Banner = function(j$) {
this.#navigateWithNewParam('random', !config.random); this.#navigateWithNewParam('random', !config.random);
}; };
const hideDisabled = optionsMenuDom.querySelector( if (!this.#omitHideDisabled) {
'#jasmine-hide-disabled' const hideDisabled = optionsMenuDom.querySelector(
); '#jasmine-hide-disabled'
hideDisabled.checked = config.hideDisabled; );
// TODO: backfill tests for this! hideDisabled.checked = config.hideDisabled;
hideDisabled.onclick = () => { // TODO: backfill tests for this!
this.#navigateWithNewParam('hideDisabled', !config.hideDisabled); hideDisabled.onclick = () => {
}; this.#navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
}
const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'), optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
+27 -5
View File
@@ -22,7 +22,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
// Sub-views // Sub-views
#alerts; #alerts;
#symbols; #progress;
#banner; #banner;
#failures; #failures;
@@ -56,16 +56,17 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
this.#stateBuilder = new j$.private.ResultsStateBuilder(); this.#stateBuilder = new j$.private.ResultsStateBuilder();
this.#alerts = new j$.private.AlertsView(this.#urlBuilder); this.#alerts = new j$.private.AlertsView(this.#urlBuilder);
this.#symbols = new j$.private.SymbolsView(); this.#progress = new ProgressView();
this.#banner = new j$.private.Banner( this.#banner = new j$.private.Banner(
this.#queryString.navigateWithNewParam.bind(this.#queryString) this.#queryString.navigateWithNewParam.bind(this.#queryString),
true
); );
this.#failures = new j$.private.FailuresView(this.#urlBuilder); this.#failures = new j$.private.FailuresView(this.#urlBuilder);
this.#htmlReporterMain = createDom( this.#htmlReporterMain = createDom(
'div', 'div',
{ className: 'jasmine_html-reporter' }, { className: 'jasmine_html-reporter' },
this.#banner.rootEl, this.#banner.rootEl,
this.#symbols.rootEl, this.#progress.rootEl,
this.#alerts.rootEl, this.#alerts.rootEl,
this.#failures.rootEl this.#failures.rootEl
); );
@@ -74,6 +75,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineStarted(options) { jasmineStarted(options) {
this.#stateBuilder.jasmineStarted(options); this.#stateBuilder.jasmineStarted(options);
this.#progress.start(options.totalSpecsDefined);
} }
suiteStarted(result) { suiteStarted(result) {
@@ -90,7 +92,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
specDone(result) { specDone(result) {
this.#stateBuilder.specDone(result); this.#stateBuilder.specDone(result);
this.#symbols.append(result, this.#config); this.#progress.specDone(result, this.#config);
if (noExpectations(result)) { if (noExpectations(result)) {
const noSpecMsg = "Spec '" + result.fullName + "' has no expectations."; const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
@@ -110,6 +112,7 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineDone(doneResult) { jasmineDone(doneResult) {
this.#stateBuilder.jasmineDone(doneResult); this.#stateBuilder.jasmineDone(doneResult);
this.#progress.rootEl.style.visibility = 'hidden';
this.#alerts.addDuration(doneResult.totalTime); this.#alerts.addDuration(doneResult.totalTime);
this.#banner.showOptionsMenu(this.#config); this.#banner.showOptionsMenu(this.#config);
@@ -175,6 +178,25 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
} }
} }
class ProgressView {
constructor() {
this.rootEl = createDom('progress', { value: 0 });
}
start(totalSpecsDefined) {
this.rootEl.max = totalSpecsDefined;
}
specDone(result) {
this.rootEl.value = this.rootEl.value + 1;
if (result.status === 'failed') {
// TODO: also a non-color indicator
this.rootEl.classList.add('failed');
}
}
}
class UrlBuilder { class UrlBuilder {
#queryString; #queryString;
#getSuiteById; #getSuiteById;
+1 -2
View File
@@ -22,8 +22,7 @@ jasmineRequire.HtmlReporterV2Urls = function(j$) {
stopOnSpecFailure: this.queryString.getParam('stopOnSpecFailure'), stopOnSpecFailure: this.queryString.getParam('stopOnSpecFailure'),
stopSpecOnExpectationFailure: this.queryString.getParam( stopSpecOnExpectationFailure: this.queryString.getParam(
'stopSpecOnExpectationFailure' 'stopSpecOnExpectationFailure'
), )
hideDisabled: this.queryString.getParam('hideDisabled')
}; };
const random = this.queryString.getParam('random'); const random = this.queryString.getParam('random');
+20
View File
@@ -26,6 +26,26 @@ $space: "\0020";
$font-size: 11px; $font-size: 11px;
$large-font-size: 14px; $large-font-size: 14px;
// TODO: nope
progress {
width: 100%;
}
progress[value] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
progress[value]::-webkit-progress-value, progress[value]::-moz-progress-bar {
background: $passing-color;
.failed & {
background: $failing-color;
}
}
progress.failed[value]::-webkit-progress-value, progress.failed[value]::-moz-progress-bar {
background: $failing-color;
}
body { body {
overflow-y: scroll; overflow-y: scroll;
} }