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

View File

@@ -781,9 +781,7 @@ getJasmineRequireObj().Spec = function(j$) {
#throwOnExpectationFailure;
#timer;
#metadata;
// TODO: better naming. Don't make 'excluded' mean two things.
#dynamicallyExcluded;
#requireExpectations;
#executionState;
constructor(attrs) {
this.expectationFactory = attrs.expectationFactory;
@@ -815,23 +813,23 @@ getJasmineRequireObj().Spec = function(j$) {
this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.#timer = attrs.timer || new j$.Timer();
this.reset();
if (!this.queueableFn.fn) {
this.exclude();
}
this.reset();
}
addExpectationResult(passed, data, isError) {
const expectationResult = j$.private.buildExpectationResult(data);
if (passed) {
this.result.passedExpectations.push(expectationResult);
this.#executionState.passedExpectations.push(expectationResult);
} else {
if (this.reportedDone) {
this.onLateError(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
this.#executionState.failedExpectations.push(expectationResult);
}
if (this.#throwOnExpectationFailure && !isError) {
@@ -841,8 +839,8 @@ getJasmineRequireObj().Spec = function(j$) {
}
getSpecProperty(key) {
this.result.properties = this.result.properties || {};
return this.result.properties[key];
this.#executionState.properties = this.#executionState.properties || {};
return this.#executionState.properties[key];
}
setSpecProperty(key, value) {
@@ -851,8 +849,8 @@ getJasmineRequireObj().Spec = function(j$) {
// Throw a better one now.
j$.private.util.assertReporterCloneable(key, 'Key');
j$.private.util.assertReporterCloneable(value, 'Value');
this.result.properties = this.result.properties || {};
this.result.properties[key] = value;
this.#executionState.properties = this.#executionState.properties || {};
this.#executionState.properties[key] = value;
}
executionStarted() {
@@ -860,17 +858,17 @@ getJasmineRequireObj().Spec = function(j$) {
}
executionFinished(excluded, failSpecWithNoExp) {
this.#dynamicallyExcluded = excluded;
this.#requireExpectations = failSpecWithNoExp;
this.#executionState.dynamicallyExcluded = excluded;
this.#executionState.requireExpectations = failSpecWithNoExp;
if (this.#autoCleanClosures) {
this.queueableFn.fn = null;
}
this.result.duration = this.#timer.elapsed();
this.#executionState.duration = this.#timer.elapsed();
if (this.status() !== 'failed') {
this.result.debugLogs = null;
this.#executionState.debugLogs = null;
}
}
@@ -889,24 +887,20 @@ getJasmineRequireObj().Spec = function(j$) {
}
reset() {
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
parentSuiteId: this.parentSuiteId,
filename: this.filename,
this.#executionState = {
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: this.excludeMessage || '',
duration: 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.#dynamicallyExcluded = false;
this.#requireExpectations = false;
}
startedEvent() {
@@ -965,7 +959,7 @@ getJasmineRequireObj().Spec = function(j$) {
];
for (const k of toCopy) {
event[k] = this.result[k];
event[k] = this.#executionState[k];
}
return event;
@@ -1003,12 +997,16 @@ getJasmineRequireObj().Spec = function(j$) {
}
pend(message) {
this.markedPending = true;
this.#executionState.markedPending = true;
if (message) {
this.result.pendingReason = message;
this.#executionState.pendingReason = message;
}
}
get markedPending() {
return this.#executionState.markedPending;
}
// Like pend(), but pending state will survive reset().
// Useful for fit, xit, where pending state remains.
exclude(message) {
@@ -1019,15 +1017,8 @@ getJasmineRequireObj().Spec = function(j$) {
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() {
if (this.#dynamicallyExcluded) {
if (this.#executionState.dynamicallyExcluded) {
return 'excluded';
}
@@ -1036,10 +1027,10 @@ getJasmineRequireObj().Spec = function(j$) {
}
if (
this.result.failedExpectations.length > 0 ||
(this.#requireExpectations &&
this.result.failedExpectations.length +
this.result.passedExpectations.length ===
this.#executionState.failedExpectations.length > 0 ||
(this.#executionState.requireExpectations &&
this.#executionState.failedExpectations.length +
this.#executionState.passedExpectations.length ===
0)
) {
return 'failed';
@@ -1056,14 +1047,14 @@ getJasmineRequireObj().Spec = function(j$) {
if (typeof deprecation === 'string') {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(
this.#executionState.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation)
);
}
debugLog(msg) {
if (!this.result.debugLogs) {
this.result.debugLogs = [];
if (!this.#executionState.debugLogs) {
this.#executionState.debugLogs = [];
}
/**
@@ -1072,7 +1063,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {number} timestamp - The time when the entry was added, in
* milliseconds from the spec's start time
*/
this.result.debugLogs.push({
this.#executionState.debugLogs.push({
message: msg,
timestamp: this.#timer.elapsed()
});

View File

@@ -85,7 +85,7 @@ describe('Spec', function() {
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() {
@@ -97,7 +97,7 @@ describe('Spec', function() {
spec.setSpecProperty('b', 'original-value');
spec.setSpecProperty('a', 'new-value');
expect(spec.result.properties).toEqual({
expect(spec.doneEvent().properties).toEqual({
a: 'new-value',
b: 'original-value'
});
@@ -272,10 +272,10 @@ describe('Spec', function() {
spec.addExpectationResult(true, { message: 'expectation1' });
spec.addExpectationResult(false, { message: 'expectation2' });
expect(spec.result.passedExpectations).toEqual([
expect(spec.doneEvent().passedExpectations).toEqual([
jasmine.objectContaining({ message: 'expectation1' })
]);
expect(spec.result.failedExpectations).toEqual([
expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'expectation2' })
]);
});
@@ -292,7 +292,7 @@ describe('Spec', function() {
spec.addExpectationResult(false, { message: 'failed' });
}).toThrowError(jasmineUnderTest.private.errors.ExpectationFailed);
expect(spec.result.failedExpectations).toEqual([
expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' })
]);
});
@@ -306,7 +306,7 @@ describe('Spec', function() {
spec.addExpectationResult(false, { message: 'failed' });
expect(spec.result.failedExpectations).toEqual([
expect(spec.doneEvent().failedExpectations).toEqual([
jasmine.objectContaining({ message: 'failed' })
]);
});
@@ -335,7 +335,7 @@ describe('Spec', function() {
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() {
@@ -372,7 +372,7 @@ describe('Spec', function() {
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() {
@@ -386,7 +386,7 @@ describe('Spec', function() {
spec.handleException(error);
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() {
@@ -449,7 +449,7 @@ describe('Spec', function() {
spec.handleException('foo');
expect(spec.result.failedExpectations).toEqual([
expect(spec.doneEvent().failedExpectations).toEqual([
{
message: 'foo thrown',
matcherName: '',
@@ -469,7 +469,7 @@ describe('Spec', function() {
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 t2 = 456;
expect(spec.result.debugLogs).toBeNull();
expect(spec.doneEvent().debugLogs).toBeNull();
timer.elapsed.and.returnValue(t1);
spec.debugLog('msg 1');
expect(spec.result.debugLogs).toEqual([
expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 }
]);
timer.elapsed.and.returnValue(t2);
spec.debugLog('msg 2');
expect(spec.result.debugLogs).toEqual([
expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg 1', timestamp: t1 },
{ message: 'msg 2', timestamp: t2 }
]);
@@ -506,7 +506,7 @@ describe('Spec', function() {
spec.debugLog('msg');
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.executionFinished();
expect(spec.result.debugLogs).toEqual([
expect(spec.doneEvent().debugLogs).toEqual([
{ message: 'msg', timestamp: timestamp }
]);
});

View File

@@ -64,7 +64,7 @@ describe('TreeRunner', function() {
expect(currentRunableTracker.currentSpec()).toBeFalsy();
expect(runableResources.clearForRunable).toHaveBeenCalledWith(spec.id);
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);
await Promise.resolve();
await Promise.resolve();

View File

@@ -4,9 +4,7 @@ getJasmineRequireObj().Spec = function(j$) {
#throwOnExpectationFailure;
#timer;
#metadata;
// TODO: better naming. Don't make 'excluded' mean two things.
#dynamicallyExcluded;
#requireExpectations;
#executionState;
constructor(attrs) {
this.expectationFactory = attrs.expectationFactory;
@@ -38,23 +36,23 @@ getJasmineRequireObj().Spec = function(j$) {
this.#throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.#timer = attrs.timer || new j$.Timer();
this.reset();
if (!this.queueableFn.fn) {
this.exclude();
}
this.reset();
}
addExpectationResult(passed, data, isError) {
const expectationResult = j$.private.buildExpectationResult(data);
if (passed) {
this.result.passedExpectations.push(expectationResult);
this.#executionState.passedExpectations.push(expectationResult);
} else {
if (this.reportedDone) {
this.onLateError(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
this.#executionState.failedExpectations.push(expectationResult);
}
if (this.#throwOnExpectationFailure && !isError) {
@@ -64,8 +62,8 @@ getJasmineRequireObj().Spec = function(j$) {
}
getSpecProperty(key) {
this.result.properties = this.result.properties || {};
return this.result.properties[key];
this.#executionState.properties = this.#executionState.properties || {};
return this.#executionState.properties[key];
}
setSpecProperty(key, value) {
@@ -74,8 +72,8 @@ getJasmineRequireObj().Spec = function(j$) {
// Throw a better one now.
j$.private.util.assertReporterCloneable(key, 'Key');
j$.private.util.assertReporterCloneable(value, 'Value');
this.result.properties = this.result.properties || {};
this.result.properties[key] = value;
this.#executionState.properties = this.#executionState.properties || {};
this.#executionState.properties[key] = value;
}
executionStarted() {
@@ -83,17 +81,17 @@ getJasmineRequireObj().Spec = function(j$) {
}
executionFinished(excluded, failSpecWithNoExp) {
this.#dynamicallyExcluded = excluded;
this.#requireExpectations = failSpecWithNoExp;
this.#executionState.dynamicallyExcluded = excluded;
this.#executionState.requireExpectations = failSpecWithNoExp;
if (this.#autoCleanClosures) {
this.queueableFn.fn = null;
}
this.result.duration = this.#timer.elapsed();
this.#executionState.duration = this.#timer.elapsed();
if (this.status() !== 'failed') {
this.result.debugLogs = null;
this.#executionState.debugLogs = null;
}
}
@@ -112,24 +110,20 @@ getJasmineRequireObj().Spec = function(j$) {
}
reset() {
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
parentSuiteId: this.parentSuiteId,
filename: this.filename,
this.#executionState = {
failedExpectations: [],
passedExpectations: [],
deprecationWarnings: [],
pendingReason: this.excludeMessage || '',
duration: 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.#dynamicallyExcluded = false;
this.#requireExpectations = false;
}
startedEvent() {
@@ -188,7 +182,7 @@ getJasmineRequireObj().Spec = function(j$) {
];
for (const k of toCopy) {
event[k] = this.result[k];
event[k] = this.#executionState[k];
}
return event;
@@ -226,12 +220,16 @@ getJasmineRequireObj().Spec = function(j$) {
}
pend(message) {
this.markedPending = true;
this.#executionState.markedPending = true;
if (message) {
this.result.pendingReason = message;
this.#executionState.pendingReason = message;
}
}
get markedPending() {
return this.#executionState.markedPending;
}
// Like pend(), but pending state will survive reset().
// Useful for fit, xit, where pending state remains.
exclude(message) {
@@ -242,15 +240,8 @@ getJasmineRequireObj().Spec = function(j$) {
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() {
if (this.#dynamicallyExcluded) {
if (this.#executionState.dynamicallyExcluded) {
return 'excluded';
}
@@ -259,10 +250,10 @@ getJasmineRequireObj().Spec = function(j$) {
}
if (
this.result.failedExpectations.length > 0 ||
(this.#requireExpectations &&
this.result.failedExpectations.length +
this.result.passedExpectations.length ===
this.#executionState.failedExpectations.length > 0 ||
(this.#executionState.requireExpectations &&
this.#executionState.failedExpectations.length +
this.#executionState.passedExpectations.length ===
0)
) {
return 'failed';
@@ -279,14 +270,14 @@ getJasmineRequireObj().Spec = function(j$) {
if (typeof deprecation === 'string') {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(
this.#executionState.deprecationWarnings.push(
j$.private.buildExpectationResult(deprecation)
);
}
debugLog(msg) {
if (!this.result.debugLogs) {
this.result.debugLogs = [];
if (!this.#executionState.debugLogs) {
this.#executionState.debugLogs = [];
}
/**
@@ -295,7 +286,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {number} timestamp - The time when the entry was added, in
* milliseconds from the spec's start time
*/
this.result.debugLogs.push({
this.#executionState.debugLogs.push({
message: msg,
timestamp: this.#timer.elapsed()
});