Encapsulate suite result

This commit is contained in:
Steve Gravrock
2025-10-04 09:40:10 -07:00
parent 0738ba6462
commit 18491e9b84
8 changed files with 55 additions and 82 deletions

View File

@@ -9631,6 +9631,7 @@ getJasmineRequireObj().Runner = function(j$) {
overallStatus = 'passed'; overallStatus = 'passed';
} }
const topSuiteResult = this.#topSuite.doneEvent();
/** /**
* Information passed to the {@link Reporter#jasmineDone} event. * Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo * @typedef JasmineDoneInfo
@@ -9650,8 +9651,8 @@ getJasmineRequireObj().Runner = function(j$) {
incompleteReason: incompleteReason, incompleteReason: incompleteReason,
incompleteCode: incompleteCode, incompleteCode: incompleteCode,
order: orderForReporting(order), order: orderForReporting(order),
failedExpectations: this.#topSuite.result.failedExpectations, failedExpectations: topSuiteResult.failedExpectations,
deprecationWarnings: this.#topSuite.result.deprecationWarnings deprecationWarnings: topSuiteResult.deprecationWarnings
}; };
this.#topSuite.reportedDone = true; this.#topSuite.reportedDone = true;
await this.#reportDispatcher.jasmineDone(jasmineDoneInfo); await this.#reportDispatcher.jasmineDone(jasmineDoneInfo);
@@ -10615,6 +10616,7 @@ getJasmineRequireObj().Suite = function(j$) {
#throwOnExpectationFailure; #throwOnExpectationFailure;
#autoCleanClosures; #autoCleanClosures;
#timer; #timer;
#result;
constructor(attrs) { constructor(attrs) {
this.id = attrs.id; this.id = attrs.id;
@@ -10647,8 +10649,8 @@ getJasmineRequireObj().Suite = function(j$) {
// Throw a better one now. // Throw a better one now.
j$.private.util.assertReporterCloneable(key, 'Key'); j$.private.util.assertReporterCloneable(key, 'Key');
j$.private.util.assertReporterCloneable(value, 'Value'); j$.private.util.assertReporterCloneable(value, 'Value');
this.result.properties = this.result.properties || {}; this.#result.properties = this.#result.properties || {};
this.result.properties[key] = value; this.#result.properties[key] = value;
} }
getFullName() { getFullName() {
@@ -10698,7 +10700,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
endTimer() { endTimer() {
this.result.duration = this.#timer.elapsed(); this.#result.duration = this.#timer.elapsed();
} }
cleanupBeforeAfter() { cleanupBeforeAfter() {
@@ -10711,7 +10713,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
reset() { reset() {
this.result = { this.#result = {
id: this.id, id: this.id,
description: this.description, description: this.description,
fullName: this.getFullName(), fullName: this.getFullName(),
@@ -10779,7 +10781,7 @@ getJasmineRequireObj().Suite = function(j$) {
]; ];
for (const k of toCopy) { for (const k of toCopy) {
event[k] = this.result[k]; event[k] = this.#result[k];
} }
return event; return event;
@@ -10808,7 +10810,7 @@ getJasmineRequireObj().Suite = function(j$) {
return 'pending'; return 'pending';
} }
if (this.result.failedExpectations.length > 0) { if (this.#result.failedExpectations.length > 0) {
return 'failed'; return 'failed';
} else { } else {
return 'passed'; return 'passed';
@@ -10816,12 +10818,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
hasOwnFailedExpectations() { hasOwnFailedExpectations() {
return this.result.failedExpectations.length > 0; return this.#result.failedExpectations.length > 0;
}
getResult() {
this.result.status = this.#status();
return this.result;
} }
sharedUserContext() { sharedUserContext() {
@@ -10857,7 +10854,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(failedExpectation); this.onLateError(failedExpectation);
} else { } else {
this.result.failedExpectations.push(failedExpectation); this.#result.failedExpectations.push(failedExpectation);
} }
} }
@@ -10895,12 +10892,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(expectationResult); this.onLateError(expectationResult);
} else { } else {
this.result.failedExpectations.push(expectationResult); this.#result.failedExpectations.push(expectationResult);
// TODO: refactor so that we don't need to override cached status
if (this.result.status) {
this.result.status = 'failed';
}
} }
if (this.#throwOnExpectationFailure) { if (this.#throwOnExpectationFailure) {
@@ -10912,7 +10904,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (typeof deprecation === 'string') { if (typeof deprecation === 'string') {
deprecation = { message: deprecation }; deprecation = { message: deprecation };
} }
this.result.deprecationWarnings.push( this.#result.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation) j$.private.buildExpectationResult(deprecation)
); );
} }
@@ -11807,7 +11799,6 @@ getJasmineRequireObj().TreeRunner = function(j$) {
#suiteSegmentComplete(suite, next) { #suiteSegmentComplete(suite, next) {
suite.endTimer(); suite.endTimer();
const result = suite.doneEvent();
const isTopSuite = suite === this.#executionTree.topSuite; const isTopSuite = suite === this.#executionTree.topSuite;
if (!isTopSuite) { if (!isTopSuite) {
@@ -11823,14 +11814,14 @@ getJasmineRequireObj().TreeRunner = function(j$) {
this.#runableResources.clearForRunable(suite.id); this.#runableResources.clearForRunable(suite.id);
this.#currentRunableTracker.popSuite(); this.#currentRunableTracker.popSuite();
if (result.status === 'failed') { if (suite.doneEvent().status === 'failed') {
this.#hasFailures = true; this.#hasFailures = true;
} }
} }
const finish = isTopSuite const finish = isTopSuite
? next ? next
: () => this.#reportSuiteDone(suite, result, next); : () => this.#reportSuiteDone(suite, next);
if (suite.hadBeforeAllFailure) { if (suite.hadBeforeAllFailure) {
this.#reportChildrenOfBeforeAllFailure(suite).then(finish); this.#reportChildrenOfBeforeAllFailure(suite).then(finish);
@@ -11839,9 +11830,9 @@ getJasmineRequireObj().TreeRunner = function(j$) {
} }
} }
#reportSuiteDone(suite, result, next) { #reportSuiteDone(suite, next) {
suite.reportedDone = true; suite.reportedDone = true;
this.#reportDispatcher.suiteDone(result).then(next); this.#reportDispatcher.suiteDone(suite.doneEvent()).then(next);
} }
async #specComplete(spec) { async #specComplete(spec) {
@@ -11865,11 +11856,6 @@ getJasmineRequireObj().TreeRunner = function(j$) {
if (child instanceof j$.private.Suite) { if (child instanceof j$.private.Suite) {
await this.#reportDispatcher.suiteStarted(child.startedEvent()); await this.#reportDispatcher.suiteStarted(child.startedEvent());
await this.#reportChildrenOfBeforeAllFailure(child); await this.#reportChildrenOfBeforeAllFailure(child);
// Marking the suite passed is consistent with how suites that
// contain failed specs but no suite-level failures are reported.
child.result.status = 'passed';
await this.#reportDispatcher.suiteDone(child.doneEvent()); await this.#reportDispatcher.suiteDone(child.doneEvent());
} else { } else {
/* a spec */ /* a spec */

View File

@@ -37,11 +37,6 @@ describe('Runner', function() {
this.sharedUserContext = function() { this.sharedUserContext = function() {
return attrs.userContext || {}; return attrs.userContext || {};
}; };
// TODO remove
this.result = {
id: this.id,
failedExpectations: []
};
this.startedEvent = jasmine.createSpy('startedEvent'); this.startedEvent = jasmine.createSpy('startedEvent');
this.doneEvent = jasmine.createSpy('doneEvent'); this.doneEvent = jasmine.createSpy('doneEvent');
this.hasOwnFailedExpectations = jasmine.createSpy( this.hasOwnFailedExpectations = jasmine.createSpy(
@@ -132,6 +127,7 @@ describe('Runner', function() {
children: [spec], children: [spec],
userContext: { root: 'context' } userContext: { root: 'context' }
}); });
topSuite.doneEvent.and.returnValue({});
detectLateRejectionHandling = true; detectLateRejectionHandling = true;
const subject = makeRunner(topSuite); const subject = makeRunner(topSuite);
@@ -159,6 +155,7 @@ describe('Runner', function() {
children: [suite], children: [suite],
userContext: { for: 'topSuite' } userContext: { for: 'topSuite' }
}); });
topSuite.doneEvent.and.returnValue({});
suite.parentSuite = topSuite; suite.parentSuite = topSuite;
const subject = makeRunner(topSuite); const subject = makeRunner(topSuite);
@@ -249,9 +246,11 @@ describe('Runner', function() {
verifyAndFinishSpec(spec, queueableFns[1], true); verifyAndFinishSpec(spec, queueableFns[1], true);
parent.doneEvent.and.returnValue(parent.result); parent.doneEvent.and.returnValue('parent suite done event');
runQueue.calls.argsFor(1)[0].onComplete(); runQueue.calls.argsFor(1)[0].onComplete();
expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(parent.result); expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(
'parent suite done event'
);
await expectAsync(promise).toBePending(); await expectAsync(promise).toBePending();
}); });

View File

@@ -311,10 +311,11 @@ describe('SuiteBuilder', function() {
suiteBuilder.topSuite.handleException(new Error('nope')); suiteBuilder.topSuite.handleException(new Error('nope'));
suiteBuilder.parallelReset(); suiteBuilder.parallelReset();
expect(suiteBuilder.topSuite.result).toEqual({ expect(suiteBuilder.topSuite.doneEvent()).toEqual({
id: suiteBuilder.topSuite.id, id: suiteBuilder.topSuite.id,
description: 'Jasmine__TopLevel__Suite', description: 'Jasmine__TopLevel__Suite',
fullName: '', fullName: '',
status: 'passed',
failedExpectations: [], failedExpectations: [],
deprecationWarnings: [], deprecationWarnings: [],
duration: null, duration: null,

View File

@@ -115,20 +115,20 @@ describe('Suite', function() {
const suite = new privateUnderTest.Suite({}); const suite = new privateUnderTest.Suite({});
suite.addExpectationResult(false, {}); suite.addExpectationResult(false, {});
expect(suite.getResult().status).toBe('failed'); expect(suite.doneEvent().status).toBe('failed');
}); });
it('retrieves a result with updated status', function() { it('retrieves a result with updated status', function() {
const suite = new privateUnderTest.Suite({}); const suite = new privateUnderTest.Suite({});
expect(suite.getResult().status).toBe('passed'); expect(suite.doneEvent().status).toBe('passed');
}); });
it('retrieves a result with pending status', function() { it('retrieves a result with pending status', function() {
const suite = new privateUnderTest.Suite({}); const suite = new privateUnderTest.Suite({});
suite.pend(); suite.pend();
expect(suite.getResult().status).toBe('pending'); expect(suite.doneEvent().status).toBe('pending');
}); });
it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() { it('throws an ExpectationFailed when receiving a failed expectation when throwOnExpectationFailure is set', function() {
@@ -140,8 +140,8 @@ describe('Suite', function() {
suite.addExpectationResult(false, { message: 'failed' }); suite.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed); }).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed);
expect(suite.getResult().status).toBe('failed'); expect(suite.doneEvent().status).toBe('failed');
expect(suite.result.failedExpectations).toEqual([ expect(suite.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' }) jasmine.objectContaining({ message: 'failed' })
]); ]);
}); });
@@ -153,7 +153,7 @@ describe('Suite', function() {
new jasmineUnderTest.private.errors.ExpectationFailed() new jasmineUnderTest.private.errors.ExpectationFailed()
); );
expect(suite.getResult().failedExpectations).toEqual([]); expect(suite.doneEvent().failedExpectations).toEqual([]);
}); });
it('forwards late expectation failures to onLateError', function() { it('forwards late expectation failures to onLateError', function() {
@@ -175,7 +175,7 @@ describe('Suite', function() {
message: jasmine.stringMatching(/^Error: nope/) message: jasmine.stringMatching(/^Error: nope/)
}) })
); );
expect(suite.result.failedExpectations).toEqual([]); expect(suite.doneEvent().failedExpectations).toEqual([]);
}); });
it('does not forward non-late expectation failures to onLateError', function() { it('does not forward non-late expectation failures to onLateError', function() {
@@ -194,7 +194,7 @@ describe('Suite', function() {
suite.addExpectationResult(false, data, true); suite.addExpectationResult(false, data, true);
expect(onLateError).not.toHaveBeenCalled(); expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1); expect(suite.doneEvent().failedExpectations.length).toEqual(1);
}); });
it('forwards late handleException calls to onLateError', function() { it('forwards late handleException calls to onLateError', function() {
@@ -212,7 +212,7 @@ describe('Suite', function() {
message: jasmine.stringMatching(/^Error: oops/) message: jasmine.stringMatching(/^Error: oops/)
}) })
); );
expect(suite.result.failedExpectations).toEqual([]); expect(suite.doneEvent().failedExpectations).toEqual([]);
}); });
it('does not forward non-late handleException calls to onLateError', function() { it('does not forward non-late handleException calls to onLateError', function() {
@@ -225,7 +225,7 @@ describe('Suite', function() {
suite.handleException(error); suite.handleException(error);
expect(onLateError).not.toHaveBeenCalled(); expect(onLateError).not.toHaveBeenCalled();
expect(suite.result.failedExpectations.length).toEqual(1); expect(suite.doneEvent().failedExpectations.length).toEqual(1);
}); });
it('clears the reportedDone flag when reset', function() { it('clears the reportedDone flag when reset', function() {
@@ -248,7 +248,7 @@ describe('Suite', function() {
}); });
suite.startTimer(); suite.startTimer();
suite.endTimer(); suite.endTimer();
expect(suite.getResult().duration).toEqual(77000); expect(suite.doneEvent().duration).toEqual(77000);
}); });
describe('#sharedUserContext', function() { describe('#sharedUserContext', function() {
@@ -306,14 +306,14 @@ describe('Suite', function() {
const suite = new privateUnderTest.Suite({}); const suite = new privateUnderTest.Suite({});
suite.pend(); suite.pend();
suite.reset(); suite.reset();
expect(suite.getResult().status).toBe('passed'); expect(suite.doneEvent().status).toBe('passed');
}); });
it('should not reset the "pending" status when the suite was excluded', function() { it('should not reset the "pending" status when the suite was excluded', function() {
const suite = new privateUnderTest.Suite({}); const suite = new privateUnderTest.Suite({});
suite.exclude(); suite.exclude();
suite.reset(); suite.reset();
expect(suite.getResult().status).toBe('pending'); expect(suite.doneEvent().status).toBe('pending');
}); });
it('should also reset the children', function() { it('should also reset the children', function() {
@@ -335,7 +335,7 @@ describe('Suite', function() {
suite.reset(); suite.reset();
const result = suite.getResult(); const result = suite.doneEvent();
expect(result.status).toBe('passed'); expect(result.status).toBe('passed');
expect(result.failedExpectations).toHaveSize(0); expect(result.failedExpectations).toHaveSize(0);
}); });

View File

@@ -218,7 +218,7 @@ describe('TreeRunner', function() {
timer.elapsed.and.returnValue('the duration'); timer.elapsed.and.returnValue('the duration');
suiteRunQueueOpts.onComplete(); suiteRunQueueOpts.onComplete();
expect(timer.elapsed).toHaveBeenCalled(); expect(timer.elapsed).toHaveBeenCalled();
const result = suite.getResult(); const result = suite.doneEvent();
expect(result.duration).toEqual('the duration'); expect(result.duration).toEqual('the duration');
expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(result); expect(reportDispatcher.suiteDone).toHaveBeenCalledWith(result);

View File

@@ -137,6 +137,7 @@ getJasmineRequireObj().Runner = function(j$) {
overallStatus = 'passed'; overallStatus = 'passed';
} }
const topSuiteResult = this.#topSuite.doneEvent();
/** /**
* Information passed to the {@link Reporter#jasmineDone} event. * Information passed to the {@link Reporter#jasmineDone} event.
* @typedef JasmineDoneInfo * @typedef JasmineDoneInfo
@@ -156,8 +157,8 @@ getJasmineRequireObj().Runner = function(j$) {
incompleteReason: incompleteReason, incompleteReason: incompleteReason,
incompleteCode: incompleteCode, incompleteCode: incompleteCode,
order: orderForReporting(order), order: orderForReporting(order),
failedExpectations: this.#topSuite.result.failedExpectations, failedExpectations: topSuiteResult.failedExpectations,
deprecationWarnings: this.#topSuite.result.deprecationWarnings deprecationWarnings: topSuiteResult.deprecationWarnings
}; };
this.#topSuite.reportedDone = true; this.#topSuite.reportedDone = true;
await this.#reportDispatcher.jasmineDone(jasmineDoneInfo); await this.#reportDispatcher.jasmineDone(jasmineDoneInfo);

View File

@@ -4,6 +4,7 @@ getJasmineRequireObj().Suite = function(j$) {
#throwOnExpectationFailure; #throwOnExpectationFailure;
#autoCleanClosures; #autoCleanClosures;
#timer; #timer;
#result;
constructor(attrs) { constructor(attrs) {
this.id = attrs.id; this.id = attrs.id;
@@ -36,8 +37,8 @@ getJasmineRequireObj().Suite = function(j$) {
// Throw a better one now. // Throw a better one now.
j$.private.util.assertReporterCloneable(key, 'Key'); j$.private.util.assertReporterCloneable(key, 'Key');
j$.private.util.assertReporterCloneable(value, 'Value'); j$.private.util.assertReporterCloneable(value, 'Value');
this.result.properties = this.result.properties || {}; this.#result.properties = this.#result.properties || {};
this.result.properties[key] = value; this.#result.properties[key] = value;
} }
getFullName() { getFullName() {
@@ -87,7 +88,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
endTimer() { endTimer() {
this.result.duration = this.#timer.elapsed(); this.#result.duration = this.#timer.elapsed();
} }
cleanupBeforeAfter() { cleanupBeforeAfter() {
@@ -100,7 +101,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
reset() { reset() {
this.result = { this.#result = {
id: this.id, id: this.id,
description: this.description, description: this.description,
fullName: this.getFullName(), fullName: this.getFullName(),
@@ -168,7 +169,7 @@ getJasmineRequireObj().Suite = function(j$) {
]; ];
for (const k of toCopy) { for (const k of toCopy) {
event[k] = this.result[k]; event[k] = this.#result[k];
} }
return event; return event;
@@ -197,7 +198,7 @@ getJasmineRequireObj().Suite = function(j$) {
return 'pending'; return 'pending';
} }
if (this.result.failedExpectations.length > 0) { if (this.#result.failedExpectations.length > 0) {
return 'failed'; return 'failed';
} else { } else {
return 'passed'; return 'passed';
@@ -205,12 +206,7 @@ getJasmineRequireObj().Suite = function(j$) {
} }
hasOwnFailedExpectations() { hasOwnFailedExpectations() {
return this.result.failedExpectations.length > 0; return this.#result.failedExpectations.length > 0;
}
getResult() {
this.result.status = this.#status();
return this.result;
} }
sharedUserContext() { sharedUserContext() {
@@ -246,7 +242,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(failedExpectation); this.onLateError(failedExpectation);
} else { } else {
this.result.failedExpectations.push(failedExpectation); this.#result.failedExpectations.push(failedExpectation);
} }
} }
@@ -284,12 +280,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(expectationResult); this.onLateError(expectationResult);
} else { } else {
this.result.failedExpectations.push(expectationResult); this.#result.failedExpectations.push(expectationResult);
// TODO: refactor so that we don't need to override cached status
if (this.result.status) {
this.result.status = 'failed';
}
} }
if (this.#throwOnExpectationFailure) { if (this.#throwOnExpectationFailure) {
@@ -301,7 +292,7 @@ getJasmineRequireObj().Suite = function(j$) {
if (typeof deprecation === 'string') { if (typeof deprecation === 'string') {
deprecation = { message: deprecation }; deprecation = { message: deprecation };
} }
this.result.deprecationWarnings.push( this.#result.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation) j$.private.buildExpectationResult(deprecation)
); );
} }

View File

@@ -263,11 +263,6 @@ getJasmineRequireObj().TreeRunner = function(j$) {
if (child instanceof j$.private.Suite) { if (child instanceof j$.private.Suite) {
await this.#reportDispatcher.suiteStarted(child.startedEvent()); await this.#reportDispatcher.suiteStarted(child.startedEvent());
await this.#reportChildrenOfBeforeAllFailure(child); await this.#reportChildrenOfBeforeAllFailure(child);
// Marking the suite passed is consistent with how suites that
// contain failed specs but no suite-level failures are reported.
child.result.status = 'passed';
await this.#reportDispatcher.suiteDone(child.doneEvent()); await this.#reportDispatcher.suiteDone(child.doneEvent());
} else { } else {
/* a spec */ /* a spec */