Encapsulate spec result

This commit is contained in:
Steve Gravrock
2025-09-21 16:53:13 -07:00
parent d99bc3ab58
commit 712f9bac29
4 changed files with 87 additions and 105 deletions
+35 -44
View File
@@ -781,9 +781,7 @@ getJasmineRequireObj().Spec = function(j$) {
#throwOnExpectationFailure; #throwOnExpectationFailure;
#timer; #timer;
#metadata; #metadata;
// TODO: better naming. Don't make 'excluded' mean two things. #executionState;
#dynamicallyExcluded;
#requireExpectations;
constructor(attrs) { constructor(attrs) {
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
@@ -815,23 +813,23 @@ getJasmineRequireObj().Spec = function(j$) {
this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.#timer = attrs.timer || new j$.Timer(); this.#timer = attrs.timer || new j$.Timer();
this.reset();
if (!this.queueableFn.fn) { if (!this.queueableFn.fn) {
this.exclude(); this.exclude();
} }
this.reset();
} }
addExpectationResult(passed, data, isError) { addExpectationResult(passed, data, isError) {
const expectationResult = j$.private.buildExpectationResult(data); const expectationResult = j$.private.buildExpectationResult(data);
if (passed) { if (passed) {
this.result.passedExpectations.push(expectationResult); this.#executionState.passedExpectations.push(expectationResult);
} else { } else {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(expectationResult); this.onLateError(expectationResult);
} else { } else {
this.result.failedExpectations.push(expectationResult); this.#executionState.failedExpectations.push(expectationResult);
} }
if (this.#throwOnExpectationFailure && !isError) { if (this.#throwOnExpectationFailure && !isError) {
@@ -841,8 +839,8 @@ getJasmineRequireObj().Spec = function(j$) {
} }
getSpecProperty(key) { getSpecProperty(key) {
this.result.properties = this.result.properties || {}; this.#executionState.properties = this.#executionState.properties || {};
return this.result.properties[key]; return this.#executionState.properties[key];
} }
setSpecProperty(key, value) { setSpecProperty(key, value) {
@@ -851,8 +849,8 @@ getJasmineRequireObj().Spec = 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.#executionState.properties = this.#executionState.properties || {};
this.result.properties[key] = value; this.#executionState.properties[key] = value;
} }
executionStarted() { executionStarted() {
@@ -860,17 +858,17 @@ getJasmineRequireObj().Spec = function(j$) {
} }
executionFinished(excluded, failSpecWithNoExp) { executionFinished(excluded, failSpecWithNoExp) {
this.#dynamicallyExcluded = excluded; this.#executionState.dynamicallyExcluded = excluded;
this.#requireExpectations = failSpecWithNoExp; this.#executionState.requireExpectations = failSpecWithNoExp;
if (this.#autoCleanClosures) { if (this.#autoCleanClosures) {
this.queueableFn.fn = null; this.queueableFn.fn = null;
} }
this.result.duration = this.#timer.elapsed(); this.#executionState.duration = this.#timer.elapsed();
if (this.status() !== 'failed') { if (this.status() !== 'failed') {
this.result.debugLogs = null; this.#executionState.debugLogs = null;
} }
} }
@@ -889,24 +887,20 @@ getJasmineRequireObj().Spec = function(j$) {
} }
reset() { reset() {
this.result = { this.#executionState = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
parentSuiteId: this.parentSuiteId,
filename: this.filename,
failedExpectations: [], failedExpectations: [],
passedExpectations: [], passedExpectations: [],
deprecationWarnings: [], deprecationWarnings: [],
pendingReason: this.excludeMessage || '', pendingReason: this.excludeMessage || '',
duration: null, duration: null,
properties: null, properties: null,
debugLogs: null debugLogs: null,
// TODO: better naming. Don't make 'excluded' mean two things.
dynamicallyExcluded: false,
requireExpectations: false,
markedPending: this.markedExcluding
}; };
this.markedPending = this.markedExcluding;
this.reportedDone = false; this.reportedDone = false;
this.#dynamicallyExcluded = false;
this.#requireExpectations = false;
} }
startedEvent() { startedEvent() {
@@ -965,7 +959,7 @@ getJasmineRequireObj().Spec = function(j$) {
]; ];
for (const k of toCopy) { for (const k of toCopy) {
event[k] = this.result[k]; event[k] = this.#executionState[k];
} }
return event; return event;
@@ -1003,12 +997,16 @@ getJasmineRequireObj().Spec = function(j$) {
} }
pend(message) { pend(message) {
this.markedPending = true; this.#executionState.markedPending = true;
if (message) { if (message) {
this.result.pendingReason = message; this.#executionState.pendingReason = message;
} }
} }
get markedPending() {
return this.#executionState.markedPending;
}
// Like pend(), but pending state will survive reset(). // Like pend(), but pending state will survive reset().
// Useful for fit, xit, where pending state remains. // Useful for fit, xit, where pending state remains.
exclude(message) { exclude(message) {
@@ -1019,15 +1017,8 @@ getJasmineRequireObj().Spec = function(j$) {
this.pend(message); this.pend(message);
} }
// TODO: ensure that all access to result goes through .getResult()
// so that the status is correct.
// Step 1: fix things so getResult() always returns correct status
getResult() {
return this.result;
}
status() { status() {
if (this.#dynamicallyExcluded) { if (this.#executionState.dynamicallyExcluded) {
return 'excluded'; return 'excluded';
} }
@@ -1036,10 +1027,10 @@ getJasmineRequireObj().Spec = function(j$) {
} }
if ( if (
this.result.failedExpectations.length > 0 || this.#executionState.failedExpectations.length > 0 ||
(this.#requireExpectations && (this.#executionState.requireExpectations &&
this.result.failedExpectations.length + this.#executionState.failedExpectations.length +
this.result.passedExpectations.length === this.#executionState.passedExpectations.length ===
0) 0)
) { ) {
return 'failed'; return 'failed';
@@ -1056,14 +1047,14 @@ getJasmineRequireObj().Spec = function(j$) {
if (typeof deprecation === 'string') { if (typeof deprecation === 'string') {
deprecation = { message: deprecation }; deprecation = { message: deprecation };
} }
this.result.deprecationWarnings.push( this.#executionState.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation) j$.private.buildExpectationResult(deprecation)
); );
} }
debugLog(msg) { debugLog(msg) {
if (!this.result.debugLogs) { if (!this.#executionState.debugLogs) {
this.result.debugLogs = []; this.#executionState.debugLogs = [];
} }
/** /**
@@ -1072,7 +1063,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {number} timestamp - The time when the entry was added, in * @property {number} timestamp - The time when the entry was added, in
* milliseconds from the spec's start time * milliseconds from the spec's start time
*/ */
this.result.debugLogs.push({ this.#executionState.debugLogs.push({
message: msg, message: msg,
timestamp: this.#timer.elapsed() timestamp: this.#timer.elapsed()
}); });
+16 -16
View File
@@ -85,7 +85,7 @@ describe('Spec', function() {
spec.setSpecProperty('a', 4); spec.setSpecProperty('a', 4);
expect(spec.result.properties).toEqual({ a: 4 }); expect(spec.doneEvent().properties).toEqual({ a: 4 });
}); });
it('replace the property result when it was previously set', function() { it('replace the property result when it was previously set', function() {
@@ -97,7 +97,7 @@ describe('Spec', function() {
spec.setSpecProperty('b', 'original-value'); spec.setSpecProperty('b', 'original-value');
spec.setSpecProperty('a', 'new-value'); spec.setSpecProperty('a', 'new-value');
expect(spec.result.properties).toEqual({ expect(spec.doneEvent().properties).toEqual({
a: 'new-value', a: 'new-value',
b: 'original-value' b: 'original-value'
}); });
@@ -272,10 +272,10 @@ describe('Spec', function() {
spec.addExpectationResult(true, { message: 'expectation1' }); spec.addExpectationResult(true, { message: 'expectation1' });
spec.addExpectationResult(false, { message: 'expectation2' }); spec.addExpectationResult(false, { message: 'expectation2' });
expect(spec.result.passedExpectations).toEqual([ expect(spec.doneEvent().passedExpectations).toEqual([
jasmine.objectContaining({ message: 'expectation1' }) jasmine.objectContaining({ message: 'expectation1' })
]); ]);
expect(spec.result.failedExpectations).toEqual([ expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'expectation2' }) jasmine.objectContaining({ message: 'expectation2' })
]); ]);
}); });
@@ -292,7 +292,7 @@ describe('Spec', function() {
spec.addExpectationResult(false, { message: 'failed' }); spec.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed); }).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed);
expect(spec.result.failedExpectations).toEqual([ expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' }) jasmine.objectContaining({ message: 'failed' })
]); ]);
}); });
@@ -306,7 +306,7 @@ describe('Spec', function() {
spec.addExpectationResult(false, { message: 'failed' }); spec.addExpectationResult(false, { message: 'failed' });
expect(spec.result.failedExpectations).toEqual([ expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' }) jasmine.objectContaining({ message: 'failed' })
]); ]);
}); });
@@ -335,7 +335,7 @@ describe('Spec', function() {
message: jasmine.stringMatching(/^Error: nope/) message: jasmine.stringMatching(/^Error: nope/)
}) })
); );
expect(spec.result.failedExpectations).toEqual([]); expect(spec.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() {
@@ -372,7 +372,7 @@ describe('Spec', function() {
message: jasmine.stringMatching(/^Error: oops/) message: jasmine.stringMatching(/^Error: oops/)
}) })
); );
expect(spec.result.failedExpectations).toEqual([]); expect(spec.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() {
@@ -386,7 +386,7 @@ describe('Spec', function() {
spec.handleException(error); spec.handleException(error);
expect(onLateError).not.toHaveBeenCalled(); expect(onLateError).not.toHaveBeenCalled();
expect(spec.result.failedExpectations.length).toEqual(1); expect(spec.doneEvent().failedExpectations.length).toEqual(1);
}); });
it('clears the reportedDone flag when reset', function() { it('clears the reportedDone flag when reset', function() {
@@ -449,7 +449,7 @@ describe('Spec', function() {
spec.handleException('foo'); spec.handleException('foo');
expect(spec.result.failedExpectations).toEqual([ expect(spec.doneEvent().failedExpectations).toEqual([
{ {
message: 'foo thrown', message: 'foo thrown',
matcherName: '', matcherName: '',
@@ -469,7 +469,7 @@ describe('Spec', function() {
new jasmineUnderTest.private.errors.ExpectationFailed() new jasmineUnderTest.private.errors.ExpectationFailed()
); );
expect(spec.result.failedExpectations).toEqual([]); expect(spec.doneEvent().failedExpectations).toEqual([]);
}); });
}); });
@@ -483,15 +483,15 @@ describe('Spec', function() {
const t1 = 123; const t1 = 123;
const t2 = 456; const t2 = 456;
expect(spec.result.debugLogs).toBeNull(); expect(spec.doneEvent().debugLogs).toBeNull();
timer.elapsed.and.returnValue(t1); timer.elapsed.and.returnValue(t1);
spec.debugLog('msg 1'); spec.debugLog('msg 1');
expect(spec.result.debugLogs).toEqual([ expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 } { message: 'msg 1', timestamp: t1 }
]); ]);
timer.elapsed.and.returnValue(t2); timer.elapsed.and.returnValue(t2);
spec.debugLog('msg 2'); spec.debugLog('msg 2');
expect(spec.result.debugLogs).toEqual([ expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 }, { message: 'msg 1', timestamp: t1 },
{ message: 'msg 2', timestamp: t2 } { message: 'msg 2', timestamp: t2 }
]); ]);
@@ -506,7 +506,7 @@ describe('Spec', function() {
spec.debugLog('msg'); spec.debugLog('msg');
spec.executionFinished(); spec.executionFinished();
expect(spec.result.debugLogs).toBeNull(); expect(spec.doneEvent().debugLogs).toBeNull();
}); });
}); });
@@ -525,7 +525,7 @@ describe('Spec', function() {
spec.handleException(new Error('nope')); spec.handleException(new Error('nope'));
spec.executionFinished(); spec.executionFinished();
expect(spec.result.debugLogs).toEqual([ expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg', timestamp: timestamp } { message: 'msg', timestamp: timestamp }
]); ]);
}); });
+1 -1
View File
@@ -64,7 +64,7 @@ describe('TreeRunner', function() {
expect(currentRunableTracker.currentSpec()).toBeFalsy(); expect(currentRunableTracker.currentSpec()).toBeFalsy();
expect(runableResources.clearForRunable).toHaveBeenCalledWith(spec.id); expect(runableResources.clearForRunable).toHaveBeenCalledWith(spec.id);
expect(reportDispatcher.specDone).toHaveBeenCalledWith(spec.doneEvent()); expect(reportDispatcher.specDone).toHaveBeenCalledWith(spec.doneEvent());
expect(spec.result.duration).toEqual('the elapsed time'); expect(spec.doneEvent().duration).toEqual('the elapsed time');
expect(spec.reportedDone).toEqual(true); expect(spec.reportedDone).toEqual(true);
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
+35 -44
View File
@@ -4,9 +4,7 @@ getJasmineRequireObj().Spec = function(j$) {
#throwOnExpectationFailure; #throwOnExpectationFailure;
#timer; #timer;
#metadata; #metadata;
// TODO: better naming. Don't make 'excluded' mean two things. #executionState;
#dynamicallyExcluded;
#requireExpectations;
constructor(attrs) { constructor(attrs) {
this.expectationFactory = attrs.expectationFactory; this.expectationFactory = attrs.expectationFactory;
@@ -38,23 +36,23 @@ getJasmineRequireObj().Spec = function(j$) {
this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.#timer = attrs.timer || new j$.Timer(); this.#timer = attrs.timer || new j$.Timer();
this.reset();
if (!this.queueableFn.fn) { if (!this.queueableFn.fn) {
this.exclude(); this.exclude();
} }
this.reset();
} }
addExpectationResult(passed, data, isError) { addExpectationResult(passed, data, isError) {
const expectationResult = j$.private.buildExpectationResult(data); const expectationResult = j$.private.buildExpectationResult(data);
if (passed) { if (passed) {
this.result.passedExpectations.push(expectationResult); this.#executionState.passedExpectations.push(expectationResult);
} else { } else {
if (this.reportedDone) { if (this.reportedDone) {
this.onLateError(expectationResult); this.onLateError(expectationResult);
} else { } else {
this.result.failedExpectations.push(expectationResult); this.#executionState.failedExpectations.push(expectationResult);
} }
if (this.#throwOnExpectationFailure && !isError) { if (this.#throwOnExpectationFailure && !isError) {
@@ -64,8 +62,8 @@ getJasmineRequireObj().Spec = function(j$) {
} }
getSpecProperty(key) { getSpecProperty(key) {
this.result.properties = this.result.properties || {}; this.#executionState.properties = this.#executionState.properties || {};
return this.result.properties[key]; return this.#executionState.properties[key];
} }
setSpecProperty(key, value) { setSpecProperty(key, value) {
@@ -74,8 +72,8 @@ getJasmineRequireObj().Spec = 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.#executionState.properties = this.#executionState.properties || {};
this.result.properties[key] = value; this.#executionState.properties[key] = value;
} }
executionStarted() { executionStarted() {
@@ -83,17 +81,17 @@ getJasmineRequireObj().Spec = function(j$) {
} }
executionFinished(excluded, failSpecWithNoExp) { executionFinished(excluded, failSpecWithNoExp) {
this.#dynamicallyExcluded = excluded; this.#executionState.dynamicallyExcluded = excluded;
this.#requireExpectations = failSpecWithNoExp; this.#executionState.requireExpectations = failSpecWithNoExp;
if (this.#autoCleanClosures) { if (this.#autoCleanClosures) {
this.queueableFn.fn = null; this.queueableFn.fn = null;
} }
this.result.duration = this.#timer.elapsed(); this.#executionState.duration = this.#timer.elapsed();
if (this.status() !== 'failed') { if (this.status() !== 'failed') {
this.result.debugLogs = null; this.#executionState.debugLogs = null;
} }
} }
@@ -112,24 +110,20 @@ getJasmineRequireObj().Spec = function(j$) {
} }
reset() { reset() {
this.result = { this.#executionState = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
parentSuiteId: this.parentSuiteId,
filename: this.filename,
failedExpectations: [], failedExpectations: [],
passedExpectations: [], passedExpectations: [],
deprecationWarnings: [], deprecationWarnings: [],
pendingReason: this.excludeMessage || '', pendingReason: this.excludeMessage || '',
duration: null, duration: null,
properties: null, properties: null,
debugLogs: null debugLogs: null,
// TODO: better naming. Don't make 'excluded' mean two things.
dynamicallyExcluded: false,
requireExpectations: false,
markedPending: this.markedExcluding
}; };
this.markedPending = this.markedExcluding;
this.reportedDone = false; this.reportedDone = false;
this.#dynamicallyExcluded = false;
this.#requireExpectations = false;
} }
startedEvent() { startedEvent() {
@@ -188,7 +182,7 @@ getJasmineRequireObj().Spec = function(j$) {
]; ];
for (const k of toCopy) { for (const k of toCopy) {
event[k] = this.result[k]; event[k] = this.#executionState[k];
} }
return event; return event;
@@ -226,12 +220,16 @@ getJasmineRequireObj().Spec = function(j$) {
} }
pend(message) { pend(message) {
this.markedPending = true; this.#executionState.markedPending = true;
if (message) { if (message) {
this.result.pendingReason = message; this.#executionState.pendingReason = message;
} }
} }
get markedPending() {
return this.#executionState.markedPending;
}
// Like pend(), but pending state will survive reset(). // Like pend(), but pending state will survive reset().
// Useful for fit, xit, where pending state remains. // Useful for fit, xit, where pending state remains.
exclude(message) { exclude(message) {
@@ -242,15 +240,8 @@ getJasmineRequireObj().Spec = function(j$) {
this.pend(message); this.pend(message);
} }
// TODO: ensure that all access to result goes through .getResult()
// so that the status is correct.
// Step 1: fix things so getResult() always returns correct status
getResult() {
return this.result;
}
status() { status() {
if (this.#dynamicallyExcluded) { if (this.#executionState.dynamicallyExcluded) {
return 'excluded'; return 'excluded';
} }
@@ -259,10 +250,10 @@ getJasmineRequireObj().Spec = function(j$) {
} }
if ( if (
this.result.failedExpectations.length > 0 || this.#executionState.failedExpectations.length > 0 ||
(this.#requireExpectations && (this.#executionState.requireExpectations &&
this.result.failedExpectations.length + this.#executionState.failedExpectations.length +
this.result.passedExpectations.length === this.#executionState.passedExpectations.length ===
0) 0)
) { ) {
return 'failed'; return 'failed';
@@ -279,14 +270,14 @@ getJasmineRequireObj().Spec = function(j$) {
if (typeof deprecation === 'string') { if (typeof deprecation === 'string') {
deprecation = { message: deprecation }; deprecation = { message: deprecation };
} }
this.result.deprecationWarnings.push( this.#executionState.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation) j$.private.buildExpectationResult(deprecation)
); );
} }
debugLog(msg) { debugLog(msg) {
if (!this.result.debugLogs) { if (!this.#executionState.debugLogs) {
this.result.debugLogs = []; this.#executionState.debugLogs = [];
} }
/** /**
@@ -295,7 +286,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {number} timestamp - The time when the entry was added, in * @property {number} timestamp - The time when the entry was added, in
* milliseconds from the spec's start time * milliseconds from the spec's start time
*/ */
this.result.debugLogs.push({ this.#executionState.debugLogs.push({
message: msg, message: msg,
timestamp: this.#timer.elapsed() timestamp: this.#timer.elapsed()
}); });