HtmlReporterV2: show correct progress when running a subset of specs

This commit is contained in:
Steve Gravrock
2025-11-26 20:51:02 -08:00
parent d7b1456584
commit b559faec2a
8 changed files with 150 additions and 33 deletions

View File

@@ -1102,7 +1102,9 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineStarted(options) { jasmineStarted(options) {
this.#stateBuilder.jasmineStarted(options); this.#stateBuilder.jasmineStarted(options);
this.#progress.start(options.totalSpecsDefined); this.#progress.start(
options.totalSpecsDefined - options.numExcludedSpecs
);
} }
suiteStarted(result) { suiteStarted(result) {
@@ -1218,7 +1220,9 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
} }
specDone(result) { specDone(result) {
this.rootEl.value = this.rootEl.value + 1; if (result.status !== 'excluded') {
this.rootEl.value = this.rootEl.value + 1;
}
if (result.status === 'failed') { if (result.status === 'failed') {
this.rootEl.classList.add('failed'); this.rootEl.classList.add('failed');

View File

@@ -9862,7 +9862,8 @@ getJasmineRequireObj().Runner = function(j$) {
/** /**
* Information passed to the {@link Reporter#jasmineStarted} event. * Information passed to the {@link Reporter#jasmineStarted} event.
* @typedef JasmineStartedInfo * @typedef JasmineStartedInfo
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite. Note that this property is not present when Jasmine is run in parallel mode. * @property {int} totalSpecsDefined - The total number of specs defined in this suite. Note that this property is not present when Jasmine is run in parallel mode.
* @property {int} numExcludedSpecs - The number of specs that will be excluded from execution. Note that this property is not present when Jasmine is run in parallel mode.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode.
* @property {Boolean} parallel - Whether Jasmine is being run in parallel mode. * @property {Boolean} parallel - Whether Jasmine is being run in parallel mode.
* @since 2.0.0 * @since 2.0.0
@@ -9871,6 +9872,7 @@ getJasmineRequireObj().Runner = function(j$) {
// In parallel mode, the jasmineStarted event is separately dispatched // In parallel mode, the jasmineStarted event is separately dispatched
// by jasmine-npm. This event only reaches reporters in non-parallel. // by jasmine-npm. This event only reaches reporters in non-parallel.
totalSpecsDefined, totalSpecsDefined,
numExcludedSpecs: this.#executionTree.numExcludedSpecs(),
order: orderForReporting(order), order: orderForReporting(order),
parallel: false parallel: false
}); });
@@ -11977,6 +11979,23 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
const nodeStats = this.#stats[node.id]; const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded; return node.children ? !nodeStats.willExecute : nodeStats.excluded;
} }
numExcludedSpecs(node) {
if (!node) {
return this.numExcludedSpecs(this.topSuite);
} else if (node.children) {
let result = 0;
for (const child of node.children) {
result += this.numExcludedSpecs(child);
}
return result;
} else {
const nodeStats = this.#stats[node.id];
return nodeStats.willExecute ? 0 : 1;
}
}
} }
function segmentChildren(node, orderedChildren, stats, executableIndex) { function segmentChildren(node, orderedChildren, stats, executableIndex) {

View File

@@ -246,4 +246,53 @@ describe('TreeProcessor', function() {
{ spec: leaf1 } { spec: leaf1 }
]); ]);
}); });
describe("The returned ExecutionTree's numExcludedSpecs method", function() {
it('counts filtered-out specs', function() {
const included = new Leaf();
const excluded1 = new Leaf();
const excluded2 = new Leaf();
const excluded3 = new Leaf();
const topSuite = new Node({
children: [
excluded1,
new Node({
children: [included, excluded2, new Node({ children: [excluded3] })]
})
]
});
const processor = new privateUnderTest.TreeProcessor({
tree: topSuite,
runnableIds: [topSuite.id],
excludeNode(node) {
return node.id !== included.id;
}
});
const executionTree = processor.processTree();
expect(executionTree.numExcludedSpecs()).toEqual(3);
});
it("counts specs that aren't in or descendants of runnableIds", function() {
const includedSuite = new Node({
children: [new Node({ children: [new Leaf()] }), new Leaf()]
});
const directlyIncludedSpec = new Leaf();
const topSuite = new Node({
children: [
includedSuite,
new Node({
children: [new Leaf(), directlyIncludedSpec]
})
]
});
const processor = new privateUnderTest.TreeProcessor({
tree: topSuite,
runnableIds: [includedSuite.id, directlyIncludedSpec.id]
});
const executionTree = processor.processTree();
expect(executionTree.numExcludedSpecs()).toEqual(1);
});
});
}); });

View File

@@ -1557,6 +1557,7 @@ describe('Env integration', function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({ expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1, totalSpecsDefined: 1,
numExcludedSpecs: 0,
order: { random: true, seed: jasmine.any(String) }, order: { random: true, seed: jasmine.any(String) },
parallel: false parallel: false
}); });
@@ -1592,6 +1593,7 @@ describe('Env integration', function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({ expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1, totalSpecsDefined: 1,
numExcludedSpecs: 0,
order: { random: true, seed: jasmine.any(String) }, order: { random: true, seed: jasmine.any(String) },
parallel: false parallel: false
}); });
@@ -1648,6 +1650,7 @@ describe('Env integration', function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({ expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 6, totalSpecsDefined: 6,
numExcludedSpecs: 3,
order: { random: false }, order: { random: false },
parallel: false parallel: false
}); });
@@ -2061,6 +2064,7 @@ describe('Env integration', function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({ expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1, totalSpecsDefined: 1,
numExcludedSpecs: 1,
order: { random: true, seed: jasmine.any(String) }, order: { random: true, seed: jasmine.any(String) },
parallel: false parallel: false
}); });

View File

@@ -144,7 +144,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.specDone({ reporter.specDone({
status: 'passed', status: 'passed',
fullName: 'a spec with a deprecation', fullName: 'a spec with a deprecation',
@@ -185,7 +185,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -221,7 +221,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -240,7 +240,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
deprecationWarnings: [ deprecationWarnings: [
{ {
@@ -273,7 +273,7 @@ describe('HtmlReporterV2', function() {
it('hides all tabs', function() { it('hides all tabs', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
const tabs = container.querySelectorAll('.jasmine-tab'); const tabs = container.querySelectorAll('.jasmine-tab');
expect(tabs.length).toEqual(3); expect(tabs.length).toEqual(3);
expect(tabs[0].textContent).toEqual('Spec List'); expect(tabs[0].textContent).toEqual('Spec List');
@@ -374,7 +374,10 @@ describe('HtmlReporterV2', function() {
describe('with spec failures', function() { describe('with spec failures', function() {
hasSpecOrSuiteFailureBehavior(function(reporter) { hasSpecOrSuiteFailureBehavior(function(reporter) {
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({
totalSpecsDefined: 0,
numExcludedSpecs: 0
});
reporter.specDone({ reporter.specDone({
id: 1, id: 1,
description: 'a failing spec', description: 'a failing spec',
@@ -397,7 +400,10 @@ describe('HtmlReporterV2', function() {
describe('with suite failures', function() { describe('with suite failures', function() {
hasSpecOrSuiteFailureBehavior(function(reporter) { hasSpecOrSuiteFailureBehavior(function(reporter) {
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({
totalSpecsDefined: 0,
numExcludedSpecs: 0
});
reporter.specDone({ reporter.specDone({
id: 1, id: 1,
description: 'a failing spec', description: 'a failing spec',
@@ -420,7 +426,10 @@ describe('HtmlReporterV2', function() {
describe('without any failures', function() { describe('without any failures', function() {
hasSpecAndSuiteSuccessBehavior(function(reporter) { hasSpecAndSuiteSuccessBehavior(function(reporter) {
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({
totalSpecsDefined: 0,
numExcludedSpecs: 0
});
reporter.specDone({ reporter.specDone({
id: 1, id: 1,
description: 'a passing spec', description: 'a passing spec',
@@ -438,7 +447,10 @@ describe('HtmlReporterV2', function() {
// Top suite failures are displayed in their own alert bars, so they // Top suite failures are displayed in their own alert bars, so they
// don't cause the failures tab to be shown. // don't cause the failures tab to be shown.
hasSpecAndSuiteSuccessBehavior(function(reporter) { hasSpecAndSuiteSuccessBehavior(function(reporter) {
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({
totalSpecsDefined: 0,
numExcludedSpecs: 0
});
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [{}] failedExpectations: [{}]
}); });
@@ -448,7 +460,7 @@ describe('HtmlReporterV2', function() {
it('shows the slow spec view when the Performance tab is clicked', function() { it('shows the slow spec view when the Performance tab is clicked', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.specDone({ reporter.specDone({
duration: 1.2, duration: 1.2,
failedExpectations: [], failedExpectations: [],
@@ -473,7 +485,7 @@ describe('HtmlReporterV2', function() {
spyOn(console, 'error'); spyOn(console, 'error');
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.suiteStarted({ id: 1 }); reporter.suiteStarted({ id: 1 });
reporter.specDone({ reporter.specDone({
id: 1, id: 1,
@@ -497,7 +509,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ totalTime: 100 }); reporter.jasmineDone({ totalTime: 100 });
@@ -515,7 +527,7 @@ describe('HtmlReporterV2', function() {
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.suiteStarted({ reporter.suiteStarted({
id: 1, id: 1,
description: 'A Suite', description: 'A Suite',
@@ -646,7 +658,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ {
@@ -675,7 +687,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ message: 'load error', globalErrorType: 'load' }, { message: 'load error', globalErrorType: 'load' },
@@ -705,7 +717,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
failedExpectations: [ failedExpectations: [
{ {
@@ -911,7 +923,7 @@ describe('HtmlReporterV2', function() {
passedExpectations: [] passedExpectations: []
}; };
reporter.jasmineStarted({ totalSpecsDefined: 3 }); reporter.jasmineStarted({ totalSpecsDefined: 3, numExcludedSpecs: 0 });
reporter.specDone({ ...minimalSpecDone }); reporter.specDone({ ...minimalSpecDone });
reporter.specDone({ ...minimalSpecDone }); reporter.specDone({ ...minimalSpecDone });
reporter.specDone({ ...minimalSpecDone, status: 'excluded' }); reporter.specDone({ ...minimalSpecDone, status: 'excluded' });
@@ -929,7 +941,7 @@ describe('HtmlReporterV2', function() {
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({ totalSpecsDefined: 1, numExcludedSpecs: 0 });
reporter.jasmineDone({ order: { random: true } }); reporter.jasmineDone({ order: { random: true } });
const skippedLink = container.querySelector('.jasmine-skipped a'); const skippedLink = container.querySelector('.jasmine-skipped a');
@@ -942,7 +954,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 2 }); reporter.jasmineStarted({ totalSpecsDefined: 2, numExcludedSpecs: 0 });
reporter.specDone({ reporter.specDone({
id: 123, id: 123,
description: 'with a spec', description: 'with a spec',
@@ -1008,7 +1020,10 @@ describe('HtmlReporterV2', function() {
} }
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({
totalSpecsDefined: 1,
numExcludedSpecs: 0
});
reporter.specDone(specStatus); reporter.specDone(specStatus);
reporter.jasmineDone({}); reporter.jasmineDone({});
}); });
@@ -1030,7 +1045,10 @@ describe('HtmlReporterV2', function() {
} }
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({
totalSpecsDefined: 1,
numExcludedSpecs: 0
});
reporter.specDone(specStatus); reporter.specDone(specStatus);
reporter.jasmineDone({}); reporter.jasmineDone({});
}); });
@@ -1066,7 +1084,7 @@ describe('HtmlReporterV2', function() {
reporter = setup(); reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({ totalSpecsDefined: 1, numExcludedSpecs: 0 });
}); });
it('reports the pending specs count', function() { it('reports the pending specs count', function() {
@@ -1119,7 +1137,7 @@ describe('HtmlReporterV2', function() {
reporter = setup(); reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({ totalSpecsDefined: 1, numExcludedSpecs: 0 });
reporter.suiteStarted({ reporter.suiteStarted({
id: 1, id: 1,
description: 'A suite' description: 'A suite'
@@ -1287,7 +1305,7 @@ describe('HtmlReporterV2', function() {
}); });
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 }); reporter.jasmineStarted({ totalSpecsDefined: 1, numExcludedSpecs: 0 });
const failingSpecResult = { const failingSpecResult = {
id: 124, id: 124,
@@ -1395,7 +1413,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'passed', overallStatus: 'passed',
failedExpectations: [] failedExpectations: []
@@ -1411,7 +1429,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'failed', overallStatus: 'failed',
failedExpectations: [] failedExpectations: []
@@ -1427,7 +1445,7 @@ describe('HtmlReporterV2', function() {
const reporter = setup(); const reporter = setup();
reporter.initialize(); reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 0 }); reporter.jasmineStarted({ totalSpecsDefined: 0, numExcludedSpecs: 0 });
reporter.jasmineDone({ reporter.jasmineDone({
overallStatus: 'incomplete', overallStatus: 'incomplete',
incompleteReason: 'because nope', incompleteReason: 'because nope',

View File

@@ -96,7 +96,8 @@ getJasmineRequireObj().Runner = function(j$) {
/** /**
* Information passed to the {@link Reporter#jasmineStarted} event. * Information passed to the {@link Reporter#jasmineStarted} event.
* @typedef JasmineStartedInfo * @typedef JasmineStartedInfo
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite. Note that this property is not present when Jasmine is run in parallel mode. * @property {int} totalSpecsDefined - The total number of specs defined in this suite. Note that this property is not present when Jasmine is run in parallel mode.
* @property {int} numExcludedSpecs - The number of specs that will be excluded from execution. Note that this property is not present when Jasmine is run in parallel mode.
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. Note that this property is not present when Jasmine is run in parallel mode.
* @property {Boolean} parallel - Whether Jasmine is being run in parallel mode. * @property {Boolean} parallel - Whether Jasmine is being run in parallel mode.
* @since 2.0.0 * @since 2.0.0
@@ -105,6 +106,7 @@ getJasmineRequireObj().Runner = function(j$) {
// In parallel mode, the jasmineStarted event is separately dispatched // In parallel mode, the jasmineStarted event is separately dispatched
// by jasmine-npm. This event only reaches reporters in non-parallel. // by jasmine-npm. This event only reaches reporters in non-parallel.
totalSpecsDefined, totalSpecsDefined,
numExcludedSpecs: this.#executionTree.numExcludedSpecs(),
order: orderForReporting(order), order: orderForReporting(order),
parallel: false parallel: false
}); });

View File

@@ -123,6 +123,23 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
const nodeStats = this.#stats[node.id]; const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded; return node.children ? !nodeStats.willExecute : nodeStats.excluded;
} }
numExcludedSpecs(node) {
if (!node) {
return this.numExcludedSpecs(this.topSuite);
} else if (node.children) {
let result = 0;
for (const child of node.children) {
result += this.numExcludedSpecs(child);
}
return result;
} else {
const nodeStats = this.#stats[node.id];
return nodeStats.willExecute ? 0 : 1;
}
}
} }
function segmentChildren(node, orderedChildren, stats, executableIndex) { function segmentChildren(node, orderedChildren, stats, executableIndex) {

View File

@@ -112,7 +112,9 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
jasmineStarted(options) { jasmineStarted(options) {
this.#stateBuilder.jasmineStarted(options); this.#stateBuilder.jasmineStarted(options);
this.#progress.start(options.totalSpecsDefined); this.#progress.start(
options.totalSpecsDefined - options.numExcludedSpecs
);
} }
suiteStarted(result) { suiteStarted(result) {
@@ -228,7 +230,9 @@ jasmineRequire.HtmlReporterV2 = function(j$) {
} }
specDone(result) { specDone(result) {
this.rootEl.value = this.rootEl.value + 1; if (result.status !== 'excluded') {
this.rootEl.value = this.rootEl.value + 1;
}
if (result.status === 'failed') { if (result.status === 'failed') {
this.rootEl.classList.add('failed'); this.rootEl.classList.add('failed');