From 78c14f81a8aed7df06d2cdfbaaad367b3e0a8f1d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 15 Nov 2025 14:40:39 -0800 Subject: [PATCH 01/26] Copy 6.0.0-alpha.2 release notes from branch --- release_notes/6.0.0-alpha.2.md | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 release_notes/6.0.0-alpha.2.md diff --git a/release_notes/6.0.0-alpha.2.md b/release_notes/6.0.0-alpha.2.md new file mode 100644 index 00000000..16146ddb --- /dev/null +++ b/release_notes/6.0.0-alpha.2.md @@ -0,0 +1,90 @@ +# Jasmine Core 6.0.0-alpha.2 Release Notes + +This is a pre-release, intended to offer a preview of upcoming changes and to +solicit feedback. + +## A Note About Pre-Release Compatibility + +There may be additional breaking changes in future 6.0 pre-releases or in the +final 6.0 release. That's allowed by the semver specification, but users are +sometimes unpleasantly surprised by it. + +NPM's implementation of carat version ranges assumes that subsequent +pre-releases and final releases are fully compatible with earlier pre-releases. +If your package.json contains `"jasmine-core": "^6.0.0-alpha.2`, +NPM might install any later 6.x version even though there is no guarantee of +compatibility. If that isn't ok, you should specify an exact pre-release version: +`"jasmine-core": "6.0.0-alpha.2`. + + +## Changes to supported environments + +Safari 26 is now supported on a best-effort basis.† + +Due to the limited availability of Safari 18 and later on free CI services, +Safari support in future jasmine-core versions will be limited to: + +* Best-effort support for the latest Safari version available on GitHub Actions, + which may change at any time. +* Best-effort support for Safari 16 and 17 for as long as it remains practical. + +## Bug Fixes + +* Fix custom matchers in top-level specs†† + * Merges [#2088](https://github.com/jasmine/jasmine/pull/2088) from @bonkevin + +## New features + +* Larger body font size in HTML reporters +* New Performance tab in HtmlReporterV2 shows metrics and a list of the slowest + specs. +* Experimental `safariYieldStrategy: "time"` config option, which may make + Jasmine run significantly faster in Safari and similar browsers. So far, this + option has not been tested on a wide variety of workloads. Feedback is + appreciated. +* New `extraItStackFrames` and `extraDescribeStackFrames` config options to fix + the filename properties of reporter events in configurations that wrap + `it`/`describe`, such as zone.js.† +* `jasmine.allOf asymmetric` equality tester† + * Merges [#2087](https://github.com/jasmine/jasmine/pull/2087) from @jonahd-g + * Fixes [#2083](https://github.com/jasmine/jasmine/issues/2083) +* Re-add support for partial spec name filtering via `spec` query parameter + * Fixes [#2085](https://github.com/jasmine/jasmine/issues/2085). +* Require spec/suite property keys to be strings, not just anything that's + cloneable and serializable. This matches the existing API reference + documentation. + +## Documentation improvements + +* Fix HtmlReporterV2 ctor example + +## Internal Improvements + +* Remove code to support browsers that don't have MessageChannel. Jasmine hasn't + run in any such browsers since 2.x. + +† Also likely to be included in a future 5.x release.
+†† Also released in 5.12.1. + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari | 16**, 17**, 26** | +| Chrome | 142* | +| Firefox | 102**, 115**, 128**, 140, 145* | +| Edge | 142* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From c5555dd8cc8a4ccdbccbb1fe8bf37528cdf27b66 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 27 Nov 2025 06:30:09 -0800 Subject: [PATCH 02/26] Better debug logging for spec that occasionally fails in FF --- spec/core/matchers/matchersUtilSpec.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 747fca59..e45564a5 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -768,7 +768,14 @@ describe('matchersUtil', function() { a2[0] = 1; const diffBuilder = new jasmineUnderTest.DiffBuilder(); expect(matchersUtil.equals(a1, a2, diffBuilder)).toBe(false); - jasmine.debugLog('Diff: ' + diffBuilder.getMessage()); + jasmine.debugLog('a1 keys: ' + jasmine.basicPrettyPrinter_( + jasmineUnderTest.MatchersUtil.keys(a1))); + jasmine.debugLog('a2 keys: ' + jasmine.basicPrettyPrinter_( + jasmineUnderTest.MatchersUtil.keys(a2))); + jasmine.debugLog('a1 length:' + a1.length); + jasmine.debugLog('a2 length:' + a2.length); + jasmine.debugLog('a1[0]: ' + a1[0]); + jasmine.debugLog('a2[0]: ' + a2[0]); } ); From 1e691b2470cccc4467a9a88b939fca51c16bd6bb Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Thu, 27 Nov 2025 06:53:27 -0800 Subject: [PATCH 03/26] Prettier --- spec/core/matchers/matchersUtilSpec.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index e45564a5..32cd4d60 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -768,10 +768,18 @@ describe('matchersUtil', function() { a2[0] = 1; const diffBuilder = new jasmineUnderTest.DiffBuilder(); expect(matchersUtil.equals(a1, a2, diffBuilder)).toBe(false); - jasmine.debugLog('a1 keys: ' + jasmine.basicPrettyPrinter_( - jasmineUnderTest.MatchersUtil.keys(a1))); - jasmine.debugLog('a2 keys: ' + jasmine.basicPrettyPrinter_( - jasmineUnderTest.MatchersUtil.keys(a2))); + jasmine.debugLog( + 'a1 keys: ' + + jasmine.basicPrettyPrinter_( + jasmineUnderTest.MatchersUtil.keys(a1) + ) + ); + jasmine.debugLog( + 'a2 keys: ' + + jasmine.basicPrettyPrinter_( + jasmineUnderTest.MatchersUtil.keys(a2) + ) + ); jasmine.debugLog('a1 length:' + a1.length); jasmine.debugLog('a2 length:' + a2.length); jasmine.debugLog('a1[0]: ' + a1[0]); From 79405426fa1c7a3c942425c3d2738bbb4322d875 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 28 Nov 2025 11:35:46 -0800 Subject: [PATCH 04/26] Bump version to 6.0.0-beta.0 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- release_notes/6.0.0-beta.0.md | 74 +++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 release_notes/6.0.0-beta.0.md diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 08d7c19f..31f435ec 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -12385,5 +12385,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '6.0.0-alpha.2'; + return '6.0.0-beta.0'; }; diff --git a/package.json b/package.json index 6950dbf1..eb339b00 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "6.0.0-alpha.2", + "version": "6.0.0-beta.0", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/release_notes/6.0.0-beta.0.md b/release_notes/6.0.0-beta.0.md new file mode 100644 index 00000000..3ea586ee --- /dev/null +++ b/release_notes/6.0.0-beta.0.md @@ -0,0 +1,74 @@ +# Jasmine Core 6.0.0-beta.0 Release Notes + +This is a pre-release, intended to offer a preview of upcoming changes and to +solicit feedback. + +## A Note About Pre-Release Compatibility + +There may be additional breaking changes in future 6.0 pre-releases or in the +final 6.0 release. That's allowed by the semver specification, but users are +sometimes unpleasantly surprised by it. + +NPM's implementation of carat version ranges assumes that subsequent +pre-releases and final releases are fully compatible with earlier pre-releases. +If your package.json contains `"jasmine-core": "^6.0.0-beta.0`, +NPM might install any later 6.x version even though there is no guarantee of +compatibility. If that isn't ok, you should specify an exact pre-release version: +`"jasmine-core": "6.0.0-beta.0`. + + +## Breaking changes + +* boot1.js no longer adds jsApiReporter to the env. +* HtmlReporterV2 initialization and boot1.js have been simplified. If you + maintain your own boot file, update it to match the boot1.js included in this + package. + + +## New features + +* Statically exposed pretty printer as jasmine.pp(). + +## Bug fixes + +* Fixed HtmlReporterV2 progress bar when running a subset of specs. + + +## Deprecations + +* jsApiReporter is deprecated. +* Detect monkey patching and emit a deprecation warning. + +## Documentation improvements + +* Documented the set of possible spec statuses. + + +## Internal improvements + +* Replaced isArray helper with native Array.isArray + + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari | 16**, 17**, 26.1** | +| Chrome | 142* | +| Firefox | 102**, 115**, 128**, 140, 145* | +| Edge | 142* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From db6c142afdb03e7b4d7269f0187539888dc31111 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 28 Nov 2025 11:49:05 -0800 Subject: [PATCH 05/26] Copy 6.0.0-beta.0 release notes from branch --- release_notes/6.0.0-beta.0.md | 74 +++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 release_notes/6.0.0-beta.0.md diff --git a/release_notes/6.0.0-beta.0.md b/release_notes/6.0.0-beta.0.md new file mode 100644 index 00000000..3ea586ee --- /dev/null +++ b/release_notes/6.0.0-beta.0.md @@ -0,0 +1,74 @@ +# Jasmine Core 6.0.0-beta.0 Release Notes + +This is a pre-release, intended to offer a preview of upcoming changes and to +solicit feedback. + +## A Note About Pre-Release Compatibility + +There may be additional breaking changes in future 6.0 pre-releases or in the +final 6.0 release. That's allowed by the semver specification, but users are +sometimes unpleasantly surprised by it. + +NPM's implementation of carat version ranges assumes that subsequent +pre-releases and final releases are fully compatible with earlier pre-releases. +If your package.json contains `"jasmine-core": "^6.0.0-beta.0`, +NPM might install any later 6.x version even though there is no guarantee of +compatibility. If that isn't ok, you should specify an exact pre-release version: +`"jasmine-core": "6.0.0-beta.0`. + + +## Breaking changes + +* boot1.js no longer adds jsApiReporter to the env. +* HtmlReporterV2 initialization and boot1.js have been simplified. If you + maintain your own boot file, update it to match the boot1.js included in this + package. + + +## New features + +* Statically exposed pretty printer as jasmine.pp(). + +## Bug fixes + +* Fixed HtmlReporterV2 progress bar when running a subset of specs. + + +## Deprecations + +* jsApiReporter is deprecated. +* Detect monkey patching and emit a deprecation warning. + +## Documentation improvements + +* Documented the set of possible spec statuses. + + +## Internal improvements + +* Replaced isArray helper with native Array.isArray + + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari | 16**, 17**, 26.1** | +| Chrome | 142* | +| Firefox | 102**, 115**, 128**, 140, 145* | +| Edge | 142* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From 9cf9b856b0db97a93a43f09734ef4f776d94b752 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 1 Dec 2025 17:25:03 -0800 Subject: [PATCH 06/26] Bump version to 5.13.0 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- release_notes/5.13.0.md | 44 +++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 release_notes/5.13.0.md diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index f281779f..33c6f01c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -11901,5 +11901,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '5.12.1'; + return '5.13.0'; }; diff --git a/package.json b/package.json index 905d1526..b58081ce 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "5.12.1", + "version": "5.13.0", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/release_notes/5.13.0.md b/release_notes/5.13.0.md new file mode 100644 index 00000000..64874b7f --- /dev/null +++ b/release_notes/5.13.0.md @@ -0,0 +1,44 @@ +# Jasmine Core 5.13.0 Release Notes + +## Changes to supported environments + +Safari 26 is now supported on a best-effort basis. + +Due to the limited availability of Safari 18 and later on free CI services, +Safari support in future jasmine-core versions will be limited to: + +* Best-effort support for the latest Safari version available on GitHub Actions, + which may change at any time. +* Best-effort support for Safari 16 and 17 for as long as it remains practical. + +## New Features + +* New `extraItStackFrames` and `extraDescribeStackFrames` config options to fix + the filename properties of reporter events in configurations that wrap + `it`/`describe`, such as zone.js. The `filename` properties of reporter events + are no longer deprecated. +* `jasmine.allOf` asymmetric equality tester + * Merges [#2087](https://github.com/jasmine/jasmine/issues/2083) from @jonahd-g + * Fixes [#2083](https://github.com/jasmine/jasmine/pull/2087) + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------|--------------------------------| +| Node | 18.20.5**, 20, 22, 24 | +| Safari** | 16, 17, 26.1 | +| Chrome | 142* | +| Firefox | 102**, 115**, 128**, 140, 145* | +| Edge | 142* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From c999ce0787ff692a24a6c8d544a6560428f32c63 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 1 Dec 2025 17:57:18 -0800 Subject: [PATCH 07/26] Update some dev dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index eb339b00..1685dd90 100644 --- a/package.json +++ b/package.json @@ -43,10 +43,10 @@ "ejs": "^3.1.10", "eslint": "^9.24.0", "eslint-plugin-compat": "^6.0.2", - "glob": "^10.2.3", + "glob": "^13.0.0", "globals": "^16.0.0", - "jasmine": "github:jasmine/jasmine-npm#6.0", - "jasmine-browser-runner": "github:jasmine/jasmine-browser-runner#4.0", + "jasmine": "github:jasmine/jasmine-npm", + "jasmine-browser-runner": "github:jasmine/jasmine-browser-runner", "jsdom": "^26.0.0", "prettier": "1.17.1", "sass": "^1.58.3" From f3dba82b04bf0638ff8a87cf7b5e427da3057dee Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 1 Dec 2025 18:33:08 -0800 Subject: [PATCH 08/26] Revert to using window.onload To support top level await, jasmine-browser-runner needs to be able to delay env execution until after spec files have initialized. The old-fashioned event listener style makes that straightforward. --- lib/jasmine-core/boot1.js | 9 +++++++-- src/boot/boot1.js | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/jasmine-core/boot1.js b/lib/jasmine-core/boot1.js index 9f3401d3..0194e6c6 100644 --- a/lib/jasmine-core/boot1.js +++ b/lib/jasmine-core/boot1.js @@ -49,11 +49,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ env.configure(urls.configFromCurrentUrl()); - window.addEventListener('load', function() { + const currentWindowOnload = window.onload; + window.onload = function() { + if (currentWindowOnload) { + currentWindowOnload(); + } + // The HTML reporter needs to be set up here so it can access the DOM. Other // reporters can be added at any time before env.execute() is called. const htmlReporter = new jasmine.HtmlReporterV2({ env, urls }); env.addReporter(htmlReporter); env.execute(); - }); + }; })(); diff --git a/src/boot/boot1.js b/src/boot/boot1.js index bf0d2891..d923db8b 100644 --- a/src/boot/boot1.js +++ b/src/boot/boot1.js @@ -25,11 +25,16 @@ */ env.configure(urls.configFromCurrentUrl()); - window.addEventListener('load', function() { + const currentWindowOnload = window.onload; + window.onload = function() { + if (currentWindowOnload) { + currentWindowOnload(); + } + // The HTML reporter needs to be set up here so it can access the DOM. Other // reporters can be added at any time before env.execute() is called. const htmlReporter = new jasmine.HtmlReporterV2({ env, urls }); env.addReporter(htmlReporter); env.execute(); - }); + }; })(); From 9f0488dc3211c66f78f1d6856e9930a2fb5e978d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 6 Dec 2025 10:56:56 -0800 Subject: [PATCH 09/26] Bump version to 6.0.0-beta.1 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- release_notes/6.0.0-beta.1.md | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 release_notes/6.0.0-beta.1.md diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 31f435ec..b5c3220d 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -12385,5 +12385,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '6.0.0-beta.0'; + return '6.0.0-beta.1'; }; diff --git a/package.json b/package.json index 1685dd90..6bb4a501 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "6.0.0-beta.0", + "version": "6.0.0-beta.1", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/release_notes/6.0.0-beta.1.md b/release_notes/6.0.0-beta.1.md new file mode 100644 index 00000000..85a3977d --- /dev/null +++ b/release_notes/6.0.0-beta.1.md @@ -0,0 +1,47 @@ +# Jasmine Core 6.0.0-beta.1 Release Notes + +This is a pre-release, intended to offer a preview of upcoming changes and to +solicit feedback. + +A corresponding release of the `jasmine` package is not planned because the +change in this release only affects browser users. + +## A Note About Pre-Release Compatibility + +There may be additional breaking changes in future 6.0 pre-releases or in the +final 6.0 release. That's allowed by the semver specification, but users are +sometimes unpleasantly surprised by it. + +NPM's implementation of carat version ranges assumes that subsequent +pre-releases and final releases are fully compatible with earlier pre-releases. +If your package.json contains `"jasmine-core": "^6.0.0-beta.1`, +NPM might install any later 6.x version even though there is no guarantee of +compatibility. If that isn't ok, you should specify an exact pre-release version: +`"jasmine-core": "6.0.0-beta.1`. + +## Bug Fixes + +* Revert to using window.onload in boot1.js. This fixes top level await in + jasmine-browser-runner. + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari** | 16, 17, 26.1 | +| Chrome | 143* | +| Firefox | 102**, 115**, 128**, 140, 145* | +| Edge | 142* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From a15df6d455f6689dbd85b2a46a03063e2b6b8880 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 30 Dec 2025 12:15:33 -0800 Subject: [PATCH 10/26] Document that globals may be overwritten --- lib/jasmine-core/jasmine.js | 27 +++++++++++++++++++++++++-- src/core/requireInterface.js | 27 +++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b5c3220d..a014b8ac 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -9075,6 +9075,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -9090,6 +9091,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -9106,6 +9108,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -9124,6 +9127,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. @@ -9141,6 +9145,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed. */ @@ -9156,6 +9161,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} testFunction Function that contains the code of your test. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. @@ -9171,6 +9177,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @see async @@ -9185,6 +9192,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @see async @@ -9201,6 +9209,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @see async @@ -9217,6 +9226,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @see async @@ -9230,6 +9240,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name getSpecProperty * @since 5.10.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @returns {*} The value of the property */ @@ -9242,6 +9254,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name setSpecProperty * @since 3.6.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @param {*} value The value of the property */ @@ -9254,6 +9268,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name setSuiteProperty * @since 3.6.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @param {*} value The value of the property */ @@ -9267,6 +9283,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -9283,6 +9300,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 3.3.0 * @function * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {async-matchers} * @example @@ -9309,8 +9327,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name throwUnlessAsync * @since 5.1.0 * @function - * @param actual * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -9333,8 +9351,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name throwUnless * @since 5.1.0 * @function - * @param actual * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -9348,6 +9366,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.0.0 * @function * @global + * @overwritable * @param {String} [message] - Reason the spec is pending. */ pending: function() { @@ -9360,6 +9379,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String|Error} [error] - Reason for the failure. */ fail: function() { @@ -9372,6 +9392,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy}. * @param {String} methodName - The name of the method to replace with a {@link Spy}. * @returns {Spy} @@ -9386,6 +9407,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.6.0 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy} * @param {String} propertyName - The name of the property to replace with a {@link Spy}. * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on. @@ -9401,6 +9423,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 3.2.1 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy}s * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties * @returns {Object} the spied object diff --git a/src/core/requireInterface.js b/src/core/requireInterface.js index 0e6e931a..eaf8c394 100644 --- a/src/core/requireInterface.js +++ b/src/core/requireInterface.js @@ -20,6 +20,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -35,6 +36,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -51,6 +53,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String} description Textual description of the group * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs */ @@ -69,6 +72,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. @@ -86,6 +90,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed. */ @@ -101,6 +106,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String} description Textual description of what this spec is checking. * @param {implementationCallback} testFunction Function that contains the code of your test. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec. @@ -116,6 +122,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach. * @see async @@ -130,6 +137,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach. * @see async @@ -146,6 +154,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to setup your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll. * @see async @@ -162,6 +171,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {implementationCallback} [function] Function that contains the code to teardown your specs. * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll. * @see async @@ -175,6 +185,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name getSpecProperty * @since 5.10.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @returns {*} The value of the property */ @@ -187,6 +199,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name setSpecProperty * @since 3.6.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @param {*} value The value of the property */ @@ -199,6 +213,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name setSuiteProperty * @since 3.6.0 * @function + * @global + * @overwritable * @param {String} key The name of the property * @param {*} value The value of the property */ @@ -212,6 +228,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -228,6 +245,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 3.3.0 * @function * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {async-matchers} * @example @@ -254,8 +272,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name throwUnlessAsync * @since 5.1.0 * @function - * @param actual * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -278,8 +296,8 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @name throwUnless * @since 5.1.0 * @function - * @param actual * @global + * @overwritable * @param {Object} actual - Actual computed value to test expectations against. * @return {matchers} */ @@ -293,6 +311,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.0.0 * @function * @global + * @overwritable * @param {String} [message] - Reason the spec is pending. */ pending: function() { @@ -305,6 +324,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.1.0 * @function * @global + * @overwritable * @param {String|Error} [error] - Reason for the failure. */ fail: function() { @@ -317,6 +337,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 1.3.0 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy}. * @param {String} methodName - The name of the method to replace with a {@link Spy}. * @returns {Spy} @@ -331,6 +352,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 2.6.0 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy} * @param {String} propertyName - The name of the property to replace with a {@link Spy}. * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on. @@ -346,6 +368,7 @@ getJasmineRequireObj().interface = function(jasmine, env) { * @since 3.2.1 * @function * @global + * @overwritable * @param {Object} obj - The object upon which to install the {@link Spy}s * @param {boolean} includeNonEnumerable - Whether or not to add spies to non-enumerable properties * @returns {Object} the spied object From 3d36b11c8fc470350af08e916966c99a7270446a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Tue, 30 Dec 2025 12:18:22 -0800 Subject: [PATCH 11/26] rm bogus @optional jsdoc tags --- lib/jasmine-core/jasmine.js | 2 -- src/core/reporterEvents.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index a014b8ac..2f6c538a 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -8961,7 +8961,6 @@ getJasmineRequireObj().reporterEvents = function(j$) { * {@link ReporterCapabilities} will apply. * @name Reporter#reporterCapabilities * @type ReporterCapabilities | undefined - * @optional * @since 5.0 */ /** @@ -9028,7 +9027,6 @@ getJasmineRequireObj().reporterEvents = function(j$) { /** * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions) * @function - * @optional * @name Reporter#specStarted * @param {SpecStartedEvent} result Information about the individual {@link it} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. diff --git a/src/core/reporterEvents.js b/src/core/reporterEvents.js index 55243039..633b1c4f 100644 --- a/src/core/reporterEvents.js +++ b/src/core/reporterEvents.js @@ -7,7 +7,6 @@ getJasmineRequireObj().reporterEvents = function(j$) { * {@link ReporterCapabilities} will apply. * @name Reporter#reporterCapabilities * @type ReporterCapabilities | undefined - * @optional * @since 5.0 */ /** @@ -74,7 +73,6 @@ getJasmineRequireObj().reporterEvents = function(j$) { /** * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions) * @function - * @optional * @name Reporter#specStarted * @param {SpecStartedEvent} result Information about the individual {@link it} being run * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on. From 1ad28d8515b26f8a1e024d4869a000bf2f18398d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 11 Jan 2026 19:23:25 -0800 Subject: [PATCH 12/26] Update copyright date --- LICENSE | 2 +- README.md | 2 +- lib/jasmine-core.js | 2 +- lib/jasmine-core/boot0.js | 2 +- lib/jasmine-core/boot1.js | 2 +- lib/jasmine-core/jasmine-html.js | 2 +- lib/jasmine-core/jasmine.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index 73a62df0..3bbb5119 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 6d6d69a7..7963fc75 100644 --- a/README.md +++ b/README.md @@ -60,5 +60,5 @@ To find out what environments work with a particular Jasmine release, see the [r * Sheel Choksi Copyright (c) 2008-2019 Pivotal Labs
-Copyright (c) 2008-2025 The Jasmine developers
+Copyright (c) 2008-2026 The Jasmine developers
This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE). diff --git a/lib/jasmine-core.js b/lib/jasmine-core.js index 6efa2367..d767005a 100644 --- a/lib/jasmine-core.js +++ b/lib/jasmine-core.js @@ -1,6 +1,6 @@ /* Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/jasmine-core/boot0.js b/lib/jasmine-core/boot0.js index 53887758..5a97826d 100644 --- a/lib/jasmine-core/boot0.js +++ b/lib/jasmine-core/boot0.js @@ -1,6 +1,6 @@ /* Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/jasmine-core/boot1.js b/lib/jasmine-core/boot1.js index 0194e6c6..ebcb5bb3 100644 --- a/lib/jasmine-core/boot1.js +++ b/lib/jasmine-core/boot1.js @@ -1,6 +1,6 @@ /* Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index d89e6002..c3c92d5b 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -1,6 +1,6 @@ /* Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2f6c538a..dd7a348e 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -1,6 +1,6 @@ /* Copyright (c) 2008-2019 Pivotal Labs -Copyright (c) 2008-2025 The Jasmine developers +Copyright (c) 2008-2026 The Jasmine developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From e759ddced2604f0325e48e9c1554e15c97c9a6c4 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 11 Jan 2026 19:23:51 -0800 Subject: [PATCH 13/26] Clarify monkey patching deprecation warning --- lib/jasmine-core/jasmine.js | 2 +- src/core/deprecateMonkeyPatching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index dd7a348e..53aa0b5f 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3870,7 +3870,7 @@ getJasmineRequireObj().deprecateMonkeyPatching = function(j$) { }, set(newValue) { j$.getEnv().deprecated( - 'Monkey patching detected. This is not supported and will break in a future jasmine-core release.' + 'Monkey patching detected. Code that overwrites parts of Jasmine, except globala and other properties that are documented as writeable, is not supported and will break in a future release.' ); value = newValue; } diff --git a/src/core/deprecateMonkeyPatching.js b/src/core/deprecateMonkeyPatching.js index ca73e764..0635775b 100644 --- a/src/core/deprecateMonkeyPatching.js +++ b/src/core/deprecateMonkeyPatching.js @@ -11,7 +11,7 @@ getJasmineRequireObj().deprecateMonkeyPatching = function(j$) { }, set(newValue) { j$.getEnv().deprecated( - 'Monkey patching detected. This is not supported and will break in a future jasmine-core release.' + 'Monkey patching detected. Code that overwrites parts of Jasmine, except globala and other properties that are documented as writeable, is not supported and will break in a future release.' ); value = newValue; } From 6755b03f12a0bb5b4c50bec2c5d613bcd953bc2a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 17 Jan 2026 11:25:22 -0800 Subject: [PATCH 14/26] Temporarily (I hope) disable testing against Safari 16 and 17 Saucelabs VMs for these browsers currently fail to start. There was a successful run last night against commit e759ddced260. --- scripts/run-sauce-browsers | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run-sauce-browsers b/scripts/run-sauce-browsers index fc6abd7b..ad4f73da 100755 --- a/scripts/run-sauce-browsers +++ b/scripts/run-sauce-browsers @@ -44,8 +44,8 @@ else fi run_browser firefox 102 -run_browser safari 17 -run_browser safari 16 +# run_browser safari 17 +# run_browser safari 16 run_browser MicrosoftEdge latest From 0a6f6d2b0eb9a1ba7fed54a7721ae99137f5205a Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 17 Jan 2026 11:27:38 -0800 Subject: [PATCH 15/26] Bump version to 6.0.0 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- release_notes/6.0.0.md | 190 ++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 release_notes/6.0.0.md diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 53aa0b5f..89d36cfc 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -12406,5 +12406,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '6.0.0-beta.1'; + return '6.0.0'; }; diff --git a/package.json b/package.json index 6bb4a501..469e5611 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "6.0.0-beta.1", + "version": "6.0.0", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/release_notes/6.0.0.md b/release_notes/6.0.0.md new file mode 100644 index 00000000..83b8bae5 --- /dev/null +++ b/release_notes/6.0.0.md @@ -0,0 +1,190 @@ +# Jasmine Core 6.0.0 Release Notes + +## Summary + +This is a major release that includes breaking changes as well as significant +new features. Many of the breaking changes and deprecations in this release are +intended to improve the stability of the Jasmine ecosystem by making the +distinction between public and private APIs more obvious, reducing exposure of +jasmine-core's internal state, removing ambiguities from the reporter API, and +warning about monkey patching. + +6.x is intended to ba a relatively short-lived, transitional series. It is +compatible with the current versions of karam-jasmine and other legacy Angular +tools but emits deprecation warnings when used with them. 7.0 will drop +compatibility with those tools. If you use Karma in a non-Angular context, +consider migrating to a maintained alternative such as jasmine-browser-runner or +web-test-runner. If you use Angular, please direct any questions about support +for future versions of Jasmine to the Angular team. + +Please see the [migration guide](https://jasmine.github.io/upgrade-guides/6.0) +for more information. If you use Jasmine via the `jasmine` package, please see +[its release notes](https://github.com/jasmine/jasmine-npm/blob/main/release_notes/6.0.0.md) +as well. + + +## Changes to supported environments + +* Node 18 is no longer supported. + + +## Breaking changes + +### General + +* Private APIs have been removed from the `jasmine` namespace. + + The purpose of this change is to reduce the risk of users inadvertently + depending on private APIs. Anything not covered by + [the documentation](https://jasmine.github.io/pages/docs_home.html) remains + private regardless of namespacing. Private APIs may be changed or removed in + any release. This change is being made in a major release as a courtesy to + users of libraries that depend on private APIs. + +### Changes that affect spec writing + +* Global error spies always receive a single argument. Previously, the browser + error event was passed as the second argument. +* If a spy is invoked via `.call(null, ...)` or `.apply(null, ...)`, the spy's + `this` argument will be `null`. Previously it was `globalThis`. +* Mock clock timing functions cannot be spied on. Previously this "worked" but + prevented the mock clock from uninstalling itself. +* The mock clock no longer supports the eval forms of `setTimeout` and + `setInterval`. +* Keys passed to `setSpecProperty`/`setSuiteProperty` must be strings. Values + must be both structured-cloneable and JSON-serializable. + +### Changes that affect configuration + +* HTML reporters cache configuration throughout each run. Configuration changes + made while specs are running will not affect reporter behavior. +* If an execution order is passed to `Env#execute`, it must not enter any suite + more than once. +* The argument passed to spec filters is a + [spec metadata](https://jasmine.github.io/api/6.0/Spec.html) + instance, not the internal spec object. +* The default value of the `forbidDuplicateNames` config option has been + changed to true. + +### Changes that affect reporters + +This release includes changes that are intended to streamline and clarify the +reporter interface, prevent sharing of mutable state, and prevent bugs involving +non-serializable objects. These changes should be compatible with most existing +reporters but could break reporters that manage their internal state in unusual +ways. + +* Meaningless properties such as `status` and `failedExpectations` are omitted + from the events passed to [suiteStarted](https://jasmine.github.io/api/6.0/global.html#SuiteStartedEvent) + and [specStarted](https://jasmine.github.io/api/6.0/global.html#SpecStartedEvent). +* Reporter events are deep-cloned before being passed to each reporter. This + protects reporters against later mutation by jasmine-core or other reporters. +* The `expected` and `actual` properties of + [passed and failed expectations](https://jasmine.github.io/api/6.0/global.html#ExpectationResult) + have been removed. +* The [order](https://jasmine.github.io/api/6.0/global.html#Order) + property of the`jasmineStarted` and `jasmineDone` reporter events no longer + includes undocumented properties. +* boot1.js no longer adds `jsApiReporter` to the env. + +### Changes that affect browser boot files + +* The `createElement` and `createTextNode` options of the legacy `HtmlReporter` + are ignored. `HtmlReporter` now unconditionally uses `document.createElement` + and `document.createTextNode`. + +### Changes to Node boot functions + +* [boot](https://jasmine.github.io/api/6.0/module-jasmine-core.html#.boot) + defaults to creating a new core instance each time it's called. This restores + the pre-5.0 default behavior. +* [noGlobals](https://jasmine.github.io/api/6.0/module-jasmine-core.html#.noGlobals) + no longer takes a parameter. It always returns the same object when called + repeatedly. + + +## New features + +* A new `HtmlReporterV2` with several improvements over the old `HtmlReporter`: + * Clicking a spec/suite link does exact filtering rather than a substring + match. + * The old dots are replaced with a progress bar. This improves usability with + large suites and fixes an accessibility problem. + * Details of failed specs are displayed as soon as each spec finishes. + * A Performance tab shows metrics and a list of the slowest specs. + * Initialization and wire-up in boot files are much simpler. + + If you're using jasmine-browser-runner or copying boot1.js from the standalone + distribution, you'll automatically get the new reporter. If you maintain your + own boot files, you'll get the old reporter unless you update your boot files + to match the one that's in this package. + + The new reporter produces `spec` query string parameters that are different + from those created by the old reporter. If you use other software that + interprets the `spec` parameter, such as karma-jasmine, you won't be able to + adopt `HtmlReporterV2` unlesss that other software is updated. + +* Larger body font size in HTML reporters +* `globalThis` is used to determine the global object during initialization + This makes jasmine-core more tolerant of buggy bundlers or loaders that + cause `this` to be undefined in the global context. +* Experimental [`safariYieldStrategy: "time"`](https://jasmine.github.io/api/6.0/Configuration.html#safariYieldStrategy) + config option, which may make Jasmine run significantly faster in Safari and + similar browsers. So far, this option has not been tested on a wide variety of + workloads. Feedback is appreciated. +* Statically exposed pretty printer as `jasmine.pp()`. + + +## Deprecations + +* Common monkey patching patterns are detected and result in a deprecation + warning. Code that overwrites anything provided by jasmine-core (other than + globals like `it`/`expect`/etc or configuration properties like + `jasmine.DEFAULT_TIMEOUT_INTERVAL`) may be broken by any jasmine-core release. +* Warn if jasmine-core is loaded as an ES module in a browser. + This is an untested and unsupported configuration that has been known to cause + problems. +* `HtmlReporter` and `HtmlSpecFilter` are deprecated in favor of `HtmlReporterV2`. +* `jsApiReporter` is deprecated. + + +## Documentation improvements + +* Improved API reference documentation for APIs that are used from browser boot + files. +* Documented the set of possible spec statuses. +* Documented that globals are overwriteable. + + +## Internal improvements + +* Encapsulated suite and spec result and status management. +* Adopted strict mode throughout the codebase. +* Decomposed `HtmlReporter` into components and converted to ES6 classes. +* Made global error handling more uniform between browsers and Node. +* Removed code to support browsers that don't have `MessageChannel`. Jasmine + hasn't run in any such browsers since 2.x. +* Replaced `isArray` helper with native `Array.isArray`. + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari** | 16, 17, 26.2 | +| Chrome | 143* | +| Firefox | 102**, 115**, 128**, 140, 147* | +| Edge | 143* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From 0c75a154a8d3699bec92101af3a69220ab931652 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 17 Jan 2026 12:00:58 -0800 Subject: [PATCH 16/26] Fix typo --- release_notes/6.0.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release_notes/6.0.0.md b/release_notes/6.0.0.md index 83b8bae5..7051f2a3 100644 --- a/release_notes/6.0.0.md +++ b/release_notes/6.0.0.md @@ -10,7 +10,7 @@ jasmine-core's internal state, removing ambiguities from the reporter API, and warning about monkey patching. 6.x is intended to ba a relatively short-lived, transitional series. It is -compatible with the current versions of karam-jasmine and other legacy Angular +compatible with the current versions of karma-jasmine and other legacy Angular tools but emits deprecation warnings when used with them. 7.0 will drop compatibility with those tools. If you use Karma in a non-Angular context, consider migrating to a maintained alternative such as jasmine-browser-runner or From 87177d9d437c7d5113c599beba0343b043db4d66 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 17 Jan 2026 17:12:32 -0800 Subject: [PATCH 17/26] Fix browser ESM deprecation wraning Previously, the warning was issued if jasmineRequire.core was called from an ES module rather than being defined in an ES module. --- lib/jasmine-core/jasmine.js | 6 ++++-- src/core/requireCore.js | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 89d36cfc..2c4204fb 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -43,6 +43,9 @@ var getJasmineRequireObj = (function() { return jasmineRequire; } + const loadedAsBrowserEsm = + globalThis.document && !globalThis.document.currentScript; + getJasmineRequire().core = function(jRequire) { const j$ = {}; Object.defineProperty(j$, 'private', { @@ -124,8 +127,7 @@ var getJasmineRequireObj = (function() { j$.private.matchers = jRequire.requireMatchers(jRequire, j$); j$.private.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$); - j$.private.loadedAsBrowserEsm = - globalThis.document && !globalThis.document.currentScript; + j$.private.loadedAsBrowserEsm = loadedAsBrowserEsm; j$.private.deprecateMonkeyPatching(j$, [ // These are meant to be set by users. diff --git a/src/core/requireCore.js b/src/core/requireCore.js index e8b70c20..70b08ef6 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -19,6 +19,9 @@ var getJasmineRequireObj = (function() { return jasmineRequire; } + const loadedAsBrowserEsm = + globalThis.document && !globalThis.document.currentScript; + getJasmineRequire().core = function(jRequire) { const j$ = {}; Object.defineProperty(j$, 'private', { @@ -100,8 +103,7 @@ var getJasmineRequireObj = (function() { j$.private.matchers = jRequire.requireMatchers(jRequire, j$); j$.private.asyncMatchers = jRequire.requireAsyncMatchers(jRequire, j$); - j$.private.loadedAsBrowserEsm = - globalThis.document && !globalThis.document.currentScript; + j$.private.loadedAsBrowserEsm = loadedAsBrowserEsm; j$.private.deprecateMonkeyPatching(j$, [ // These are meant to be set by users. From 066669cfeec89ff445c448fc4885f9fc5f4e9375 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sun, 18 Jan 2026 20:51:20 -0800 Subject: [PATCH 18/26] Revert "Temporarily (I hope) disable testing against Safari 16 and 17" This reverts commit 6755b03f12a0bb5b4c50bec2c5d613bcd953bc2a. --- scripts/run-sauce-browsers | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/run-sauce-browsers b/scripts/run-sauce-browsers index ad4f73da..fc6abd7b 100755 --- a/scripts/run-sauce-browsers +++ b/scripts/run-sauce-browsers @@ -44,8 +44,8 @@ else fi run_browser firefox 102 -# run_browser safari 17 -# run_browser safari 16 +run_browser safari 17 +run_browser safari 16 run_browser MicrosoftEdge latest From 4db18aafcee928a313f8d8a521d0fe5578a3ad4b Mon Sep 17 00:00:00 2001 From: Holger Jeromin Date: Mon, 19 Jan 2026 13:41:08 +0100 Subject: [PATCH 19/26] Fix default MAX_PRETTY_PRINT_CHARS in JsDoc --- lib/jasmine-core/jasmine.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2c4204fb..3c22294d 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -222,7 +222,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { * Maximum number of characters to display when pretty printing objects. * Characters past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_CHARS - * @default 100 + * @default 1000 * @since 2.9.0 */ j$.MAX_PRETTY_PRINT_CHARS = 1000; From 7379a3a11b38303bc566610851aa5416cc04f3fb Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 19 Jan 2026 07:59:36 -0800 Subject: [PATCH 20/26] Bump version to 6.0.1 --- lib/jasmine-core/jasmine.js | 2 +- package.json | 2 +- release_notes/6.0.1.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 release_notes/6.0.1.md diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 2c4204fb..b6132e6c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -12408,5 +12408,5 @@ getJasmineRequireObj().UserContext = function(j$) { }; getJasmineRequireObj().version = function() { - return '6.0.0'; + return '6.0.1'; }; diff --git a/package.json b/package.json index 469e5611..7d6b55c2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jasmine-core", "license": "MIT", - "version": "6.0.0", + "version": "6.0.1", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine.git" diff --git a/release_notes/6.0.1.md b/release_notes/6.0.1.md new file mode 100644 index 00000000..f5ec6a0a --- /dev/null +++ b/release_notes/6.0.1.md @@ -0,0 +1,29 @@ +# Jasmine Core 6.0.1 Release Notes + +## Bug fixes + +* Don't emit a deprecation warning when `jasmineRequire.core` is called from an + ES module + +## Supported environments + +This version has been tested in the following environments. + +| Environment | Supported versions | +|-------------------|--------------------------------| +| Node | 20, 22, 24 | +| Safari** | 16, 17, 26.2 | +| Chrome | 143* | +| Firefox | 102**, 115**, 128**, 140, 147* | +| Edge | 143* | + +\* Evergreen browser. Each version of Jasmine is tested against the latest +version available at release time.
+\** Supported on a best-effort basis. Support for these versions may be dropped +if it becomes impractical, and bugs affecting only these versions may not be +treated as release blockers. + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ From 1d0718dc2f48db5a9ffb6ff90f324703b805a58c Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Mon, 19 Jan 2026 14:58:15 -0800 Subject: [PATCH 21/26] Fix MAX_PRETTY_PRINT_CHARS default jsdoc in source code too --- lib/jasmine-core/jasmine.js | 2 +- src/core/base.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b6132e6c..5d5700b9 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -222,7 +222,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { * Maximum number of characters to display when pretty printing objects. * Characters past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_CHARS - * @default 100 + * @default 1000 * @since 2.9.0 */ j$.MAX_PRETTY_PRINT_CHARS = 1000; diff --git a/src/core/base.js b/src/core/base.js index 95d5bdef..3b916fc6 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -22,7 +22,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) { * Maximum number of characters to display when pretty printing objects. * Characters past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_CHARS - * @default 100 + * @default 1000 * @since 2.9.0 */ j$.MAX_PRETTY_PRINT_CHARS = 1000; From 319776d2413f42c3da13d6a605118cdcf775e541 Mon Sep 17 00:00:00 2001 From: Charley Date: Thu, 5 Feb 2026 20:50:32 -0600 Subject: [PATCH 22/26] Report the constituent errors of an AggregateError Fixes #2063 --- spec/core/ExceptionFormatterSpec.js | 167 ++++++++++++++++++ .../integration/ExceptionFormattingSpec.js | 84 +++++++++ src/core/ExceptionFormatter.js | 15 +- 3 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 spec/core/integration/ExceptionFormattingSpec.js diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index 47217fd6..d8c2d94a 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -346,5 +346,172 @@ describe('ExceptionFormatter', function() { }).not.toThrowError(); }); }); + + describe('when the error has an errors array (AggregateError)', function() { + it('includes all aggregated errors in the stack trace', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const error1 = new Error('first error'); + const error2 = new Error('second error'); + const error3 = new Error('third error'); + const aggregateError = new Error('Multiple errors occurred'); + aggregateError.errors = [error1, error2, error3]; + + const lines = subject.stack(aggregateError).split('\n'); + + const error1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: first error') + ); + expect(error1MsgIx) + .withContext('first error message') + .toBeGreaterThan(-1); + + const error2MsgIx = lines.findIndex(line => + line.includes('Error 2: Error: second error') + ); + expect(error2MsgIx) + .withContext('second error message') + .toBeGreaterThan(error1MsgIx); + + const error3MsgIx = lines.findIndex(line => + line.includes('Error 3: Error: third error') + ); + expect(error3MsgIx) + .withContext('third error message') + .toBeGreaterThan(error2MsgIx); + }); + + it('handles AggregateError with single error', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const error1 = new Error('single error'); + const aggregateError = new Error('One error occurred'); + aggregateError.errors = [error1]; + + const lines = subject.stack(aggregateError).split('\n'); + + const error1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: single error') + ); + expect(error1MsgIx).toBeGreaterThan(-1); + }); + + it('handles empty errors array', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const aggregateError = new Error('No errors'); + aggregateError.errors = []; + + expect(function() { + subject.stack(aggregateError); + }).not.toThrowError(); + }); + + it('handles nested AggregateError', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const innerError1 = new Error('inner error 1'); + const innerError2 = new Error('inner error 2'); + const innerAggregate = new Error('Inner aggregate'); + innerAggregate.errors = [innerError1, innerError2]; + + const outerError = new Error('outer error'); + const outerAggregate = new Error('Outer aggregate'); + outerAggregate.errors = [innerAggregate, outerError]; + + const lines = subject.stack(outerAggregate).split('\n'); + + const innerAggMsgIx = lines.findIndex(line => + line.includes('Error 1: Error: Inner aggregate') + ); + expect(innerAggMsgIx).toBeGreaterThan(-1); + + const innerError1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: inner error 1') + ); + expect(innerError1MsgIx).toBeGreaterThan(innerAggMsgIx); + + const innerError2MsgIx = lines.findIndex(line => + line.includes('Error 2: Error: inner error 2') + ); + expect(innerError2MsgIx).toBeGreaterThan(innerError1MsgIx); + + const outerErrorMsgIx = lines.findIndex(line => + line.includes('Error 2: Error: outer error') + ); + expect(outerErrorMsgIx).toBeGreaterThan(innerError2MsgIx); + }); + + it('handles AggregateError containing error with cause', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const rootCause = new Error('root cause'); + const errorWithCause = new Error('error with cause', { + cause: rootCause + }); + const aggregateError = new Error('Aggregate with cause chain'); + aggregateError.errors = [errorWithCause]; + + const lines = subject.stack(aggregateError).split('\n'); + + const error1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: error with cause') + ); + expect(error1MsgIx).toBeGreaterThan(-1); + + const causeMsgIx = lines.findIndex(line => + line.includes('Caused by: Error: root cause') + ); + expect(causeMsgIx).toBeGreaterThan(error1MsgIx); + }); + + it('skips non-Error items in errors array', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const error1 = new Error('real error'); + const aggregateError = new Error('Mixed array'); + aggregateError.errors = [ + error1, + 'string error', + { message: 'object error' }, + null, + undefined, + 42 + ]; + + const lines = subject.stack(aggregateError).split('\n'); + + const error1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: real error') + ); + expect(error1MsgIx).toBeGreaterThan(-1); + + const hasStringError = lines.some(line => + line.includes('string error') + ); + expect(hasStringError).toBe(false); + + const hasObjectError = lines.some(line => + line.includes('object error') + ); + expect(hasObjectError).toBe(false); + }); + + it('works with native AggregateError constructor', function() { + const subject = new privateUnderTest.ExceptionFormatter(); + const error1 = new Error('first error'); + const error2 = new Error('second error'); + const aggregateError = new AggregateError( + [error1, error2], + 'Multiple errors' + ); + + const lines = subject.stack(aggregateError).split('\n'); + + const error1MsgIx = lines.findIndex(line => + line.includes('Error 1: Error: first error') + ); + expect(error1MsgIx).toBeGreaterThan(-1); + + const error2MsgIx = lines.findIndex(line => + line.includes('Error 2: Error: second error') + ); + expect(error2MsgIx).toBeGreaterThan(error1MsgIx); + }); + }); }); }); diff --git a/spec/core/integration/ExceptionFormattingSpec.js b/spec/core/integration/ExceptionFormattingSpec.js new file mode 100644 index 00000000..f8664228 --- /dev/null +++ b/spec/core/integration/ExceptionFormattingSpec.js @@ -0,0 +1,84 @@ +describe('Exception formatting (integration)', function() { + let env; + + beforeEach(function() { + specHelpers.registerIntegrationMatchers(); + env = new privateUnderTest.Env(); + }); + + afterEach(function() { + env.cleanup_(); + }); + + describe('AggregateError formatting', function() { + it('formats AggregateError with individual errors', async function() { + env.it('should format AggregateError with individual errors', function() { + const errors = [ + new Error('Database connection failed'), + new Error('Invalid configuration'), + new Error('Service unavailable') + ]; + throw new AggregateError(errors, 'Multiple initialization errors'); + }); + + const reporter = jasmine.createSpyObj('reporter', ['specDone']); + env.addReporter(reporter); + await env.execute(); + + expect(reporter.specDone).toHaveBeenCalledTimes(1); + const result = reporter.specDone.calls.argsFor(0)[0]; + expect(result.status).toEqual('failed'); + expect(result.failedExpectations.length).toEqual(1); + + const failure = result.failedExpectations[0]; + expect(failure.message).toContain('AggregateError'); + expect(failure.message).toContain('Multiple initialization errors'); + + expect(failure.stack).toContain( + 'Error 1: Error: Database connection failed' + ); + expect(failure.stack).toContain('Error 2: Error: Invalid configuration'); + expect(failure.stack).toContain('Error 3: Error: Service unavailable'); + }); + + it('formats nested AggregateError', async function() { + env.it('should format nested AggregateError', function() { + const innerErrors = [ + new Error('Inner error 1'), + new Error('Inner error 2') + ]; + const innerAggregate = new AggregateError( + innerErrors, + 'Inner operation failed' + ); + + const outerErrors = [ + innerAggregate, + new Error('Outer error'), + new Error('Other outer error') + ]; + throw new AggregateError(outerErrors, 'Multiple operations failed'); + }); + + const reporter = jasmine.createSpyObj('reporter', ['specDone']); + env.addReporter(reporter); + await env.execute(); + + expect(reporter.specDone).toHaveBeenCalledTimes(1); + const result = reporter.specDone.calls.argsFor(0)[0]; + expect(result.status).toEqual('failed'); + + const failure = result.failedExpectations[0]; + + // Firefox & Safari don't preserve types for nested errors + expect(failure.stack).toMatch( + /Error 1: (AggregateError|Error): Inner operation failed/ + ); + expect(failure.stack).toContain('Error 2: Error: Outer error'); + expect(failure.stack).toContain('Error 3: Error: Other outer error'); + + expect(failure.stack).toContain('Error 1: Error: Inner error 1'); + expect(failure.stack).toContain('Error 2: Error: Inner error 2'); + }); + }); +}); diff --git a/src/core/ExceptionFormatter.js b/src/core/ExceptionFormatter.js index 12d73645..933a4b00 100644 --- a/src/core/ExceptionFormatter.js +++ b/src/core/ExceptionFormatter.js @@ -11,7 +11,8 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { 'lineNumber', 'column', 'description', - 'jasmineMessage' + 'jasmineMessage', + 'errors' ]; function ExceptionFormatter(options) { @@ -77,6 +78,18 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { lines = lines.concat(substack); } + if (Array.isArray(error.errors)) { + error.errors.forEach((aggregatedError, index) => { + if (aggregatedError instanceof Error) { + const substack = this.stack_(aggregatedError, { + messageHandling: 'require' + }); + substack[0] = 'Error ' + (index + 1) + ': ' + substack[0]; + lines = lines.concat(substack); + } + }); + } + return lines; }; From b88ce2d49f54f1baa91658509cce1f941a0c62b2 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 7 Feb 2026 11:23:05 -0800 Subject: [PATCH 23/26] Improve AggregateError specs * Assert that the right inner stack traces are in the right places * Drop the integration tests. All of the AggregateError-specific code is in ExceptionFormatter, so the integration tests just duplicate existing integration tests and the ExceptionFormatter specs. --- spec/core/ExceptionFormatterSpec.js | 60 ++++++------- .../integration/ExceptionFormattingSpec.js | 84 ------------------- 2 files changed, 32 insertions(+), 112 deletions(-) delete mode 100644 spec/core/integration/ExceptionFormattingSpec.js diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index d8c2d94a..f468928b 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -350,48 +350,52 @@ describe('ExceptionFormatter', function() { describe('when the error has an errors array (AggregateError)', function() { it('includes all aggregated errors in the stack trace', function() { const subject = new privateUnderTest.ExceptionFormatter(); - const error1 = new Error('first error'); - const error2 = new Error('second error'); - const error3 = new Error('third error'); - const aggregateError = new Error('Multiple errors occurred'); - aggregateError.errors = [error1, error2, error3]; + const error1 = (function fn1() { + return new Error('first error'); + })(); + const error2 = (function fn2() { + return new Error('second error'); + })(); + const aggregateError = (function fn3() { + return new Error('Multiple errors occurred'); + })(); + aggregateError.errors = [error1, error2]; const lines = subject.stack(aggregateError).split('\n'); + // TODO: be consistent across environments about whether the message is + // included in the stack trace + if (lines[0] === 'Error: Multiple errors occurred') { + lines.shift(); + } + + for (let i = 0; i < lines.length; i++) { + jasmine.debugLog(`Line ${i}: ${lines[i]}`); + } + + expect(lines[0]) + .withContext('first stack frame of the overall error') + .toMatch(/fn3.*core\/ExceptionFormatterSpec\.js/); + const error1MsgIx = lines.findIndex(line => line.includes('Error 1: Error: first error') ); expect(error1MsgIx) - .withContext('first error message') + .withContext('first nested error message') .toBeGreaterThan(-1); + expect(lines[error1MsgIx + 1]) + .withContext('first stack frame of first nested error') + .toMatch(/fn1.*core\/ExceptionFormatterSpec\.js/); const error2MsgIx = lines.findIndex(line => line.includes('Error 2: Error: second error') ); expect(error2MsgIx) - .withContext('second error message') + .withContext('second nested error message') .toBeGreaterThan(error1MsgIx); - - const error3MsgIx = lines.findIndex(line => - line.includes('Error 3: Error: third error') - ); - expect(error3MsgIx) - .withContext('third error message') - .toBeGreaterThan(error2MsgIx); - }); - - it('handles AggregateError with single error', function() { - const subject = new privateUnderTest.ExceptionFormatter(); - const error1 = new Error('single error'); - const aggregateError = new Error('One error occurred'); - aggregateError.errors = [error1]; - - const lines = subject.stack(aggregateError).split('\n'); - - const error1MsgIx = lines.findIndex(line => - line.includes('Error 1: Error: single error') - ); - expect(error1MsgIx).toBeGreaterThan(-1); + expect(lines[error2MsgIx + 1]) + .withContext('first stack frame of second nested error') + .toMatch(/fn2.*core\/ExceptionFormatterSpec\.js/); }); it('handles empty errors array', function() { diff --git a/spec/core/integration/ExceptionFormattingSpec.js b/spec/core/integration/ExceptionFormattingSpec.js deleted file mode 100644 index f8664228..00000000 --- a/spec/core/integration/ExceptionFormattingSpec.js +++ /dev/null @@ -1,84 +0,0 @@ -describe('Exception formatting (integration)', function() { - let env; - - beforeEach(function() { - specHelpers.registerIntegrationMatchers(); - env = new privateUnderTest.Env(); - }); - - afterEach(function() { - env.cleanup_(); - }); - - describe('AggregateError formatting', function() { - it('formats AggregateError with individual errors', async function() { - env.it('should format AggregateError with individual errors', function() { - const errors = [ - new Error('Database connection failed'), - new Error('Invalid configuration'), - new Error('Service unavailable') - ]; - throw new AggregateError(errors, 'Multiple initialization errors'); - }); - - const reporter = jasmine.createSpyObj('reporter', ['specDone']); - env.addReporter(reporter); - await env.execute(); - - expect(reporter.specDone).toHaveBeenCalledTimes(1); - const result = reporter.specDone.calls.argsFor(0)[0]; - expect(result.status).toEqual('failed'); - expect(result.failedExpectations.length).toEqual(1); - - const failure = result.failedExpectations[0]; - expect(failure.message).toContain('AggregateError'); - expect(failure.message).toContain('Multiple initialization errors'); - - expect(failure.stack).toContain( - 'Error 1: Error: Database connection failed' - ); - expect(failure.stack).toContain('Error 2: Error: Invalid configuration'); - expect(failure.stack).toContain('Error 3: Error: Service unavailable'); - }); - - it('formats nested AggregateError', async function() { - env.it('should format nested AggregateError', function() { - const innerErrors = [ - new Error('Inner error 1'), - new Error('Inner error 2') - ]; - const innerAggregate = new AggregateError( - innerErrors, - 'Inner operation failed' - ); - - const outerErrors = [ - innerAggregate, - new Error('Outer error'), - new Error('Other outer error') - ]; - throw new AggregateError(outerErrors, 'Multiple operations failed'); - }); - - const reporter = jasmine.createSpyObj('reporter', ['specDone']); - env.addReporter(reporter); - await env.execute(); - - expect(reporter.specDone).toHaveBeenCalledTimes(1); - const result = reporter.specDone.calls.argsFor(0)[0]; - expect(result.status).toEqual('failed'); - - const failure = result.failedExpectations[0]; - - // Firefox & Safari don't preserve types for nested errors - expect(failure.stack).toMatch( - /Error 1: (AggregateError|Error): Inner operation failed/ - ); - expect(failure.stack).toContain('Error 2: Error: Outer error'); - expect(failure.stack).toContain('Error 3: Error: Other outer error'); - - expect(failure.stack).toContain('Error 1: Error: Inner error 1'); - expect(failure.stack).toContain('Error 2: Error: Inner error 2'); - }); - }); -}); From 6af5d24b3b2ef3a242b20113d01891930e76d61d Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 7 Feb 2026 18:22:12 -0800 Subject: [PATCH 24/26] Improve formatting of AggregateErrors --- lib/jasmine-core/jasmine.js | 13 ++++---- spec/core/ExceptionFormatterSpec.js | 46 +++++++++++++++-------------- src/core/ExceptionFormatter.js | 13 ++++---- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6e5406e2..9cf37c8c 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -4071,15 +4071,16 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { } if (Array.isArray(error.errors)) { - error.errors.forEach((aggregatedError, index) => { - if (aggregatedError instanceof Error) { - const substack = this.stack_(aggregatedError, { + for (let i = 0; i < error.errors.length; i++) { + if (error.errors[i] instanceof Error) { + lines.push(''); + const substack = this.stack_(error.errors[i], { messageHandling: 'require' }); - substack[0] = 'Error ' + (index + 1) + ': ' + substack[0]; - lines = lines.concat(substack); + substack[0] = 'Error ' + (i + 1) + ': ' + substack[0]; + lines = lines.concat(substack.map(x => ' ' + x)); } - }); + } } return lines; diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index f468928b..c8aae4ea 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -369,33 +369,35 @@ describe('ExceptionFormatter', function() { lines.shift(); } - for (let i = 0; i < lines.length; i++) { - jasmine.debugLog(`Line ${i}: ${lines[i]}`); + const filteredLines = lines.filter(x => !x.includes('/jasmine.js:')); + + for (let i = 0; i < filteredLines.length; i++) { + jasmine.debugLog(`Line ${i} after filtering: ${filteredLines[i]}`); } - expect(lines[0]) - .withContext('first stack frame of the overall error') - .toMatch(/fn3.*core\/ExceptionFormatterSpec\.js/); + // Inexact matching because stack frame formatting varies from runtime + // to runtime + const expectedPatterns = [ + // Overall error + /fn3.*ExceptionFormatterSpec\.js/, + /ExceptionFormatterSpec\.js/, + /^$/, - const error1MsgIx = lines.findIndex(line => - line.includes('Error 1: Error: first error') - ); - expect(error1MsgIx) - .withContext('first nested error message') - .toBeGreaterThan(-1); - expect(lines[error1MsgIx + 1]) - .withContext('first stack frame of first nested error') - .toMatch(/fn1.*core\/ExceptionFormatterSpec\.js/); + // First nested error + /^ Error 1: Error: first error$/, + /^ .*fn1.*ExceptionFormatterSpec\.js/, + /^ .*ExceptionFormatterSpec\.js/, + /^$/, - const error2MsgIx = lines.findIndex(line => - line.includes('Error 2: Error: second error') + // Second nested error + /^ .*Error 2: Error: second error$/, + /^ .*fn2.*ExceptionFormatterSpec\.js/, + /^ .*ExceptionFormatterSpec\.js/, + ]; + + expect(filteredLines).toEqual( + expectedPatterns.map(p => jasmine.stringMatching(p)), ); - expect(error2MsgIx) - .withContext('second nested error message') - .toBeGreaterThan(error1MsgIx); - expect(lines[error2MsgIx + 1]) - .withContext('first stack frame of second nested error') - .toMatch(/fn2.*core\/ExceptionFormatterSpec\.js/); }); it('handles empty errors array', function() { diff --git a/src/core/ExceptionFormatter.js b/src/core/ExceptionFormatter.js index 933a4b00..2a0f3a82 100644 --- a/src/core/ExceptionFormatter.js +++ b/src/core/ExceptionFormatter.js @@ -79,15 +79,16 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) { } if (Array.isArray(error.errors)) { - error.errors.forEach((aggregatedError, index) => { - if (aggregatedError instanceof Error) { - const substack = this.stack_(aggregatedError, { + for (let i = 0; i < error.errors.length; i++) { + if (error.errors[i] instanceof Error) { + lines.push(''); + const substack = this.stack_(error.errors[i], { messageHandling: 'require' }); - substack[0] = 'Error ' + (index + 1) + ': ' + substack[0]; - lines = lines.concat(substack); + substack[0] = 'Error ' + (i + 1) + ': ' + substack[0]; + lines = lines.concat(substack.map(x => ' ' + x)); } - }); + } } return lines; From 42baa422b3fb28ffc69048e4d36b32667f6257bf Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 7 Feb 2026 18:36:36 -0800 Subject: [PATCH 25/26] Formatting --- spec/core/ExceptionFormatterSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index c8aae4ea..6916fba6 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -392,11 +392,11 @@ describe('ExceptionFormatter', function() { // Second nested error /^ .*Error 2: Error: second error$/, /^ .*fn2.*ExceptionFormatterSpec\.js/, - /^ .*ExceptionFormatterSpec\.js/, + /^ .*ExceptionFormatterSpec\.js/ ]; expect(filteredLines).toEqual( - expectedPatterns.map(p => jasmine.stringMatching(p)), + expectedPatterns.map(p => jasmine.stringMatching(p)) ); }); From 5de03beea14cb40467a22c48007dc1148371ecd7 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 7 Feb 2026 20:03:59 -0800 Subject: [PATCH 26/26] Fix test failure in Node 20 and 22 parallel tests --- spec/core/ExceptionFormatterSpec.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/core/ExceptionFormatterSpec.js b/spec/core/ExceptionFormatterSpec.js index 6916fba6..87b312e2 100644 --- a/spec/core/ExceptionFormatterSpec.js +++ b/spec/core/ExceptionFormatterSpec.js @@ -369,7 +369,13 @@ describe('ExceptionFormatter', function() { lines.shift(); } - const filteredLines = lines.filter(x => !x.includes('/jasmine.js:')); + // Exclude lines that vary from environment to environment + const filteredLines = lines.filter( + x => + !x.includes('/jasmine.js:') && + // Some Node 20 and 22 minors when running in parallel + !x.includes('process.processTicksAndRejections') + ); for (let i = 0; i < filteredLines.length; i++) { jasmine.debugLog(`Line ${i} after filtering: ${filteredLines[i]}`);