jasmine-core 5.5.0 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2008-2019 Pivotal Labs
2
- Copyright (c) 2008-2024 The Jasmine developers
2
+ Copyright (c) 2008-2025 The Jasmine developers
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <a name="README">[<img src="https://rawgithub.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" />](http://jasmine.github.io)</a>
1
+ <a name="README"><img src="https://raw.githubusercontent.com/jasmine/jasmine/main/images/jasmine-horizontal.svg" width="400px" alt="Jasmine"></a>
2
2
 
3
3
  # A JavaScript Testing Framework
4
4
 
@@ -30,7 +30,7 @@ Microsoft Edge) as well as Node.
30
30
  | Environment | Supported versions |
31
31
  |-------------------|----------------------------|
32
32
  | Node | 18, 20, 22 |
33
- | Safari | 15-17 |
33
+ | Safari | 15*, 16*, 17* |
34
34
  | Chrome | Evergreen |
35
35
  | Firefox | Evergreen, 102*, 115*, 128 |
36
36
  | Edge | Evergreen |
@@ -39,9 +39,9 @@ For evergreen browsers, each version of Jasmine is tested against the version of
39
39
  at the time of release. Other browsers, as well as older & newer versions of some supported browsers, are likely to work.
40
40
  However, Jasmine isn't tested against them and they aren't actively supported.
41
41
 
42
- \* Environments that are past end of life are supported on a best-effort basis.
43
- They may be dropped in a future minor release of Jasmine if continued support
44
- becomes impractical.
42
+ \* Supported on a best-effort basis. Support for these versions may be dropped
43
+ if it becomes impractical, and bugs affecting only these versions may not be
44
+ treated as release blockers.
45
45
 
46
46
  To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
47
47
 
@@ -60,5 +60,5 @@ To find out what environments work with a particular Jasmine release, see the [r
60
60
  * Sheel Choksi
61
61
 
62
62
  Copyright (c) 2008-2019 Pivotal Labs<br>
63
- Copyright (c) 2008-2024 The Jasmine developers<br>
63
+ Copyright (c) 2008-2025 The Jasmine developers<br>
64
64
  This software is licensed under the [MIT License](https://github.com/jasmine/jasmine/blob/main/LICENSE).
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  Copyright (c) 2008-2019 Pivotal Labs
3
- Copyright (c) 2008-2024 The Jasmine developers
3
+ Copyright (c) 2008-2025 The Jasmine developers
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -21,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
+
24
25
  /**
25
26
  This file starts the process of "booting" Jasmine. It initializes Jasmine,
26
27
  makes its globals available, and creates the env. This file should be loaded
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  Copyright (c) 2008-2019 Pivotal Labs
3
- Copyright (c) 2008-2024 The Jasmine developers
3
+ Copyright (c) 2008-2025 The Jasmine developers
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -21,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
+
24
25
  /**
25
26
  This file finishes 'booting' Jasmine, performing all of the necessary
26
27
  initialization before executing the loaded environment and all of a project's
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  Copyright (c) 2008-2019 Pivotal Labs
3
- Copyright (c) 2008-2024 The Jasmine developers
3
+ Copyright (c) 2008-2025 The Jasmine developers
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -21,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
+
24
25
  // eslint-disable-next-line no-var
25
26
  var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
26
27
 
@@ -155,8 +156,10 @@ jasmineRequire.HtmlReporter = function(j$) {
155
156
  if (noExpectations(result)) {
156
157
  const noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
157
158
  if (result.status === 'failed') {
159
+ // eslint-disable-next-line no-console
158
160
  console.error(noSpecMsg);
159
161
  } else {
162
+ // eslint-disable-next-line no-console
160
163
  console.warn(noSpecMsg);
161
164
  }
162
165
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  Copyright (c) 2008-2019 Pivotal Labs
3
- Copyright (c) 2008-2024 The Jasmine developers
3
+ Copyright (c) 2008-2025 The Jasmine developers
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -21,6 +21,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
+
24
25
  // eslint-disable-next-line no-unused-vars,no-var
25
26
  var getJasmineRequireObj = (function(jasmineGlobal) {
26
27
  let jasmineRequire;
@@ -150,6 +151,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
150
151
  'toBeTrue',
151
152
  'toBeTruthy',
152
153
  'toBeUndefined',
154
+ 'toBeNullish',
153
155
  'toContain',
154
156
  'toEqual',
155
157
  'toHaveSize',
@@ -159,7 +161,9 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
159
161
  'toHaveBeenCalledTimes',
160
162
  'toHaveBeenCalledWith',
161
163
  'toHaveClass',
164
+ 'toHaveClasses',
162
165
  'toHaveSpyInteractions',
166
+ 'toHaveNoOtherSpyInteractions',
163
167
  'toMatch',
164
168
  'toThrow',
165
169
  'toThrowError',
@@ -788,11 +792,11 @@ getJasmineRequireObj().Spec = function(j$) {
788
792
  this.onStart = attrs.onStart || function() {};
789
793
  this.autoCleanClosures =
790
794
  attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
791
- this.getSpecName =
792
- attrs.getSpecName ||
793
- function() {
794
- return '';
795
- };
795
+
796
+ this.getPath = function() {
797
+ return attrs.getPath ? attrs.getPath(this) : [];
798
+ };
799
+
796
800
  this.onLateError = attrs.onLateError || function() {};
797
801
  this.catchingExceptions =
798
802
  attrs.catchingExceptions ||
@@ -915,6 +919,9 @@ getJasmineRequireObj().Spec = function(j$) {
915
919
  * @property {String} fullName - The full description including all ancestors of this spec.
916
920
  * @property {String|null} parentSuiteId - The ID of the suite containing this spec, or null if this spec is not in a describe().
917
921
  * @property {String} filename - The name of the file the spec was defined in.
922
+ * Note: The value may be incorrect if zone.js is installed or
923
+ * `it`/`fit`/`xit` have been replaced with versions that don't maintain the
924
+ * same call stack height as the originals.
918
925
  * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed during execution of this spec.
919
926
  * @property {ExpectationResult[]} passedExpectations - The list of expectations that passed during execution of this spec.
920
927
  * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
@@ -1018,7 +1025,7 @@ getJasmineRequireObj().Spec = function(j$) {
1018
1025
  };
1019
1026
 
1020
1027
  Spec.prototype.getFullName = function() {
1021
- return this.getSpecName(this);
1028
+ return this.getPath().join(' ');
1022
1029
  };
1023
1030
 
1024
1031
  Spec.prototype.addDeprecationWarning = function(deprecation) {
@@ -1072,6 +1079,10 @@ getJasmineRequireObj().Spec = function(j$) {
1072
1079
  * @since 2.0.0
1073
1080
  */
1074
1081
  Object.defineProperty(Spec.prototype, 'metadata', {
1082
+ // NOTE: Although most of jasmine-core only exposes these metadata objects,
1083
+ // actual Spec instances are still passed to Configuration#specFilter. Until
1084
+ // that is fixed, it's important to make sure that all metadata properties
1085
+ // also exist in compatible form on the underlying Spec.
1075
1086
  get: function() {
1076
1087
  if (!this.metadata_) {
1077
1088
  this.metadata_ = {
@@ -1100,7 +1111,16 @@ getJasmineRequireObj().Spec = function(j$) {
1100
1111
  * @returns {string}
1101
1112
  * @since 2.0.0
1102
1113
  */
1103
- getFullName: this.getFullName.bind(this)
1114
+ getFullName: this.getFullName.bind(this),
1115
+
1116
+ /**
1117
+ * The full path of the spec, as an array of names.
1118
+ * @name Spec#getPath
1119
+ * @function
1120
+ * @returns {Array.<string>}
1121
+ * @since 5.7.0
1122
+ */
1123
+ getPath: this.getPath.bind(this)
1104
1124
  };
1105
1125
  }
1106
1126
 
@@ -1542,7 +1562,9 @@ getJasmineRequireObj().Env = function(j$) {
1542
1562
 
1543
1563
  // If we get here, all results have been reported and there's nothing we
1544
1564
  // can do except log the result and hope the user sees it.
1565
+ // eslint-disable-next-line no-console
1545
1566
  console.error('Jasmine received a result after the suite finished:');
1567
+ // eslint-disable-next-line no-console
1546
1568
  console.error(expectationResult);
1547
1569
  }
1548
1570
 
@@ -2690,7 +2712,8 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
2690
2712
  * in a future release. In many Jasmine configurations they are passed
2691
2713
  * through JSON serialization and deserialization, which is inherently
2692
2714
  * lossy. In such cases, the expected and actual values may be placeholders
2693
- * or approximations of the original objects.
2715
+ * or approximations of the original objects. jasmine-browser-runner 3.0 and
2716
+ * later omits them entirely.
2694
2717
  *
2695
2718
  * @typedef ExpectationResult
2696
2719
  * @property {String} matcherName - The name of the matcher that was executed for this expectation.
@@ -2896,6 +2919,10 @@ getJasmineRequireObj().CallTracker = function(j$) {
2896
2919
  this.saveArgumentsByValue = function() {
2897
2920
  opts.cloneArgs = true;
2898
2921
  };
2922
+
2923
+ this.unverifiedCount = function() {
2924
+ return calls.reduce((count, call) => count + (call.verified ? 0 : 1), 0);
2925
+ };
2899
2926
  }
2900
2927
 
2901
2928
  return CallTracker;
@@ -3058,6 +3085,15 @@ getJasmineRequireObj().Clock = function() {
3058
3085
  let installed = false;
3059
3086
  let delayedFunctionScheduler;
3060
3087
  let timer;
3088
+ // Tracks how the clock ticking behaves.
3089
+ // By default, the clock only ticks when the user manually calls a tick method.
3090
+ // There is also an 'auto' mode which will advance the clock automatically to
3091
+ // to the next task. Once enabled, there is currently no mechanism for users
3092
+ // to disable the auto ticking.
3093
+ let tickMode = {
3094
+ mode: 'manual',
3095
+ counter: 0
3096
+ };
3061
3097
 
3062
3098
  this.FakeTimeout = FakeTimeout;
3063
3099
 
@@ -3167,8 +3203,98 @@ getJasmineRequireObj().Clock = function() {
3167
3203
  }
3168
3204
  };
3169
3205
 
3206
+ /**
3207
+ * Updates the clock to automatically advance time.
3208
+ *
3209
+ * With this mode, the clock advances to the first scheduled timer and fires it, in a loop.
3210
+ * Between each timer, it will also break the event loop, allowing any scheduled promise
3211
+ callbacks to execute _before_ running the next one.
3212
+ *
3213
+ * This mode allows tests to be authored in a way that does not need to be aware of the
3214
+ * mock clock. Consequently, tests which have been authored without a mock clock installed
3215
+ * can one with auto tick enabled without any other updates to the test logic.
3216
+ *
3217
+ * In many cases, this can greatly improve test execution speed because asynchronous tasks
3218
+ * will execute as quickly as possible rather than waiting real time to complete.
3219
+ *
3220
+ * Furthermore, tests can be authored in a consistent manner. They can always be written in an asynchronous style
3221
+ * rather than having `tick` sprinkled throughout the tests with mock time in order to manually
3222
+ * advance the clock.
3223
+ *
3224
+ * When auto tick is enabled, `tick` can still be used to synchronously advance the clock if necessary.
3225
+ * @name Clock#autoTick
3226
+ * @function
3227
+ * @since 5.7.0
3228
+ */
3229
+ this.autoTick = function() {
3230
+ if (tickMode.mode === 'auto') {
3231
+ return;
3232
+ }
3233
+
3234
+ tickMode = { mode: 'auto', counter: tickMode.counter + 1 };
3235
+ advanceUntilModeChanges();
3236
+ };
3237
+
3170
3238
  return this;
3171
3239
 
3240
+ // Advances the Clock's time until the mode changes.
3241
+ //
3242
+ // The time is advanced asynchronously, giving microtasks and events a chance
3243
+ // to run before each timer runs.
3244
+ //
3245
+ // @function
3246
+ // @return {!Promise<undefined>}
3247
+ async function advanceUntilModeChanges() {
3248
+ if (!installed) {
3249
+ throw new Error(
3250
+ 'Mock clock is not installed, use jasmine.clock().install()'
3251
+ );
3252
+ }
3253
+ const { counter } = tickMode;
3254
+
3255
+ while (true) {
3256
+ await newMacrotask();
3257
+
3258
+ if (
3259
+ tickMode.counter !== counter ||
3260
+ !installed ||
3261
+ delayedFunctionScheduler === null
3262
+ ) {
3263
+ return;
3264
+ }
3265
+
3266
+ if (!delayedFunctionScheduler.isEmpty()) {
3267
+ delayedFunctionScheduler.runNextQueuedFunction(function(millis) {
3268
+ mockDate.tick(millis);
3269
+ });
3270
+ }
3271
+ }
3272
+ }
3273
+
3274
+ // Waits until a new macro task.
3275
+ //
3276
+ // Used with autoTick(), which is meant to act when the test is waiting, we need
3277
+ // to insert ourselves in the macro task queue.
3278
+ //
3279
+ // @return {!Promise<undefined>}
3280
+ async function newMacrotask() {
3281
+ // MessageChannel ensures that setTimeout is not throttled to 4ms.
3282
+ // https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
3283
+ // https://stackblitz.com/edit/stackblitz-starters-qtlpcc
3284
+ // Note: This trick does not work in Safari, which will still throttle the setTimeout
3285
+ const channel = new MessageChannel();
3286
+ await new Promise(resolve => {
3287
+ channel.port1.onmessage = resolve;
3288
+ channel.port2.postMessage(undefined);
3289
+ });
3290
+ channel.port1.close();
3291
+ channel.port2.close();
3292
+ // setTimeout ensures that we interleave with other setTimeouts.
3293
+ await new Promise(resolve => {
3294
+ realTimingFunctions.setTimeout.call(global, resolve);
3295
+ });
3296
+ }
3297
+
3172
3298
  function originalTimingFunctionsIntact() {
3173
3299
  return (
3174
3300
  global.setTimeout === realTimingFunctions.setTimeout &&
@@ -3399,6 +3525,37 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
3399
3525
  }
3400
3526
  };
3401
3527
 
3528
+ // Returns whether there are any scheduled functions.
3529
+ // Returns true if there are any scheduled functions, otherwise false.
3530
+ this.isEmpty = function() {
3531
+ return this.scheduledFunctions_.length === 0;
3532
+ };
3533
+
3534
+ // Runs the next timeout in the queue, advancing the clock.
3535
+ this.runNextQueuedFunction = function(tickDate) {
3536
+ if (this.scheduledLookup_.length === 0) {
3537
+ return;
3538
+ }
3539
+
3540
+ const newCurrentTime = this.scheduledLookup_[0];
3541
+ if (newCurrentTime >= this.currentTime_) {
3542
+ tickDate(newCurrentTime - this.currentTime_);
3543
+ this.currentTime_ = newCurrentTime;
3544
+ }
3545
+
3546
+ const funcsAtTime = this.scheduledFunctions_[this.currentTime_];
3547
+ const fn = funcsAtTime.shift();
3548
+ if (funcsAtTime.length === 0) {
3549
+ delete this.scheduledFunctions_[this.currentTime_];
3550
+ this.scheduledLookup_.splice(0, 1);
3551
+ }
3552
+
3553
+ if (fn.recurring) {
3554
+ this.reschedule_(fn);
3555
+ }
3556
+ fn.funcToCall.apply(null, fn.params || []);
3557
+ };
3558
+
3402
3559
  return this;
3403
3560
  }
3404
3561
 
@@ -3535,6 +3692,7 @@ getJasmineRequireObj().Deprecator = function(j$) {
3535
3692
 
3536
3693
  Deprecator.prototype.log_ = function(runnable, deprecation, options) {
3537
3694
  if (j$.isError_(deprecation)) {
3695
+ // eslint-disable-next-line no-console
3538
3696
  console.error(deprecation);
3539
3697
  return;
3540
3698
  }
@@ -3557,6 +3715,7 @@ getJasmineRequireObj().Deprecator = function(j$) {
3557
3715
  context += '\n' + verboseNote;
3558
3716
  }
3559
3717
 
3718
+ // eslint-disable-next-line no-console
3560
3719
  console.error('DEPRECATION: ' + deprecation + context);
3561
3720
  };
3562
3721
 
@@ -4332,7 +4491,9 @@ getJasmineRequireObj().toBePending = function(j$) {
4332
4491
  return {
4333
4492
  compare: function(actual) {
4334
4493
  if (!j$.isPromiseLike(actual)) {
4335
- throw new Error('Expected toBePending to be called on a promise.');
4494
+ throw new Error(
4495
+ `Expected toBePending to be called on a promise but was on a ${typeof actual}.`
4496
+ );
4336
4497
  }
4337
4498
  const want = {};
4338
4499
  return Promise.race([actual, Promise.resolve(want)]).then(
@@ -4364,7 +4525,9 @@ getJasmineRequireObj().toBeRejected = function(j$) {
4364
4525
  return {
4365
4526
  compare: function(actual) {
4366
4527
  if (!j$.isPromiseLike(actual)) {
4367
- throw new Error('Expected toBeRejected to be called on a promise.');
4528
+ throw new Error(
4529
+ `Expected toBeRejected to be called on a promise but was on a ${typeof actual}.`
4530
+ );
4368
4531
  }
4369
4532
  return actual.then(
4370
4533
  function() {
@@ -4397,7 +4560,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
4397
4560
  compare: function(actualPromise, expectedValue) {
4398
4561
  if (!j$.isPromiseLike(actualPromise)) {
4399
4562
  throw new Error(
4400
- 'Expected toBeRejectedWith to be called on a promise.'
4563
+ `Expected toBeRejectedWith to be called on a promise but was on a ${typeof actualPromise}.`
4401
4564
  );
4402
4565
  }
4403
4566
 
@@ -4461,7 +4624,7 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
4461
4624
  compare: function(actualPromise, arg1, arg2) {
4462
4625
  if (!j$.isPromiseLike(actualPromise)) {
4463
4626
  throw new Error(
4464
- 'Expected toBeRejectedWithError to be called on a promise.'
4627
+ `Expected toBeRejectedWithError to be called on a promise but was on a ${typeof actualPromise}.`
4465
4628
  );
4466
4629
  }
4467
4630
 
@@ -4579,7 +4742,9 @@ getJasmineRequireObj().toBeResolved = function(j$) {
4579
4742
  return {
4580
4743
  compare: function(actual) {
4581
4744
  if (!j$.isPromiseLike(actual)) {
4582
- throw new Error('Expected toBeResolved to be called on a promise.');
4745
+ throw new Error(
4746
+ `Expected toBeResolved to be called on a promise but was on a ${typeof actual}.`
4747
+ );
4583
4748
  }
4584
4749
 
4585
4750
  return actual.then(
@@ -4619,7 +4784,9 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
4619
4784
  return {
4620
4785
  compare: function(actualPromise, expectedValue) {
4621
4786
  if (!j$.isPromiseLike(actualPromise)) {
4622
- throw new Error('Expected toBeResolvedTo to be called on a promise.');
4787
+ throw new Error(
4788
+ `Expected toBeResolvedTo to be called on a promise but was on a ${typeof actualPromise}.`
4789
+ );
4623
4790
  }
4624
4791
 
4625
4792
  function prefix(passed) {
@@ -5846,6 +6013,7 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) {
5846
6013
  try {
5847
6014
  expectedMatcher = new j$.Any(expected);
5848
6015
  pass = expectedMatcher.asymmetricMatch(actual);
6016
+ // eslint-disable-next-line no-unused-vars
5849
6017
  } catch (error) {
5850
6018
  throw new Error(
5851
6019
  usageError('Expected value is not a constructor function')
@@ -6010,6 +6178,28 @@ getJasmineRequireObj().toBeNull = function() {
6010
6178
  return toBeNull;
6011
6179
  };
6012
6180
 
6181
+ getJasmineRequireObj().toBeNullish = function() {
6182
+ /**
6183
+ * {@link expect} the actual value to be `null` or `undefined`.
6184
+ * @function
6185
+ * @name matchers#toBeNullish
6186
+ * @since 5.6.0
6187
+ * @example
6188
+ * expect(result).toBeNullish():
6189
+ */
6190
+ function toBeNullish() {
6191
+ return {
6192
+ compare: function(actual) {
6193
+ return {
6194
+ pass: null === actual || void 0 === actual
6195
+ };
6196
+ }
6197
+ };
6198
+ }
6199
+
6200
+ return toBeNullish;
6201
+ };
6202
+
6013
6203
  getJasmineRequireObj().toBePositiveInfinity = function(j$) {
6014
6204
  /**
6015
6205
  * {@link expect} the actual value to be `Infinity` (infinity).
@@ -6199,6 +6389,8 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
6199
6389
 
6200
6390
  result.pass = actual.calls.any();
6201
6391
 
6392
+ actual.calls.all().forEach(call => (call.verified = true));
6393
+
6202
6394
  result.message = result.pass
6203
6395
  ? 'Expected spy ' + actual.and.identity + ' not to have been called.'
6204
6396
  : 'Expected spy ' + actual.and.identity + ' to have been called.';
@@ -6263,6 +6455,9 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
6263
6455
  result.pass = latest1stSpyCall < first2ndSpyCall;
6264
6456
 
6265
6457
  if (result.pass) {
6458
+ firstSpy.calls.mostRecent().verified = true;
6459
+ latterSpy.calls.first().verified = true;
6460
+
6266
6461
  result.message =
6267
6462
  'Expected spy ' +
6268
6463
  firstSpy.and.identity +
@@ -6319,7 +6514,7 @@ getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
6319
6514
  * @example
6320
6515
  * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2);
6321
6516
  */
6322
- function toHaveBeenCalledOnceWith(util) {
6517
+ function toHaveBeenCalledOnceWith(matchersUtil) {
6323
6518
  return {
6324
6519
  compare: function() {
6325
6520
  const args = Array.prototype.slice.call(arguments, 0),
@@ -6328,20 +6523,29 @@ getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
6328
6523
 
6329
6524
  if (!j$.isSpy(actual)) {
6330
6525
  throw new Error(
6331
- getErrorMsg('Expected a spy, but got ' + util.pp(actual) + '.')
6526
+ getErrorMsg(
6527
+ 'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
6528
+ )
6332
6529
  );
6333
6530
  }
6334
6531
 
6335
6532
  const prettyPrintedCalls = actual.calls
6336
6533
  .allArgs()
6337
6534
  .map(function(argsForCall) {
6338
- return ' ' + util.pp(argsForCall);
6535
+ return ' ' + matchersUtil.pp(argsForCall);
6339
6536
  });
6340
6537
 
6341
6538
  if (
6342
6539
  actual.calls.count() === 1 &&
6343
- util.contains(actual.calls.allArgs(), expectedArgs)
6540
+ matchersUtil.contains(actual.calls.allArgs(), expectedArgs)
6344
6541
  ) {
6542
+ const firstIndex = actual.calls
6543
+ .all()
6544
+ .findIndex(call => matchersUtil.equals(call.args, expectedArgs));
6545
+ if (firstIndex > -1) {
6546
+ actual.calls.all()[firstIndex].verified = true;
6547
+ }
6548
+
6345
6549
  return {
6346
6550
  pass: true,
6347
6551
  message:
@@ -6349,7 +6553,7 @@ getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
6349
6553
  actual.and.identity +
6350
6554
  ' to have been called 0 times, multiple times, or once, but with arguments different from:\n' +
6351
6555
  ' ' +
6352
- util.pp(expectedArgs) +
6556
+ matchersUtil.pp(expectedArgs) +
6353
6557
  '\n' +
6354
6558
  'But the actual call was:\n' +
6355
6559
  prettyPrintedCalls.join(',\n') +
@@ -6360,7 +6564,7 @@ getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
6360
6564
  function getDiffs() {
6361
6565
  return actual.calls.allArgs().map(function(argsForCall, callIx) {
6362
6566
  const diffBuilder = new j$.DiffBuilder();
6363
- util.equals(argsForCall, expectedArgs, diffBuilder);
6567
+ matchersUtil.equals(argsForCall, expectedArgs, diffBuilder);
6364
6568
  return diffBuilder.getMessage();
6365
6569
  });
6366
6570
  }
@@ -6393,7 +6597,7 @@ getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
6393
6597
  actual.and.identity +
6394
6598
  ' to have been called only once, and with given args:\n' +
6395
6599
  ' ' +
6396
- util.pp(expectedArgs) +
6600
+ matchersUtil.pp(expectedArgs) +
6397
6601
  '\n' +
6398
6602
  butString()
6399
6603
  };
@@ -6442,23 +6646,35 @@ getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
6442
6646
  }
6443
6647
 
6444
6648
  actual = args[0];
6445
- const calls = actual.calls.count();
6649
+
6650
+ const callsCount = actual.calls.count();
6446
6651
  const timesMessage = expected === 1 ? 'once' : expected + ' times';
6447
- result.pass = calls === expected;
6652
+
6653
+ result.pass = callsCount === expected;
6654
+
6655
+ if (result.pass) {
6656
+ const allCalls = actual.calls.all();
6657
+ const max = Math.min(expected, callsCount);
6658
+
6659
+ for (let i = 0; i < max; i++) {
6660
+ allCalls[i].verified = true;
6661
+ }
6662
+ }
6663
+
6448
6664
  result.message = result.pass
6449
6665
  ? 'Expected spy ' +
6450
6666
  actual.and.identity +
6451
6667
  ' not to have been called ' +
6452
6668
  timesMessage +
6453
6669
  '. It was called ' +
6454
- calls +
6670
+ callsCount +
6455
6671
  ' times.'
6456
6672
  : 'Expected spy ' +
6457
6673
  actual.and.identity +
6458
6674
  ' to have been called ' +
6459
6675
  timesMessage +
6460
6676
  '. It was called ' +
6461
- calls +
6677
+ callsCount +
6462
6678
  ' times.';
6463
6679
  return result;
6464
6680
  }
@@ -6514,6 +6730,11 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
6514
6730
  }
6515
6731
 
6516
6732
  if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) {
6733
+ actual.calls
6734
+ .all()
6735
+ .filter(call => matchersUtil.equals(call.args, expectedArgs))
6736
+ .forEach(call => (call.verified = true));
6737
+
6517
6738
  result.pass = true;
6518
6739
  result.message = function() {
6519
6740
  return (
@@ -6605,6 +6826,127 @@ getJasmineRequireObj().toHaveClass = function(j$) {
6605
6826
  return toHaveClass;
6606
6827
  };
6607
6828
 
6829
+ getJasmineRequireObj().toHaveClasses = function(j$) {
6830
+ /**
6831
+ * {@link expect} the actual value to be a DOM element that has the expected classes
6832
+ * @function
6833
+ * @name matchers#toHaveClasses
6834
+ * @since 5.6.0
6835
+ * @param {Object} expected - The class names to test for
6836
+ * @example
6837
+ * const el = document.createElement('div');
6838
+ * el.className = 'foo bar baz';
6839
+ * expect(el).toHaveClasses(['bar', 'baz']);
6840
+ */
6841
+ function toHaveClasses(matchersUtil) {
6842
+ return {
6843
+ compare: function(actual, expected) {
6844
+ if (!isElement(actual)) {
6845
+ throw new Error(matchersUtil.pp(actual) + ' is not a DOM element');
6846
+ }
6847
+
6848
+ return {
6849
+ pass: expected.every(e => actual.classList.contains(e))
6850
+ };
6851
+ }
6852
+ };
6853
+ }
6854
+
6855
+ function isElement(maybeEl) {
6856
+ return (
6857
+ maybeEl && maybeEl.classList && j$.isFunction_(maybeEl.classList.contains)
6858
+ );
6859
+ }
6860
+
6861
+ return toHaveClasses;
6862
+ };
6863
+
6864
+ getJasmineRequireObj().toHaveNoOtherSpyInteractions = function(j$) {
6865
+ const getErrorMsg = j$.formatErrorMsg(
6866
+ '<toHaveNoOtherSpyInteractions>',
6867
+ 'expect(<spyObj>).toHaveNoOtherSpyInteractions()'
6868
+ );
6869
+
6870
+ /**
6871
+ * {@link expect} the actual (a {@link SpyObj}) spies to have not been called except interactions which was already tracked with `toHaveBeenCalled`.
6872
+ * @function
6873
+ * @name matchers#toHaveNoOtherSpyInteractions
6874
+ * @example
6875
+ * expect(mySpyObj).toHaveNoOtherSpyInteractions();
6876
+ * expect(mySpyObj).not.toHaveNoOtherSpyInteractions();
6877
+ */
6878
+ function toHaveNoOtherSpyInteractions(matchersUtil) {
6879
+ return {
6880
+ compare: function(actual) {
6881
+ const result = {};
6882
+
6883
+ if (!j$.isObject_(actual)) {
6884
+ throw new Error(
6885
+ getErrorMsg('Expected an object, but got ' + typeof actual + '.')
6886
+ );
6887
+ }
6888
+
6889
+ if (arguments.length > 1) {
6890
+ throw new Error(getErrorMsg('Does not take arguments'));
6891
+ }
6892
+
6893
+ result.pass = true;
6894
+ let hasSpy = false;
6895
+ const unexpectedCalls = [];
6896
+
6897
+ for (const spy of Object.values(actual)) {
6898
+ if (!j$.isSpy(spy)) {
6899
+ continue;
6900
+ }
6901
+
6902
+ hasSpy = true;
6903
+
6904
+ const unverifiedCalls = spy.calls
6905
+ .all()
6906
+ .filter(call => !call.verified);
6907
+
6908
+ if (unverifiedCalls.length > 0) {
6909
+ result.pass = false;
6910
+ }
6911
+
6912
+ unverifiedCalls.forEach(unverifiedCall => {
6913
+ unexpectedCalls.push([
6914
+ spy.and.identity,
6915
+ matchersUtil.pp(unverifiedCall.args)
6916
+ ]);
6917
+ });
6918
+ }
6919
+
6920
+ if (!hasSpy) {
6921
+ throw new Error(
6922
+ getErrorMsg(
6923
+ 'Expected an object with spies, but object has no spies.'
6924
+ )
6925
+ );
6926
+ }
6927
+
6928
+ if (result.pass) {
6929
+ result.message =
6930
+ "Expected a spy object to have other spy interactions but it didn't.";
6931
+ } else {
6932
+ const ppUnexpectedCalls = unexpectedCalls
6933
+ .map(([spyName, args]) => ` ${spyName} called with ${args}`)
6934
+ .join(',\n');
6935
+
6936
+ result.message =
6937
+ 'Expected a spy object to have no other spy interactions, but it had the following calls:\n' +
6938
+ ppUnexpectedCalls +
6939
+ '.';
6940
+ }
6941
+
6942
+ return result;
6943
+ }
6944
+ };
6945
+ }
6946
+
6947
+ return toHaveNoOtherSpyInteractions;
6948
+ };
6949
+
6608
6950
  getJasmineRequireObj().toHaveSize = function(j$) {
6609
6951
  /**
6610
6952
  * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size.
@@ -7429,6 +7771,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
7429
7771
  ) {
7430
7772
  try {
7431
7773
  this.emitScalar(value.toString());
7774
+ // eslint-disable-next-line no-unused-vars
7432
7775
  } catch (e) {
7433
7776
  this.emitScalar('has-invalid-toString-method');
7434
7777
  }
@@ -7675,6 +8018,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
7675
8018
  value.toString !== Object.prototype.toString &&
7676
8019
  value.toString() !== Object.prototype.toString.call(value)
7677
8020
  );
8021
+ // eslint-disable-next-line no-unused-vars
7678
8022
  } catch (e) {
7679
8023
  // The custom toString() threw.
7680
8024
  return true;
@@ -7753,6 +8097,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7753
8097
  }
7754
8098
 
7755
8099
  function fallbackOnMultipleDone() {
8100
+ // eslint-disable-next-line no-console
7756
8101
  console.error(
7757
8102
  new Error(
7758
8103
  "An asynchronous function called its 'done' " +
@@ -7866,6 +8211,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7866
8211
  // Any error we catch here is probably due to a bug in Jasmine,
7867
8212
  // and it's not likely to end up anywhere useful if we let it
7868
8213
  // propagate. Log it so it can at least show up when debugging.
8214
+ // eslint-disable-next-line no-console
7869
8215
  console.error(error);
7870
8216
  }
7871
8217
  }
@@ -9183,7 +9529,8 @@ getJasmineRequireObj().Spy = function(j$) {
9183
9529
  const callData = {
9184
9530
  object: context,
9185
9531
  invocationOrder: nextOrder(),
9186
- args: Array.prototype.slice.apply(args)
9532
+ args: Array.prototype.slice.apply(args),
9533
+ verified: false
9187
9534
  };
9188
9535
 
9189
9536
  callTracker.track(callData);
@@ -9704,6 +10051,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
9704
10051
  let value;
9705
10052
  try {
9706
10053
  value = obj[prop];
10054
+ // eslint-disable-next-line no-unused-vars
9707
10055
  } catch (e) {
9708
10056
  return false;
9709
10057
  }
@@ -10136,6 +10484,9 @@ getJasmineRequireObj().Suite = function(j$) {
10136
10484
  * @property {String} fullName - The full description including all ancestors of this suite.
10137
10485
  * @property {String|null} parentSuiteId - The ID of the suite containing this suite, or null if this is not in another describe().
10138
10486
  * @property {String} filename - The name of the file the suite was defined in.
10487
+ * Note: The value may be incorrect if zone.js is installed or
10488
+ * `describe`/`fdescribe`/`xdescribe` have been replaced with versions that
10489
+ * don't maintain the same call stack height as the originals.
10139
10490
  * @property {ExpectationResult[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
10140
10491
  * @property {ExpectationResult[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
10141
10492
  * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
@@ -10618,9 +10969,7 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
10618
10969
  resultCallback: (result, next) => {
10619
10970
  this.specResultCallback_(spec, result, next);
10620
10971
  },
10621
- getSpecName: function(spec) {
10622
- return getSpecName(spec, suite);
10623
- },
10972
+ getPath: spec => this.getSpecPath_(spec, suite),
10624
10973
  onStart: (spec, next) => this.specStarted_(spec, suite, next),
10625
10974
  description: description,
10626
10975
  userContext: function() {
@@ -10637,6 +10986,17 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
10637
10986
  return spec;
10638
10987
  }
10639
10988
 
10989
+ getSpecPath_(spec, suite) {
10990
+ const path = [spec.description];
10991
+
10992
+ while (suite && suite !== this.topSuite) {
10993
+ path.unshift(suite.description);
10994
+ suite = suite.parentSuite;
10995
+ }
10996
+
10997
+ return path;
10998
+ }
10999
+
10640
11000
  unfocusAncestor_() {
10641
11001
  const focusedAncestor = findFocusedAncestor(
10642
11002
  this.currentDeclarationSuite_
@@ -10700,16 +11060,6 @@ getJasmineRequireObj().SuiteBuilder = function(j$) {
10700
11060
  };
10701
11061
  }
10702
11062
 
10703
- function getSpecName(spec, suite) {
10704
- const fullName = [spec.description],
10705
- suiteFullName = suite.getFullName();
10706
-
10707
- if (suiteFullName !== '') {
10708
- fullName.unshift(suiteFullName);
10709
- }
10710
- return fullName.join(' ');
10711
- }
10712
-
10713
11063
  return SuiteBuilder;
10714
11064
  };
10715
11065
 
@@ -11041,5 +11391,5 @@ getJasmineRequireObj().UserContext = function(j$) {
11041
11391
  };
11042
11392
 
11043
11393
  getJasmineRequireObj().version = function() {
11044
- return '5.5.0';
11394
+ return '5.7.0';
11045
11395
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jasmine-core",
3
3
  "license": "MIT",
4
- "version": "5.5.0",
4
+ "version": "5.7.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/jasmine/jasmine.git"
@@ -15,9 +15,11 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "posttest": "eslint \"src/**/*.js\" \"spec/**/*.js\" && prettier --check \"src/**/*.js\" \"spec/**/*.js\"",
18
- "test": "grunt --stack execSpecsInNode",
18
+ "test": "node scripts/runSpecsInNode.js",
19
+ "test:parallel": "node scripts/runSpecsInParallel.js",
19
20
  "cleanup": "prettier --write \"src/**/*.js\" \"spec/**/*.js\"",
20
- "build": "grunt buildDistribution",
21
+ "build": "node scripts/buildDistribution.js",
22
+ "buildStandaloneDist": "node scripts/buildStandaloneDist.js",
21
23
  "serve": "node spec/support/localJasmineBrowser.js",
22
24
  "serve:performance": "node spec/support/localJasmineBrowser.js jasmine-browser-performance.json",
23
25
  "ci": "node spec/support/ci.js",
@@ -34,23 +36,22 @@
34
36
  "package.json"
35
37
  ],
36
38
  "devDependencies": {
37
- "eslint": "^8.36.0",
38
- "eslint-plugin-compat": "^4.0.0",
39
+ "@eslint/eslintrc": "^3.3.1",
40
+ "@eslint/js": "^9.24.0",
41
+ "archiver": "^7.0.1",
42
+ "css-url-embed": "^0.1.0",
43
+ "ejs": "^3.1.10",
44
+ "eslint": "^9.24.0",
45
+ "eslint-plugin-compat": "^6.0.2",
39
46
  "glob": "^10.2.3",
40
- "grunt": "^1.0.4",
41
- "grunt-cli": "^1.3.2",
42
- "grunt-contrib-compress": "^2.0.0",
43
- "grunt-contrib-concat": "^2.0.0",
44
- "grunt-css-url-embed": "^1.11.1",
45
- "grunt-sass": "^3.0.2",
47
+ "globals": "^16.0.0",
46
48
  "jasmine": "^5.0.0",
47
49
  "jasmine-browser-runner": "github:jasmine/jasmine-browser-runner",
48
- "jsdom": "^22.0.0",
49
- "load-grunt-tasks": "^5.1.0",
50
+ "jsdom": "^26.0.0",
50
51
  "prettier": "1.17.1",
52
+ "rimraf": "^5.0.10",
51
53
  "sass": "^1.58.3",
52
- "shelljs": "^0.8.3",
53
- "temp": "^0.9.0"
54
+ "shelljs": "^0.9.2"
54
55
  },
55
56
  "browserslist": [
56
57
  "Safari >= 15",