From e1532be726e261bd0fbe3a2c3e70154e22cc99e9 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 31 Aug 2025 08:42:12 -0700 Subject: [PATCH] Convert Suite and SuiteMetadata to ES6 classes --- lib/jasmine-core/jasmine.js | 606 ++++++++++++++++++------------------ src/core/Suite.js | 606 ++++++++++++++++++------------------ 2 files changed, 606 insertions(+), 606 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2dd4c291..96cf63c9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -10475,88 +10475,274 @@ getJasmineRequireObj().StackTrace = function(j$) { }; getJasmineRequireObj().Suite = function(j$) { - function Suite(attrs) { - this.env = attrs.env; - this.id = attrs.id; - this.parentSuite = attrs.parentSuite; - this.description = attrs.description; - this.reportedParentSuiteId = attrs.reportedParentSuiteId; - this.filename = attrs.filename; - this.expectationFactory = attrs.expectationFactory; - this.asyncExpectationFactory = attrs.asyncExpectationFactory; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - this.autoCleanClosures = - attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; - this.onLateError = attrs.onLateError || function() {}; + class Suite { + constructor(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.reportedParentSuiteId = attrs.reportedParentSuiteId; + this.filename = attrs.filename; + this.expectationFactory = attrs.expectationFactory; + this.asyncExpectationFactory = attrs.asyncExpectationFactory; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.autoCleanClosures = + attrs.autoCleanClosures === undefined + ? true + : !!attrs.autoCleanClosures; + this.onLateError = attrs.onLateError || function() {}; - this.beforeFns = []; - this.afterFns = []; - this.beforeAllFns = []; - this.afterAllFns = []; - this.timer = attrs.timer || new j$.Timer(); - this.children = []; + this.beforeFns = []; + this.afterFns = []; + this.beforeAllFns = []; + this.afterAllFns = []; + this.timer = attrs.timer || new j$.Timer(); + this.children = []; - this.reset(); - } + this.reset(); + } - Suite.prototype.setSuiteProperty = function(key, value) { - this.result.properties = this.result.properties || {}; - this.result.properties[key] = value; - }; + setSuiteProperty(key, value) { + this.result.properties = this.result.properties || {}; + this.result.properties[key] = value; + } - Suite.prototype.getFullName = function() { - const fullName = []; - for ( - let parentSuite = this; - parentSuite; - parentSuite = parentSuite.parentSuite - ) { - if (parentSuite.parentSuite) { - fullName.unshift(parentSuite.description); + getFullName() { + const fullName = []; + for ( + let parentSuite = this; + parentSuite; + parentSuite = parentSuite.parentSuite + ) { + if (parentSuite.parentSuite) { + fullName.unshift(parentSuite.description); + } + } + return fullName.join(' '); + } + + // Mark the suite with "pending" status + pend() { + this.markedPending = true; + } + + // Like pend(), but pending state will survive reset(). + // Useful for fdescribe, xdescribe, where pending state should remain. + exclude() { + this.pend(); + this.markedExcluding = true; + } + + beforeEach(fn) { + this.beforeFns.unshift({ ...fn, suite: this }); + } + + beforeAll(fn) { + this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); + } + + afterEach(fn) { + this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); + } + + afterAll(fn) { + this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); + } + + startTimer() { + this.timer.start(); + } + + endTimer() { + this.result.duration = this.timer.elapsed(); + } + + cleanupBeforeAfter() { + if (this.autoCleanClosures) { + removeFns(this.beforeAllFns); + removeFns(this.afterAllFns); + removeFns(this.beforeFns); + removeFns(this.afterFns); } } - return fullName.join(' '); - }; - /* - * Mark the suite with "pending" status - */ - Suite.prototype.pend = function() { - this.markedPending = true; - }; + reset() { + /** + * @typedef SuiteResult + * @property {String} id - The unique id of this suite. + * @property {String} description - The description text passed to the {@link describe} that made this suite. + * @property {String} fullName - The full description including all ancestors of this suite. + * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). + * @property {String} filename - Deprecated. The name of the file the suite was defined in. + * Note: The value may be incorrect if zone.js is installed or + * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that + * don't maintain the same call stack height as the originals. This property + * may be removed in a future version unless there is enough user interest + * in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}. + * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. + * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. + * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. + * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} + * @since 2.0.0 + */ + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + parentSuiteId: this.reportedParentSuiteId, + filename: this.filename, + failedExpectations: [], + deprecationWarnings: [], + duration: null, + properties: null + }; + this.markedPending = this.markedExcluding; + this.children.forEach(function(child) { + child.reset(); + }); + this.reportedDone = false; + } - /* - * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset} - * Useful for fdescribe, xdescribe, where pending state should remain. - */ - Suite.prototype.exclude = function() { - this.pend(); - this.markedExcluding = true; - }; + removeChildren() { + this.children = []; + } - Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift({ ...fn, suite: this }); - }; + addChild(child) { + this.children.push(child); + } - Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); - }; + status() { + if (this.markedPending) { + return 'pending'; + } - Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); - }; + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'passed'; + } + } - Suite.prototype.afterAll = function(fn) { - this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); - }; + getResult() { + this.result.status = this.status(); + return this.result; + } - Suite.prototype.startTimer = function() { - this.timer.start(); - }; + canBeReentered() { + return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; + } - Suite.prototype.endTimer = function() { - this.result.duration = this.timer.elapsed(); - }; + sharedUserContext() { + if (!this.sharedContext) { + this.sharedContext = this.parentSuite + ? this.parentSuite.clonedSharedUserContext() + : new j$.UserContext(); + } + + return this.sharedContext; + } + + clonedSharedUserContext() { + return j$.UserContext.fromExisting(this.sharedUserContext()); + } + + handleException() { + if (arguments[0] instanceof j$.errors.ExpectationFailed) { + return; + } + + const data = { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: arguments[0] + }; + const failedExpectation = j$.buildExpectationResult(data); + + if (!this.parentSuite) { + failedExpectation.globalErrorType = 'afterAll'; + } + + if (this.reportedDone) { + this.onLateError(failedExpectation); + } else { + this.result.failedExpectations.push(failedExpectation); + } + } + + onMultipleDone() { + let msg; + + // Issue an error. Include the context ourselves and pass + // ignoreRunnable: true, since getting here always means that we've already + // moved on and the current runnable isn't the one that caused the problem. + if (this.parentSuite) { + msg = + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n' + + '(in suite: ' + + this.getFullName() + + ')'; + } else { + msg = + 'A top-level beforeAll or afterAll function called its ' + + "'done' callback more than once."; + } + + this.onLateError(new Error(msg)); + } + + addExpectationResult() { + if (isFailure(arguments)) { + const data = arguments[1]; + const expectationResult = j$.buildExpectationResult(data); + + if (this.reportedDone) { + this.onLateError(expectationResult); + } else { + 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) { + throw new j$.errors.ExpectationFailed(); + } + } + } + + addDeprecationWarning(deprecation) { + if (typeof deprecation === 'string') { + deprecation = { message: deprecation }; + } + this.result.deprecationWarnings.push( + j$.buildExpectationResult(deprecation) + ); + } + + hasChildWithDescription(description) { + for (const child of this.children) { + if (child.description === description) { + return true; + } + } + + return false; + } + + get metadata() { + if (!this.metadata_) { + this.metadata_ = new SuiteMetadata(this); + } + + return this.metadata_; + } + } function removeFns(queueableFns) { for (const qf of queueableFns) { @@ -10564,250 +10750,64 @@ getJasmineRequireObj().Suite = function(j$) { } } - Suite.prototype.cleanupBeforeAfter = function() { - if (this.autoCleanClosures) { - removeFns(this.beforeAllFns); - removeFns(this.afterAllFns); - removeFns(this.beforeFns); - removeFns(this.afterFns); - } - }; - - Suite.prototype.reset = function() { - /** - * @typedef SuiteResult - * @property {String} id - The unique id of this suite. - * @property {String} description - The description text passed to the {@link describe} that made this suite. - * @property {String} fullName - The full description including all ancestors of this suite. - * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). - * @property {String} filename - Deprecated. The name of the file the suite was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that - * don't maintain the same call stack height as the originals. This property - * may be removed in a future version unless there is enough user interest - * in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}. - * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. - * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. - * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. - * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} - * @since 2.0.0 - */ - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - parentSuiteId: this.reportedParentSuiteId, - filename: this.filename, - failedExpectations: [], - deprecationWarnings: [], - duration: null, - properties: null - }; - this.markedPending = this.markedExcluding; - this.children.forEach(function(child) { - child.reset(); - }); - this.reportedDone = false; - }; - - Suite.prototype.removeChildren = function() { - this.children = []; - }; - - Suite.prototype.addChild = function(child) { - this.children.push(child); - }; - - Suite.prototype.status = function() { - if (this.markedPending) { - return 'pending'; - } - - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'passed'; - } - }; - - Suite.prototype.canBeReentered = function() { - return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; - }; - - Suite.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; - - Suite.prototype.sharedUserContext = function() { - if (!this.sharedContext) { - this.sharedContext = this.parentSuite - ? this.parentSuite.clonedSharedUserContext() - : new j$.UserContext(); - } - - return this.sharedContext; - }; - - Suite.prototype.clonedSharedUserContext = function() { - return j$.UserContext.fromExisting(this.sharedUserContext()); - }; - - Suite.prototype.handleException = function() { - if (arguments[0] instanceof j$.errors.ExpectationFailed) { - return; - } - - const data = { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: arguments[0] - }; - const failedExpectation = j$.buildExpectationResult(data); - - if (!this.parentSuite) { - failedExpectation.globalErrorType = 'afterAll'; - } - - if (this.reportedDone) { - this.onLateError(failedExpectation); - } else { - this.result.failedExpectations.push(failedExpectation); - } - }; - - Suite.prototype.onMultipleDone = function() { - let msg; - - // Issue a deprecation. Include the context ourselves and pass - // ignoreRunnable: true, since getting here always means that we've already - // moved on and the current runnable isn't the one that caused the problem. - if (this.parentSuite) { - msg = - "An asynchronous beforeAll or afterAll function called its 'done' " + - 'callback more than once.\n' + - '(in suite: ' + - this.getFullName() + - ')'; - } else { - msg = - 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once."; - } - - this.onLateError(new Error(msg)); - }; - - Suite.prototype.addExpectationResult = function() { - if (isFailure(arguments)) { - const data = arguments[1]; - const expectationResult = j$.buildExpectationResult(data); - - if (this.reportedDone) { - this.onLateError(expectationResult); - } else { - 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) { - throw new j$.errors.ExpectationFailed(); - } - } - }; - - Suite.prototype.addDeprecationWarning = function(deprecation) { - if (typeof deprecation === 'string') { - deprecation = { message: deprecation }; - } - this.result.deprecationWarnings.push( - j$.buildExpectationResult(deprecation) - ); - }; - - Suite.prototype.hasChildWithDescription = function(description) { - for (const child of this.children) { - if (child.description === description) { - return true; - } - } - - return false; - }; - - Object.defineProperty(Suite.prototype, 'metadata', { - get: function() { - if (!this.metadata_) { - this.metadata_ = new SuiteMetadata(this); - } - - return this.metadata_; - } - }); - /** * @interface Suite * @see Env#topSuite * @since 2.0.0 */ - function SuiteMetadata(suite) { - this.suite_ = suite; - /** - * The unique ID of this suite. - * @name Suite#id - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.id = suite.id; + class SuiteMetadata { + #suite; - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ - this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; + constructor(suite) { + this.#suite = suite; + /** + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} + * @since 2.0.0 + */ + this.id = suite.id; - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.description = suite.description; - } + /** + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} + */ + this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - * @since 2.0.0 - */ - SuiteMetadata.prototype.getFullName = function() { - return this.suite_.getFullName(); - }; - - /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} - * @since 2.0.0 - */ - Object.defineProperty(SuiteMetadata.prototype, 'children', { - get: function() { - return this.suite_.children.map(child => child.metadata); + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + * @since 2.0.0 + */ + this.description = suite.description; } - }); + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ + getFullName() { + return this.#suite.getFullName(); + } + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + * @since 2.0.0 + */ + get children() { + return this.#suite.children.map(child => child.metadata); + } + } function isFailure(args) { return !args[0]; diff --git a/src/core/Suite.js b/src/core/Suite.js index 81235bd3..0c789b85 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -1,86 +1,272 @@ getJasmineRequireObj().Suite = function(j$) { - function Suite(attrs) { - this.env = attrs.env; - this.id = attrs.id; - this.parentSuite = attrs.parentSuite; - this.description = attrs.description; - this.reportedParentSuiteId = attrs.reportedParentSuiteId; - this.filename = attrs.filename; - this.expectationFactory = attrs.expectationFactory; - this.asyncExpectationFactory = attrs.asyncExpectationFactory; - this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; - this.autoCleanClosures = - attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures; - this.onLateError = attrs.onLateError || function() {}; + class Suite { + constructor(attrs) { + this.env = attrs.env; + this.id = attrs.id; + this.parentSuite = attrs.parentSuite; + this.description = attrs.description; + this.reportedParentSuiteId = attrs.reportedParentSuiteId; + this.filename = attrs.filename; + this.expectationFactory = attrs.expectationFactory; + this.asyncExpectationFactory = attrs.asyncExpectationFactory; + this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; + this.autoCleanClosures = + attrs.autoCleanClosures === undefined + ? true + : !!attrs.autoCleanClosures; + this.onLateError = attrs.onLateError || function() {}; - this.beforeFns = []; - this.afterFns = []; - this.beforeAllFns = []; - this.afterAllFns = []; - this.timer = attrs.timer || new j$.Timer(); - this.children = []; + this.beforeFns = []; + this.afterFns = []; + this.beforeAllFns = []; + this.afterAllFns = []; + this.timer = attrs.timer || new j$.Timer(); + this.children = []; - this.reset(); - } + this.reset(); + } - Suite.prototype.setSuiteProperty = function(key, value) { - this.result.properties = this.result.properties || {}; - this.result.properties[key] = value; - }; + setSuiteProperty(key, value) { + this.result.properties = this.result.properties || {}; + this.result.properties[key] = value; + } - Suite.prototype.getFullName = function() { - const fullName = []; - for ( - let parentSuite = this; - parentSuite; - parentSuite = parentSuite.parentSuite - ) { - if (parentSuite.parentSuite) { - fullName.unshift(parentSuite.description); + getFullName() { + const fullName = []; + for ( + let parentSuite = this; + parentSuite; + parentSuite = parentSuite.parentSuite + ) { + if (parentSuite.parentSuite) { + fullName.unshift(parentSuite.description); + } + } + return fullName.join(' '); + } + + // Mark the suite with "pending" status + pend() { + this.markedPending = true; + } + + // Like pend(), but pending state will survive reset(). + // Useful for fdescribe, xdescribe, where pending state should remain. + exclude() { + this.pend(); + this.markedExcluding = true; + } + + beforeEach(fn) { + this.beforeFns.unshift({ ...fn, suite: this }); + } + + beforeAll(fn) { + this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); + } + + afterEach(fn) { + this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); + } + + afterAll(fn) { + this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); + } + + startTimer() { + this.timer.start(); + } + + endTimer() { + this.result.duration = this.timer.elapsed(); + } + + cleanupBeforeAfter() { + if (this.autoCleanClosures) { + removeFns(this.beforeAllFns); + removeFns(this.afterAllFns); + removeFns(this.beforeFns); + removeFns(this.afterFns); } } - return fullName.join(' '); - }; - /* - * Mark the suite with "pending" status - */ - Suite.prototype.pend = function() { - this.markedPending = true; - }; + reset() { + /** + * @typedef SuiteResult + * @property {String} id - The unique id of this suite. + * @property {String} description - The description text passed to the {@link describe} that made this suite. + * @property {String} fullName - The full description including all ancestors of this suite. + * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). + * @property {String} filename - Deprecated. The name of the file the suite was defined in. + * Note: The value may be incorrect if zone.js is installed or + * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that + * don't maintain the same call stack height as the originals. This property + * may be removed in a future version unless there is enough user interest + * in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}. + * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. + * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. + * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. + * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. + * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} + * @since 2.0.0 + */ + this.result = { + id: this.id, + description: this.description, + fullName: this.getFullName(), + parentSuiteId: this.reportedParentSuiteId, + filename: this.filename, + failedExpectations: [], + deprecationWarnings: [], + duration: null, + properties: null + }; + this.markedPending = this.markedExcluding; + this.children.forEach(function(child) { + child.reset(); + }); + this.reportedDone = false; + } - /* - * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset} - * Useful for fdescribe, xdescribe, where pending state should remain. - */ - Suite.prototype.exclude = function() { - this.pend(); - this.markedExcluding = true; - }; + removeChildren() { + this.children = []; + } - Suite.prototype.beforeEach = function(fn) { - this.beforeFns.unshift({ ...fn, suite: this }); - }; + addChild(child) { + this.children.push(child); + } - Suite.prototype.beforeAll = function(fn) { - this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this }); - }; + status() { + if (this.markedPending) { + return 'pending'; + } - Suite.prototype.afterEach = function(fn) { - this.afterFns.unshift({ ...fn, suite: this, type: 'afterEach' }); - }; + if (this.result.failedExpectations.length > 0) { + return 'failed'; + } else { + return 'passed'; + } + } - Suite.prototype.afterAll = function(fn) { - this.afterAllFns.unshift({ ...fn, type: 'afterAll' }); - }; + getResult() { + this.result.status = this.status(); + return this.result; + } - Suite.prototype.startTimer = function() { - this.timer.start(); - }; + canBeReentered() { + return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; + } - Suite.prototype.endTimer = function() { - this.result.duration = this.timer.elapsed(); - }; + sharedUserContext() { + if (!this.sharedContext) { + this.sharedContext = this.parentSuite + ? this.parentSuite.clonedSharedUserContext() + : new j$.UserContext(); + } + + return this.sharedContext; + } + + clonedSharedUserContext() { + return j$.UserContext.fromExisting(this.sharedUserContext()); + } + + handleException() { + if (arguments[0] instanceof j$.errors.ExpectationFailed) { + return; + } + + const data = { + matcherName: '', + passed: false, + expected: '', + actual: '', + error: arguments[0] + }; + const failedExpectation = j$.buildExpectationResult(data); + + if (!this.parentSuite) { + failedExpectation.globalErrorType = 'afterAll'; + } + + if (this.reportedDone) { + this.onLateError(failedExpectation); + } else { + this.result.failedExpectations.push(failedExpectation); + } + } + + onMultipleDone() { + let msg; + + // Issue an error. Include the context ourselves and pass + // ignoreRunnable: true, since getting here always means that we've already + // moved on and the current runnable isn't the one that caused the problem. + if (this.parentSuite) { + msg = + "An asynchronous beforeAll or afterAll function called its 'done' " + + 'callback more than once.\n' + + '(in suite: ' + + this.getFullName() + + ')'; + } else { + msg = + 'A top-level beforeAll or afterAll function called its ' + + "'done' callback more than once."; + } + + this.onLateError(new Error(msg)); + } + + addExpectationResult() { + if (isFailure(arguments)) { + const data = arguments[1]; + const expectationResult = j$.buildExpectationResult(data); + + if (this.reportedDone) { + this.onLateError(expectationResult); + } else { + 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) { + throw new j$.errors.ExpectationFailed(); + } + } + } + + addDeprecationWarning(deprecation) { + if (typeof deprecation === 'string') { + deprecation = { message: deprecation }; + } + this.result.deprecationWarnings.push( + j$.buildExpectationResult(deprecation) + ); + } + + hasChildWithDescription(description) { + for (const child of this.children) { + if (child.description === description) { + return true; + } + } + + return false; + } + + get metadata() { + if (!this.metadata_) { + this.metadata_ = new SuiteMetadata(this); + } + + return this.metadata_; + } + } function removeFns(queueableFns) { for (const qf of queueableFns) { @@ -88,250 +274,64 @@ getJasmineRequireObj().Suite = function(j$) { } } - Suite.prototype.cleanupBeforeAfter = function() { - if (this.autoCleanClosures) { - removeFns(this.beforeAllFns); - removeFns(this.afterAllFns); - removeFns(this.beforeFns); - removeFns(this.afterFns); - } - }; - - Suite.prototype.reset = function() { - /** - * @typedef SuiteResult - * @property {String} id - The unique id of this suite. - * @property {String} description - The description text passed to the {@link describe} that made this suite. - * @property {String} fullName - The full description including all ancestors of this suite. - * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe(). - * @property {String} filename - Deprecated. The name of the file the suite was defined in. - * Note: The value may be incorrect if zone.js is installed or - * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that - * don't maintain the same call stack height as the originals. This property - * may be removed in a future version unless there is enough user interest - * in keeping it. See {@link https://github.com/jasmine/jasmine/issues/2065}. - * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. - * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. - * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. - * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach. - * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty} - * @since 2.0.0 - */ - this.result = { - id: this.id, - description: this.description, - fullName: this.getFullName(), - parentSuiteId: this.reportedParentSuiteId, - filename: this.filename, - failedExpectations: [], - deprecationWarnings: [], - duration: null, - properties: null - }; - this.markedPending = this.markedExcluding; - this.children.forEach(function(child) { - child.reset(); - }); - this.reportedDone = false; - }; - - Suite.prototype.removeChildren = function() { - this.children = []; - }; - - Suite.prototype.addChild = function(child) { - this.children.push(child); - }; - - Suite.prototype.status = function() { - if (this.markedPending) { - return 'pending'; - } - - if (this.result.failedExpectations.length > 0) { - return 'failed'; - } else { - return 'passed'; - } - }; - - Suite.prototype.canBeReentered = function() { - return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0; - }; - - Suite.prototype.getResult = function() { - this.result.status = this.status(); - return this.result; - }; - - Suite.prototype.sharedUserContext = function() { - if (!this.sharedContext) { - this.sharedContext = this.parentSuite - ? this.parentSuite.clonedSharedUserContext() - : new j$.UserContext(); - } - - return this.sharedContext; - }; - - Suite.prototype.clonedSharedUserContext = function() { - return j$.UserContext.fromExisting(this.sharedUserContext()); - }; - - Suite.prototype.handleException = function() { - if (arguments[0] instanceof j$.errors.ExpectationFailed) { - return; - } - - const data = { - matcherName: '', - passed: false, - expected: '', - actual: '', - error: arguments[0] - }; - const failedExpectation = j$.buildExpectationResult(data); - - if (!this.parentSuite) { - failedExpectation.globalErrorType = 'afterAll'; - } - - if (this.reportedDone) { - this.onLateError(failedExpectation); - } else { - this.result.failedExpectations.push(failedExpectation); - } - }; - - Suite.prototype.onMultipleDone = function() { - let msg; - - // Issue a deprecation. Include the context ourselves and pass - // ignoreRunnable: true, since getting here always means that we've already - // moved on and the current runnable isn't the one that caused the problem. - if (this.parentSuite) { - msg = - "An asynchronous beforeAll or afterAll function called its 'done' " + - 'callback more than once.\n' + - '(in suite: ' + - this.getFullName() + - ')'; - } else { - msg = - 'A top-level beforeAll or afterAll function called its ' + - "'done' callback more than once."; - } - - this.onLateError(new Error(msg)); - }; - - Suite.prototype.addExpectationResult = function() { - if (isFailure(arguments)) { - const data = arguments[1]; - const expectationResult = j$.buildExpectationResult(data); - - if (this.reportedDone) { - this.onLateError(expectationResult); - } else { - 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) { - throw new j$.errors.ExpectationFailed(); - } - } - }; - - Suite.prototype.addDeprecationWarning = function(deprecation) { - if (typeof deprecation === 'string') { - deprecation = { message: deprecation }; - } - this.result.deprecationWarnings.push( - j$.buildExpectationResult(deprecation) - ); - }; - - Suite.prototype.hasChildWithDescription = function(description) { - for (const child of this.children) { - if (child.description === description) { - return true; - } - } - - return false; - }; - - Object.defineProperty(Suite.prototype, 'metadata', { - get: function() { - if (!this.metadata_) { - this.metadata_ = new SuiteMetadata(this); - } - - return this.metadata_; - } - }); - /** * @interface Suite * @see Env#topSuite * @since 2.0.0 */ - function SuiteMetadata(suite) { - this.suite_ = suite; - /** - * The unique ID of this suite. - * @name Suite#id - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.id = suite.id; + class SuiteMetadata { + #suite; - /** - * The parent of this suite, or null if this is the top suite. - * @name Suite#parentSuite - * @readonly - * @type {Suite} - */ - this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; + constructor(suite) { + this.#suite = suite; + /** + * The unique ID of this suite. + * @name Suite#id + * @readonly + * @type {string} + * @since 2.0.0 + */ + this.id = suite.id; - /** - * The description passed to the {@link describe} that created this suite. - * @name Suite#description - * @readonly - * @type {string} - * @since 2.0.0 - */ - this.description = suite.description; - } + /** + * The parent of this suite, or null if this is the top suite. + * @name Suite#parentSuite + * @readonly + * @type {Suite} + */ + this.parentSuite = suite.parentSuite ? suite.parentSuite.metadata : null; - /** - * The full description including all ancestors of this suite. - * @name Suite#getFullName - * @function - * @returns {string} - * @since 2.0.0 - */ - SuiteMetadata.prototype.getFullName = function() { - return this.suite_.getFullName(); - }; - - /** - * The suite's children. - * @name Suite#children - * @type {Array.<(Spec|Suite)>} - * @since 2.0.0 - */ - Object.defineProperty(SuiteMetadata.prototype, 'children', { - get: function() { - return this.suite_.children.map(child => child.metadata); + /** + * The description passed to the {@link describe} that created this suite. + * @name Suite#description + * @readonly + * @type {string} + * @since 2.0.0 + */ + this.description = suite.description; } - }); + + /** + * The full description including all ancestors of this suite. + * @name Suite#getFullName + * @function + * @returns {string} + * @since 2.0.0 + */ + getFullName() { + return this.#suite.getFullName(); + } + + /** + * The suite's children. + * @name Suite#children + * @type {Array.<(Spec|Suite)>} + * @since 2.0.0 + */ + get children() { + return this.#suite.children.map(child => child.metadata); + } + } function isFailure(args) { return !args[0];