jasmine-core 3.8.0 → 3.99.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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (c) 2008-2021 Pivotal Labs
2
+ Copyright (c) 2008-2022 Pivotal Labs
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
@@ -60,11 +60,15 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
60
60
  j$.Any = jRequire.Any(j$);
61
61
  j$.Anything = jRequire.Anything(j$);
62
62
  j$.CallTracker = jRequire.CallTracker(j$);
63
- j$.MockDate = jRequire.MockDate();
63
+ j$.MockDate = jRequire.MockDate(j$);
64
64
  j$.getClearStack = jRequire.clearStack(j$);
65
65
  j$.Clock = jRequire.Clock();
66
66
  j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
67
+ j$.Deprecator = jRequire.Deprecator(j$);
67
68
  j$.Env = jRequire.Env(j$);
69
+ j$.deprecatingThisProxy = jRequire.deprecatingThisProxy(j$);
70
+ j$.deprecatingSuiteProxy = jRequire.deprecatingSuiteProxy(j$);
71
+ j$.deprecatingSpecProxy = jRequire.deprecatingSpecProxy(j$);
68
72
  j$.StackTrace = jRequire.StackTrace(j$);
69
73
  j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
70
74
  j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
@@ -76,11 +80,34 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
76
80
  j$
77
81
  );
78
82
  j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
79
- j$.pp = j$.makePrettyPrinter();
83
+ j$.basicPrettyPrinter_ = j$.makePrettyPrinter();
84
+ Object.defineProperty(j$, 'pp', {
85
+ get: function() {
86
+ j$.getEnv().deprecated(
87
+ 'jasmine.pp is deprecated and will be removed in a future release. ' +
88
+ 'Use the pp method of the matchersUtil passed to the matcher factory ' +
89
+ "or the asymmetric equality tester's `asymmetricMatch` method " +
90
+ 'instead. See ' +
91
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#static-utils> for details.'
92
+ );
93
+ return j$.basicPrettyPrinter_;
94
+ }
95
+ });
80
96
  j$.MatchersUtil = jRequire.MatchersUtil(j$);
81
- j$.matchersUtil = new j$.MatchersUtil({
97
+ var staticMatchersUtil = new j$.MatchersUtil({
82
98
  customTesters: [],
83
- pp: j$.pp
99
+ pp: j$.basicPrettyPrinter_
100
+ });
101
+ Object.defineProperty(j$, 'matchersUtil', {
102
+ get: function() {
103
+ j$.getEnv().deprecated(
104
+ 'jasmine.matchersUtil is deprecated and will be removed ' +
105
+ 'in a future release. Use the instance passed to the matcher factory or ' +
106
+ "the asymmetric equality tester's `asymmetricMatch` method instead. " +
107
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#static-utils> for details.'
108
+ );
109
+ return staticMatchersUtil;
110
+ }
84
111
  });
85
112
 
86
113
  j$.ObjectContaining = jRequire.ObjectContaining(j$);
@@ -96,6 +123,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
96
123
  j$.SpyRegistry = jRequire.SpyRegistry(j$);
97
124
  j$.SpyStrategy = jRequire.SpyStrategy(j$);
98
125
  j$.StringMatching = jRequire.StringMatching(j$);
126
+ j$.StringContaining = jRequire.StringContaining(j$);
99
127
  j$.UserContext = jRequire.UserContext(j$);
100
128
  j$.Suite = jRequire.Suite(j$);
101
129
  j$.Timer = jRequire.Timer();
@@ -175,6 +203,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
175
203
  * Maximum object depth the pretty printer will print to.
176
204
  * Set this to a lower value to speed up pretty printing if you have large objects.
177
205
  * @name jasmine.MAX_PRETTY_PRINT_DEPTH
206
+ * @default 8
178
207
  * @since 1.3.0
179
208
  */
180
209
  j$.MAX_PRETTY_PRINT_DEPTH = 8;
@@ -183,6 +212,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
183
212
  * This will also limit the number of keys and values displayed for an object.
184
213
  * Elements past this number will be ellipised.
185
214
  * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
215
+ * @default 50
186
216
  * @since 2.7.0
187
217
  */
188
218
  j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
@@ -190,15 +220,35 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
190
220
  * Maximum number of characters to display when pretty printing objects.
191
221
  * Characters past this number will be ellipised.
192
222
  * @name jasmine.MAX_PRETTY_PRINT_CHARS
223
+ * @default 100
193
224
  * @since 2.9.0
194
225
  */
195
226
  j$.MAX_PRETTY_PRINT_CHARS = 1000;
196
227
  /**
197
- * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
228
+ * Default number of milliseconds Jasmine will wait for an asynchronous spec,
229
+ * before, or after function to complete. This can be overridden on a case by
230
+ * case basis by passing a time limit as the third argument to {@link it},
231
+ * {@link beforeEach}, {@link afterEach}, {@link beforeAll}, or
232
+ * {@link afterAll}. The value must be no greater than the largest number of
233
+ * milliseconds supported by setTimeout, which is usually 2147483647.
234
+ *
235
+ * While debugging tests, you may want to set this to a large number (or pass
236
+ * a large number to one of the functions mentioned above) so that Jasmine
237
+ * does not move on to after functions or the next spec while you're debugging.
198
238
  * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
239
+ * @default 5000
199
240
  * @since 1.3.0
200
241
  */
201
- j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
242
+ var DEFAULT_TIMEOUT_INTERVAL = 5000;
243
+ Object.defineProperty(j$, 'DEFAULT_TIMEOUT_INTERVAL', {
244
+ get: function() {
245
+ return DEFAULT_TIMEOUT_INTERVAL;
246
+ },
247
+ set: function(newValue) {
248
+ j$.util.validateTimeout(newValue, 'jasmine.DEFAULT_TIMEOUT_INTERVAL');
249
+ DEFAULT_TIMEOUT_INTERVAL = newValue;
250
+ }
251
+ });
202
252
 
203
253
  j$.getGlobal = function() {
204
254
  return jasmineGlobal;
@@ -267,9 +317,21 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
267
317
  };
268
318
 
269
319
  j$.isError_ = function(value) {
320
+ if (!value) {
321
+ return false;
322
+ }
323
+
270
324
  if (value instanceof Error) {
271
325
  return true;
272
326
  }
327
+ if (
328
+ typeof window !== 'undefined' &&
329
+ typeof window.trustedTypes !== 'undefined'
330
+ ) {
331
+ return (
332
+ typeof value.stack === 'string' && typeof value.message === 'string'
333
+ );
334
+ }
273
335
  if (value && value.constructor && value.constructor.constructor) {
274
336
  var valueGlobal = value.constructor.constructor('return this');
275
337
  if (j$.isFunction_(valueGlobal)) {
@@ -385,7 +447,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
385
447
  };
386
448
 
387
449
  /**
388
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
450
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
389
451
  * that will succeed if the actual value being compared is an instance of the specified class/constructor.
390
452
  * @name jasmine.any
391
453
  * @since 1.3.0
@@ -397,7 +459,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
397
459
  };
398
460
 
399
461
  /**
400
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
462
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
401
463
  * that will succeed if the actual value being compared is not `null` and not `undefined`.
402
464
  * @name jasmine.anything
403
465
  * @since 2.2.0
@@ -408,7 +470,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
408
470
  };
409
471
 
410
472
  /**
411
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
473
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
412
474
  * that will succeed if the actual value being compared is `true` or anything truthy.
413
475
  * @name jasmine.truthy
414
476
  * @since 3.1.0
@@ -419,7 +481,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
419
481
  };
420
482
 
421
483
  /**
422
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
484
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
423
485
  * that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
424
486
  * @name jasmine.falsy
425
487
  * @since 3.1.0
@@ -430,7 +492,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
430
492
  };
431
493
 
432
494
  /**
433
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
495
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
434
496
  * that will succeed if the actual value being compared is empty.
435
497
  * @name jasmine.empty
436
498
  * @since 3.1.0
@@ -441,7 +503,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
441
503
  };
442
504
 
443
505
  /**
444
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
506
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
445
507
  * that will succeed if the actual value being compared is not empty.
446
508
  * @name jasmine.notEmpty
447
509
  * @since 3.1.0
@@ -452,7 +514,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
452
514
  };
453
515
 
454
516
  /**
455
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
517
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
456
518
  * that will succeed if the actual value being compared contains at least the keys and values.
457
519
  * @name jasmine.objectContaining
458
520
  * @since 1.3.0
@@ -464,7 +526,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
464
526
  };
465
527
 
466
528
  /**
467
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
529
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
468
530
  * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
469
531
  * @name jasmine.stringMatching
470
532
  * @since 2.2.0
@@ -476,7 +538,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
476
538
  };
477
539
 
478
540
  /**
479
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
541
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
542
+ * that will succeed if the actual value is a `String` that contains the specified `String`.
543
+ * @name jasmine.stringContaining
544
+ * @since 3.10.0
545
+ * @function
546
+ * @param {String} expected
547
+ */
548
+ j$.stringContaining = function(expected) {
549
+ return new j$.StringContaining(expected);
550
+ };
551
+
552
+ /**
553
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
480
554
  * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
481
555
  * @name jasmine.arrayContaining
482
556
  * @since 2.2.0
@@ -488,7 +562,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
488
562
  };
489
563
 
490
564
  /**
491
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
565
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
492
566
  * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
493
567
  * @name jasmine.arrayWithExactContents
494
568
  * @since 2.8.0
@@ -500,7 +574,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
500
574
  };
501
575
 
502
576
  /**
503
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
577
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
504
578
  * that will succeed if every key/value pair in the sample passes the deep equality comparison
505
579
  * with at least one key/value pair in the actual value being compared
506
580
  * @name jasmine.mapContaining
@@ -513,7 +587,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
513
587
  };
514
588
 
515
589
  /**
516
- * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
590
+ * Get an {@link AsymmetricEqualityTester}, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
517
591
  * that will succeed if every item in the sample passes the deep equality comparison
518
592
  * with at least one item in the actual value being compared
519
593
  * @name jasmine.setContaining
@@ -688,6 +762,21 @@ getJasmineRequireObj().util = function(j$) {
688
762
  }
689
763
  };
690
764
 
765
+ util.validateTimeout = function(timeout, msgPrefix) {
766
+ // Timeouts are implemented with setTimeout, which only supports a limited
767
+ // range of values. The limit is unspecified, as is the behavior when it's
768
+ // exceeded. But on all currently supported JS runtimes, setTimeout calls
769
+ // the callback immediately when the timeout is greater than 2147483647
770
+ // (the maximum value of a signed 32 bit integer).
771
+ var max = 2147483647;
772
+
773
+ if (timeout > max) {
774
+ throw new Error(
775
+ (msgPrefix || 'Timeout value') + ' cannot be greater than ' + max
776
+ );
777
+ }
778
+ };
779
+
691
780
  return util;
692
781
  };
693
782
 
@@ -695,17 +784,26 @@ getJasmineRequireObj().Spec = function(j$) {
695
784
  /**
696
785
  * @interface Spec
697
786
  * @see Configuration#specFilter
787
+ * @since 2.0.0
698
788
  */
699
789
  function Spec(attrs) {
700
790
  this.expectationFactory = attrs.expectationFactory;
701
791
  this.asyncExpectationFactory = attrs.asyncExpectationFactory;
702
792
  this.resultCallback = attrs.resultCallback || function() {};
793
+ /**
794
+ * The unique ID of this spec.
795
+ * @name Spec#id
796
+ * @readonly
797
+ * @type {string}
798
+ * @since 2.0.0
799
+ */
703
800
  this.id = attrs.id;
704
801
  /**
705
802
  * The description passed to the {@link it} that created this spec.
706
803
  * @name Spec#description
707
804
  * @readonly
708
805
  * @type {string}
806
+ * @since 2.0.0
709
807
  */
710
808
  this.description = attrs.description || '';
711
809
  this.queueableFn = attrs.queueableFn;
@@ -720,6 +818,8 @@ getJasmineRequireObj().Spec = function(j$) {
720
818
  return {};
721
819
  };
722
820
  this.onStart = attrs.onStart || function() {};
821
+ this.autoCleanClosures =
822
+ attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
723
823
  this.getSpecName =
724
824
  attrs.getSpecName ||
725
825
  function() {
@@ -727,6 +827,7 @@ getJasmineRequireObj().Spec = function(j$) {
727
827
  };
728
828
  this.expectationResultFactory =
729
829
  attrs.expectationResultFactory || function() {};
830
+ this.deprecated = attrs.deprecated || function() {};
730
831
  this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
731
832
  this.catchingExceptions =
732
833
  attrs.catchingExceptions ||
@@ -737,7 +838,7 @@ getJasmineRequireObj().Spec = function(j$) {
737
838
  this.timer = attrs.timer || new j$.Timer();
738
839
 
739
840
  if (!this.queueableFn.fn) {
740
- this.pend();
841
+ this.exclude();
741
842
  }
742
843
 
743
844
  /**
@@ -752,7 +853,8 @@ getJasmineRequireObj().Spec = function(j$) {
752
853
  * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
753
854
  * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
754
855
  * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
755
- */
856
+ * @since 2.0.0
857
+ x */
756
858
  this.result = {
757
859
  id: this.id,
758
860
  description: this.description,
@@ -804,7 +906,9 @@ getJasmineRequireObj().Spec = function(j$) {
804
906
 
805
907
  var complete = {
806
908
  fn: function(done) {
807
- self.queueableFn.fn = null;
909
+ if (self.autoCleanClosures) {
910
+ self.queueableFn.fn = null;
911
+ }
808
912
  self.result.status = self.status(excluded, failSpecWithNoExp);
809
913
  self.result.duration = self.timer.elapsed();
810
914
  self.resultCallback(self.result, done);
@@ -821,13 +925,32 @@ getJasmineRequireObj().Spec = function(j$) {
821
925
  onException: function() {
822
926
  self.onException.apply(self, arguments);
823
927
  },
824
- onComplete: function() {
825
- onComplete(
826
- self.result.status === 'failed' &&
827
- new j$.StopExecutionError('spec failed')
928
+ onMultipleDone: function() {
929
+ // Issue a deprecation. Include the context ourselves and pass
930
+ // ignoreRunnable: true, since getting here always means that we've already
931
+ // moved on and the current runnable isn't the one that caused the problem.
932
+ self.deprecated(
933
+ "An asynchronous function called its 'done' " +
934
+ 'callback more than once. This is a bug in the spec, beforeAll, ' +
935
+ 'beforeEach, afterAll, or afterEach function in question. This will ' +
936
+ 'be treated as an error in a future version. See' +
937
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
938
+ 'for more information.\n' +
939
+ '(in spec: ' +
940
+ self.getFullName() +
941
+ ')',
942
+ { ignoreRunnable: true }
828
943
  );
829
944
  },
830
- userContext: this.userContext()
945
+ onComplete: function() {
946
+ if (self.result.status === 'failed') {
947
+ onComplete(new j$.StopExecutionError('spec failed'));
948
+ } else {
949
+ onComplete();
950
+ }
951
+ },
952
+ userContext: this.userContext(),
953
+ runnableName: this.getFullName.bind(this)
831
954
  };
832
955
 
833
956
  if (this.markedPending || excluded === true) {
@@ -841,6 +964,36 @@ getJasmineRequireObj().Spec = function(j$) {
841
964
  this.queueRunnerFactory(runnerConfig);
842
965
  };
843
966
 
967
+ Spec.prototype.reset = function() {
968
+ /**
969
+ * @typedef SpecResult
970
+ * @property {Int} id - The unique id of this spec.
971
+ * @property {String} description - The description passed to the {@link it} that created this spec.
972
+ * @property {String} fullName - The full description including all ancestors of this spec.
973
+ * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
974
+ * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
975
+ * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
976
+ * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
977
+ * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
978
+ * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
979
+ * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
980
+ * @since 2.0.0
981
+ */
982
+ this.result = {
983
+ id: this.id,
984
+ description: this.description,
985
+ fullName: this.getFullName(),
986
+ failedExpectations: [],
987
+ passedExpectations: [],
988
+ deprecationWarnings: [],
989
+ pendingReason: this.excludeMessage,
990
+ duration: null,
991
+ properties: null,
992
+ trace: null
993
+ };
994
+ this.markedPending = this.markedExcluding;
995
+ };
996
+
844
997
  Spec.prototype.onException = function onException(e) {
845
998
  if (Spec.isPendingSpecException(e)) {
846
999
  this.pend(extractCustomPendingMessage(e));
@@ -864,6 +1017,10 @@ getJasmineRequireObj().Spec = function(j$) {
864
1017
  );
865
1018
  };
866
1019
 
1020
+ /*
1021
+ * Marks state as pending
1022
+ * @param {string} [message] An optional reason message
1023
+ */
867
1024
  Spec.prototype.pend = function(message) {
868
1025
  this.markedPending = true;
869
1026
  if (message) {
@@ -871,6 +1028,19 @@ getJasmineRequireObj().Spec = function(j$) {
871
1028
  }
872
1029
  };
873
1030
 
1031
+ /*
1032
+ * Like {@link Spec#pend}, but pending state will survive {@link Spec#reset}
1033
+ * Useful for fit, xit, where pending state remains.
1034
+ * @param {string} [message] An optional reason message
1035
+ */
1036
+ Spec.prototype.exclude = function(message) {
1037
+ this.markedExcluding = true;
1038
+ if (this.message) {
1039
+ this.excludeMessage = message;
1040
+ }
1041
+ this.pend(message);
1042
+ };
1043
+
874
1044
  Spec.prototype.getResult = function() {
875
1045
  this.result.status = this.status();
876
1046
  return this.result;
@@ -903,6 +1073,7 @@ getJasmineRequireObj().Spec = function(j$) {
903
1073
  * @name Spec#getFullName
904
1074
  * @function
905
1075
  * @returns {string}
1076
+ * @since 2.0.0
906
1077
  */
907
1078
  Spec.prototype.getFullName = function() {
908
1079
  return this.getSpecName(this);
@@ -1057,8 +1228,17 @@ getJasmineRequireObj().Env = function(j$) {
1057
1228
  * @since 3.3.0
1058
1229
  * @type Boolean
1059
1230
  * @default false
1231
+ * @deprecated Use the `stopOnSpecFailure` config property instead.
1060
1232
  */
1061
1233
  failFast: false,
1234
+ /**
1235
+ * Whether to stop execution of the suite after the first spec failure
1236
+ * @name Configuration#stopOnSpecFailure
1237
+ * @since 3.9.0
1238
+ * @type Boolean
1239
+ * @default false
1240
+ */
1241
+ stopOnSpecFailure: false,
1062
1242
  /**
1063
1243
  * Whether to fail the spec if it ran no expectations. By default
1064
1244
  * a spec that ran no expectations is reported as passed. Setting this
@@ -1075,8 +1255,17 @@ getJasmineRequireObj().Env = function(j$) {
1075
1255
  * @since 3.3.0
1076
1256
  * @type Boolean
1077
1257
  * @default false
1258
+ * @deprecated Use the `stopSpecOnExpectationFailure` config property instead.
1078
1259
  */
1079
1260
  oneFailurePerSpec: false,
1261
+ /**
1262
+ * Whether to cause specs to only have one expectation failure.
1263
+ * @name Configuration#stopSpecOnExpectationFailure
1264
+ * @since 3.3.0
1265
+ * @type Boolean
1266
+ * @default false
1267
+ */
1268
+ stopSpecOnExpectationFailure: false,
1080
1269
  /**
1081
1270
  * A function that takes a spec and returns true if it should be executed
1082
1271
  * or false if it should be skipped.
@@ -1111,8 +1300,31 @@ getJasmineRequireObj().Env = function(j$) {
1111
1300
  * @since 3.5.0
1112
1301
  * @type function
1113
1302
  * @default undefined
1303
+ * @deprecated In a future version, Jasmine will ignore the Promise config
1304
+ * property and always create native promises instead.
1305
+ */
1306
+ Promise: undefined,
1307
+ /**
1308
+ * Clean closures when a suite is done running (done by clearing the stored function reference).
1309
+ * This prevents memory leaks, but you won't be able to run jasmine multiple times.
1310
+ * @name Configuration#autoCleanClosures
1311
+ * @since 3.10.0
1312
+ * @type boolean
1313
+ * @default true
1114
1314
  */
1115
- Promise: undefined
1315
+ autoCleanClosures: true,
1316
+ /**
1317
+ * Whether or not to issue warnings for certain deprecated functionality
1318
+ * every time it's used. If not set or set to false, deprecation warnings
1319
+ * for methods that tend to be called frequently will be issued only once
1320
+ * or otherwise throttled to to prevent the suite output from being flooded
1321
+ * with warnings.
1322
+ * @name Configuration#verboseDeprecations
1323
+ * @since 3.6.0
1324
+ * @type Boolean
1325
+ * @default false
1326
+ */
1327
+ verboseDeprecations: false
1116
1328
  };
1117
1329
 
1118
1330
  var currentSuite = function() {
@@ -1162,33 +1374,89 @@ getJasmineRequireObj().Env = function(j$) {
1162
1374
  * @function
1163
1375
  */
1164
1376
  this.configure = function(configuration) {
1165
- if (configuration.specFilter) {
1166
- config.specFilter = configuration.specFilter;
1167
- }
1377
+ var booleanProps = [
1378
+ 'random',
1379
+ 'failSpecWithNoExpectations',
1380
+ 'hideDisabled',
1381
+ 'autoCleanClosures'
1382
+ ];
1383
+
1384
+ booleanProps.forEach(function(prop) {
1385
+ if (typeof configuration[prop] !== 'undefined') {
1386
+ config[prop] = !!configuration[prop];
1387
+ }
1388
+ });
1168
1389
 
1169
- if (configuration.hasOwnProperty('random')) {
1170
- config.random = !!configuration.random;
1171
- }
1390
+ if (typeof configuration.failFast !== 'undefined') {
1391
+ // We can't unconditionally issue a warning here because then users who
1392
+ // get the configuration from Jasmine, modify it, and pass it back would
1393
+ // see the warning.
1394
+ if (configuration.failFast !== config.failFast) {
1395
+ this.deprecated(
1396
+ 'The `failFast` config property is deprecated and will be removed ' +
1397
+ 'in a future version of Jasmine. Please use `stopOnSpecFailure` ' +
1398
+ 'instead.',
1399
+ { ignoreRunnable: true }
1400
+ );
1401
+ }
1172
1402
 
1173
- if (configuration.hasOwnProperty('seed')) {
1174
- config.seed = configuration.seed;
1175
- }
1403
+ if (typeof configuration.stopOnSpecFailure !== 'undefined') {
1404
+ if (configuration.stopOnSpecFailure !== configuration.failFast) {
1405
+ throw new Error(
1406
+ 'stopOnSpecFailure and failFast are aliases for ' +
1407
+ "each other. Don't set failFast if you also set stopOnSpecFailure."
1408
+ );
1409
+ }
1410
+ }
1176
1411
 
1177
- if (configuration.hasOwnProperty('failFast')) {
1178
1412
  config.failFast = configuration.failFast;
1179
- }
1413
+ config.stopOnSpecFailure = configuration.failFast;
1414
+ } else if (typeof configuration.stopOnSpecFailure !== 'undefined') {
1415
+ config.failFast = configuration.stopOnSpecFailure;
1416
+ config.stopOnSpecFailure = configuration.stopOnSpecFailure;
1417
+ }
1418
+
1419
+ if (typeof configuration.oneFailurePerSpec !== 'undefined') {
1420
+ // We can't unconditionally issue a warning here because then users who
1421
+ // get the configuration from Jasmine, modify it, and pass it back would
1422
+ // see the warning.
1423
+ if (configuration.oneFailurePerSpec !== config.oneFailurePerSpec) {
1424
+ this.deprecated(
1425
+ 'The `oneFailurePerSpec` config property is deprecated and will be ' +
1426
+ 'removed in a future version of Jasmine. Please use ' +
1427
+ '`stopSpecOnExpectationFailure` instead.',
1428
+ { ignoreRunnable: true }
1429
+ );
1430
+ }
1180
1431
 
1181
- if (configuration.hasOwnProperty('failSpecWithNoExpectations')) {
1182
- config.failSpecWithNoExpectations =
1183
- configuration.failSpecWithNoExpectations;
1184
- }
1432
+ if (typeof configuration.stopSpecOnExpectationFailure !== 'undefined') {
1433
+ if (
1434
+ configuration.stopSpecOnExpectationFailure !==
1435
+ configuration.oneFailurePerSpec
1436
+ ) {
1437
+ throw new Error(
1438
+ 'stopSpecOnExpectationFailure and oneFailurePerSpec are aliases for ' +
1439
+ "each other. Don't set oneFailurePerSpec if you also set stopSpecOnExpectationFailure."
1440
+ );
1441
+ }
1442
+ }
1185
1443
 
1186
- if (configuration.hasOwnProperty('oneFailurePerSpec')) {
1187
1444
  config.oneFailurePerSpec = configuration.oneFailurePerSpec;
1445
+ config.stopSpecOnExpectationFailure = configuration.oneFailurePerSpec;
1446
+ } else if (
1447
+ typeof configuration.stopSpecOnExpectationFailure !== 'undefined'
1448
+ ) {
1449
+ config.oneFailurePerSpec = configuration.stopSpecOnExpectationFailure;
1450
+ config.stopSpecOnExpectationFailure =
1451
+ configuration.stopSpecOnExpectationFailure;
1188
1452
  }
1189
1453
 
1190
- if (configuration.hasOwnProperty('hideDisabled')) {
1191
- config.hideDisabled = configuration.hideDisabled;
1454
+ if (configuration.specFilter) {
1455
+ config.specFilter = configuration.specFilter;
1456
+ }
1457
+
1458
+ if (typeof configuration.seed !== 'undefined') {
1459
+ config.seed = configuration.seed;
1192
1460
  }
1193
1461
 
1194
1462
  // Don't use hasOwnProperty to check for Promise existence because Promise
@@ -1200,12 +1468,22 @@ getJasmineRequireObj().Env = function(j$) {
1200
1468
  typeof configuration.Promise.reject === 'function'
1201
1469
  ) {
1202
1470
  customPromise = configuration.Promise;
1471
+ self.deprecated(
1472
+ 'The `Promise` config property is deprecated. Future versions ' +
1473
+ 'of Jasmine will create native promises even if the `Promise` ' +
1474
+ 'config property is set. Please remove it.'
1475
+ );
1203
1476
  } else {
1204
1477
  throw new Error(
1205
1478
  'Custom promise library missing `resolve`/`reject` functions'
1206
1479
  );
1207
1480
  }
1208
1481
  }
1482
+
1483
+ if (configuration.hasOwnProperty('verboseDeprecations')) {
1484
+ config.verboseDeprecations = configuration.verboseDeprecations;
1485
+ deprecator.verboseDeprecations(config.verboseDeprecations);
1486
+ }
1209
1487
  };
1210
1488
 
1211
1489
  /**
@@ -1226,13 +1504,19 @@ getJasmineRequireObj().Env = function(j$) {
1226
1504
  Object.defineProperty(this, 'specFilter', {
1227
1505
  get: function() {
1228
1506
  self.deprecated(
1229
- 'Getting specFilter directly from Env is deprecated and will be removed in a future version of Jasmine, please check the specFilter option from `configuration`'
1507
+ 'Getting specFilter directly from Env is deprecated and will be ' +
1508
+ 'removed in a future version of Jasmine. Please check the ' +
1509
+ 'specFilter option from `configuration` instead.',
1510
+ { ignoreRunnable: true }
1230
1511
  );
1231
1512
  return config.specFilter;
1232
1513
  },
1233
1514
  set: function(val) {
1234
1515
  self.deprecated(
1235
- 'Setting specFilter directly on Env is deprecated and will be removed in a future version of Jasmine, please use the specFilter option in `configure`'
1516
+ 'Setting specFilter directly on Env is deprecated and will be ' +
1517
+ 'removed in a future version of Jasmine. Please use the ' +
1518
+ 'specFilter option in `configure` instead.',
1519
+ { ignoreRunnable: true }
1236
1520
  );
1237
1521
  config.specFilter = val;
1238
1522
  }
@@ -1279,6 +1563,17 @@ getJasmineRequireObj().Env = function(j$) {
1279
1563
  runnableResources[currentRunnable().id].customMatchers;
1280
1564
 
1281
1565
  for (var matcherName in matchersToAdd) {
1566
+ if (matchersToAdd[matcherName].length > 1) {
1567
+ self.deprecated(
1568
+ 'The matcher factory for "' +
1569
+ matcherName +
1570
+ '" ' +
1571
+ 'accepts custom equality testers, but this parameter will no longer be ' +
1572
+ 'passed in a future release. ' +
1573
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
1574
+ );
1575
+ }
1576
+
1282
1577
  customMatchers[matcherName] = matchersToAdd[matcherName];
1283
1578
  }
1284
1579
  };
@@ -1293,6 +1588,17 @@ getJasmineRequireObj().Env = function(j$) {
1293
1588
  runnableResources[currentRunnable().id].customAsyncMatchers;
1294
1589
 
1295
1590
  for (var matcherName in matchersToAdd) {
1591
+ if (matchersToAdd[matcherName].length > 1) {
1592
+ self.deprecated(
1593
+ 'The matcher factory for "' +
1594
+ matcherName +
1595
+ '" ' +
1596
+ 'accepts custom equality testers, but this parameter will no longer be ' +
1597
+ 'passed in a future release. ' +
1598
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
1599
+ );
1600
+ }
1601
+
1296
1602
  customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
1297
1603
  }
1298
1604
  };
@@ -1375,7 +1681,9 @@ getJasmineRequireObj().Env = function(j$) {
1375
1681
  }
1376
1682
 
1377
1683
  delayedExpectationResult.message +=
1378
- 'Did you forget to return or await the result of expectAsync?';
1684
+ '1. Did you forget to return or await the result of expectAsync?\n' +
1685
+ '2. Was done() invoked before an async operation completed?\n' +
1686
+ '3. Did an expectation follow a call to done()?';
1379
1687
 
1380
1688
  topSuite.result.failedExpectations.push(delayedExpectationResult);
1381
1689
  }
@@ -1440,10 +1748,11 @@ getJasmineRequireObj().Env = function(j$) {
1440
1748
  delete runnableResources[id];
1441
1749
  };
1442
1750
 
1443
- var beforeAndAfterFns = function(suite) {
1751
+ var beforeAndAfterFns = function(targetSuite) {
1444
1752
  return function() {
1445
1753
  var befores = [],
1446
- afters = [];
1754
+ afters = [],
1755
+ suite = targetSuite;
1447
1756
 
1448
1757
  while (suite) {
1449
1758
  befores = befores.concat(suite.beforeFns);
@@ -1486,18 +1795,24 @@ getJasmineRequireObj().Env = function(j$) {
1486
1795
  * @since 2.3.0
1487
1796
  * @function
1488
1797
  * @param {Boolean} value Whether to throw when a expectation fails
1489
- * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure}
1798
+ * @deprecated Use the `stopSpecOnExpectationFailure` option with {@link Env#configure}
1490
1799
  */
1491
1800
  this.throwOnExpectationFailure = function(value) {
1492
1801
  this.deprecated(
1493
- 'Setting throwOnExpectationFailure directly on Env is deprecated and will be removed in a future version of Jasmine, please use the oneFailurePerSpec option in `configure`'
1802
+ 'Setting throwOnExpectationFailure directly on Env is deprecated and ' +
1803
+ 'will be removed in a future version of Jasmine. Please use the ' +
1804
+ 'stopSpecOnExpectationFailure option in `configure`.',
1805
+ { ignoreRunnable: true }
1494
1806
  );
1495
1807
  this.configure({ oneFailurePerSpec: !!value });
1496
1808
  };
1497
1809
 
1498
1810
  this.throwingExpectationFailures = function() {
1499
1811
  this.deprecated(
1500
- 'Getting throwingExpectationFailures directly from Env is deprecated and will be removed in a future version of Jasmine, please check the oneFailurePerSpec option from `configuration`'
1812
+ 'Getting throwingExpectationFailures directly from Env is deprecated ' +
1813
+ 'and will be removed in a future version of Jasmine. Please check ' +
1814
+ 'the stopSpecOnExpectationFailure option from `configuration`.',
1815
+ { ignoreRunnable: true }
1501
1816
  );
1502
1817
  return config.oneFailurePerSpec;
1503
1818
  };
@@ -1508,18 +1823,24 @@ getJasmineRequireObj().Env = function(j$) {
1508
1823
  * @since 2.7.0
1509
1824
  * @function
1510
1825
  * @param {Boolean} value Whether to stop suite execution when a spec fails
1511
- * @deprecated Use the `failFast` option with {@link Env#configure}
1826
+ * @deprecated Use the `stopOnSpecFailure` option with {@link Env#configure}
1512
1827
  */
1513
1828
  this.stopOnSpecFailure = function(value) {
1514
1829
  this.deprecated(
1515
- 'Setting stopOnSpecFailure directly is deprecated and will be removed in a future version of Jasmine, please use the failFast option in `configure`'
1830
+ 'Setting stopOnSpecFailure directly is deprecated and will be ' +
1831
+ 'removed in a future version of Jasmine. Please use the ' +
1832
+ 'stopOnSpecFailure option in `configure`.',
1833
+ { ignoreRunnable: true }
1516
1834
  );
1517
- this.configure({ failFast: !!value });
1835
+ this.configure({ stopOnSpecFailure: !!value });
1518
1836
  };
1519
1837
 
1520
1838
  this.stoppingOnSpecFailure = function() {
1521
1839
  this.deprecated(
1522
- 'Getting stoppingOnSpecFailure directly from Env is deprecated and will be removed in a future version of Jasmine, please check the failFast option from `configuration`'
1840
+ 'Getting stoppingOnSpecFailure directly from Env is deprecated and ' +
1841
+ 'will be removed in a future version of Jasmine. Please check the ' +
1842
+ 'stopOnSpecFailure option from `configuration`.',
1843
+ { ignoreRunnable: true }
1523
1844
  );
1524
1845
  return config.failFast;
1525
1846
  };
@@ -1534,14 +1855,20 @@ getJasmineRequireObj().Env = function(j$) {
1534
1855
  */
1535
1856
  this.randomizeTests = function(value) {
1536
1857
  this.deprecated(
1537
- 'Setting randomizeTests directly is deprecated and will be removed in a future version of Jasmine, please use the random option in `configure`'
1858
+ 'Setting randomizeTests directly is deprecated and will be removed ' +
1859
+ 'in a future version of Jasmine. Please use the random option in ' +
1860
+ '`configure` instead.',
1861
+ { ignoreRunnable: true }
1538
1862
  );
1539
1863
  config.random = !!value;
1540
1864
  };
1541
1865
 
1542
1866
  this.randomTests = function() {
1543
1867
  this.deprecated(
1544
- 'Getting randomTests directly from Env is deprecated and will be removed in a future version of Jasmine, please check the random option from `configuration`'
1868
+ 'Getting randomTests directly from Env is deprecated and will be ' +
1869
+ 'removed in a future version of Jasmine. Please check the random ' +
1870
+ 'option from `configuration` instead.',
1871
+ { ignoreRunnable: true }
1545
1872
  );
1546
1873
  return config.random;
1547
1874
  };
@@ -1556,7 +1883,10 @@ getJasmineRequireObj().Env = function(j$) {
1556
1883
  */
1557
1884
  this.seed = function(value) {
1558
1885
  this.deprecated(
1559
- 'Setting seed directly is deprecated and will be removed in a future version of Jasmine, please use the seed option in `configure`'
1886
+ 'Setting seed directly is deprecated and will be removed in a ' +
1887
+ 'future version of Jasmine. Please use the seed option in ' +
1888
+ '`configure` instead.',
1889
+ { ignoreRunnable: true }
1560
1890
  );
1561
1891
  if (value) {
1562
1892
  config.seed = value;
@@ -1566,7 +1896,10 @@ getJasmineRequireObj().Env = function(j$) {
1566
1896
 
1567
1897
  this.hidingDisabled = function(value) {
1568
1898
  this.deprecated(
1569
- 'Getting hidingDisabled directly from Env is deprecated and will be removed in a future version of Jasmine, please check the hideDisabled option from `configuration`'
1899
+ 'Getting hidingDisabled directly from Env is deprecated and will ' +
1900
+ 'be removed in a future version of Jasmine. Please check the ' +
1901
+ 'hideDisabled option from `configuration` instead.',
1902
+ { ignoreRunnable: true }
1570
1903
  );
1571
1904
  return config.hideDisabled;
1572
1905
  };
@@ -1575,41 +1908,51 @@ getJasmineRequireObj().Env = function(j$) {
1575
1908
  * @name Env#hideDisabled
1576
1909
  * @since 3.2.0
1577
1910
  * @function
1911
+ * @deprecated Use the `hideDisabled` option with {@link Env#configure}
1578
1912
  */
1579
1913
  this.hideDisabled = function(value) {
1580
1914
  this.deprecated(
1581
- 'Setting hideDisabled directly is deprecated and will be removed in a future version of Jasmine, please use the hideDisabled option in `configure`'
1915
+ 'Setting hideDisabled directly is deprecated and will be removed ' +
1916
+ 'in a future version of Jasmine. Please use the hideDisabled option ' +
1917
+ 'in `configure` instead.',
1918
+ { ignoreRunnable: true }
1582
1919
  );
1583
1920
  config.hideDisabled = !!value;
1584
1921
  };
1585
1922
 
1586
- this.deprecated = function(deprecation) {
1923
+ /**
1924
+ * Causes a deprecation warning to be logged to the console and reported to
1925
+ * reporters.
1926
+ *
1927
+ * The optional second parameter is an object that can have either of the
1928
+ * following properties:
1929
+ *
1930
+ * omitStackTrace: Whether to omit the stack trace. Optional. Defaults to
1931
+ * false. This option is ignored if the deprecation is an Error. Set this
1932
+ * when the stack trace will not contain anything that helps the user find
1933
+ * the source of the deprecation.
1934
+ *
1935
+ * ignoreRunnable: Whether to log the deprecation on the root suite, ignoring
1936
+ * the spec or suite that's running when it happens. Optional. Defaults to
1937
+ * false.
1938
+ *
1939
+ * @name Env#deprecated
1940
+ * @since 2.99
1941
+ * @function
1942
+ * @param {String|Error} deprecation The deprecation message
1943
+ * @param {Object} [options] Optional extra options, as described above
1944
+ */
1945
+ this.deprecated = function(deprecation, options) {
1587
1946
  var runnable = currentRunnable() || topSuite;
1588
- var context;
1589
-
1590
- if (runnable === topSuite) {
1591
- context = '';
1592
- } else if (runnable === currentSuite()) {
1593
- context = ' (in suite: ' + runnable.getFullName() + ')';
1594
- } else {
1595
- context = ' (in spec: ' + runnable.getFullName() + ')';
1596
- }
1597
-
1598
- runnable.addDeprecationWarning(deprecation);
1599
- if (
1600
- typeof console !== 'undefined' &&
1601
- typeof console.error === 'function'
1602
- ) {
1603
- console.error('DEPRECATION: ' + deprecation + context);
1604
- }
1947
+ deprecator.addDeprecationWarning(runnable, deprecation, options);
1605
1948
  };
1606
1949
 
1607
1950
  var queueRunnerFactory = function(options, args) {
1608
1951
  var failFast = false;
1609
1952
  if (options.isLeaf) {
1610
- failFast = config.oneFailurePerSpec;
1953
+ failFast = config.stopSpecOnExpectationFailure;
1611
1954
  } else if (!options.isReporter) {
1612
- failFast = config.failFast;
1955
+ failFast = config.stopOnSpecFailure;
1613
1956
  }
1614
1957
  options.clearStack = options.clearStack || clearStack;
1615
1958
  options.timeout = {
@@ -1635,9 +1978,10 @@ getJasmineRequireObj().Env = function(j$) {
1635
1978
  description: 'Jasmine__TopLevel__Suite',
1636
1979
  expectationFactory: expectationFactory,
1637
1980
  asyncExpectationFactory: suiteAsyncExpectationFactory,
1638
- expectationResultFactory: expectationResultFactory
1981
+ expectationResultFactory: expectationResultFactory,
1982
+ autoCleanClosures: config.autoCleanClosures
1639
1983
  });
1640
- defaultResourcesForRunnable(topSuite.id);
1984
+ var deprecator = new j$.Deprecator(topSuite);
1641
1985
  currentDeclarationSuite = topSuite;
1642
1986
 
1643
1987
  /**
@@ -1646,9 +1990,10 @@ getJasmineRequireObj().Env = function(j$) {
1646
1990
  * @function
1647
1991
  * @name Env#topSuite
1648
1992
  * @return {Suite} the root suite
1993
+ * @since 2.0.0
1649
1994
  */
1650
1995
  this.topSuite = function() {
1651
- return topSuite;
1996
+ return j$.deprecatingSuiteProxy(topSuite, null, this);
1652
1997
  };
1653
1998
 
1654
1999
  /**
@@ -1723,7 +2068,8 @@ getJasmineRequireObj().Env = function(j$) {
1723
2068
  */
1724
2069
  'specDone'
1725
2070
  ],
1726
- queueRunnerFactory
2071
+ queueRunnerFactory,
2072
+ self.deprecated
1727
2073
  );
1728
2074
 
1729
2075
  /**
@@ -1741,13 +2087,24 @@ getJasmineRequireObj().Env = function(j$) {
1741
2087
  *
1742
2088
  * execute should not be called more than once.
1743
2089
  *
2090
+ * If the environment supports promises, execute will return a promise that
2091
+ * is resolved after the suite finishes executing. The promise will be
2092
+ * resolved (not rejected) as long as the suite runs to completion. Use a
2093
+ * {@link Reporter} to determine whether or not the suite passed.
2094
+ *
1744
2095
  * @name Env#execute
1745
2096
  * @since 2.0.0
1746
2097
  * @function
1747
2098
  * @param {(string[])=} runnablesToRun IDs of suites and/or specs to run
1748
2099
  * @param {Function=} onComplete Function that will be called after all specs have run
2100
+ * @return {Promise<undefined>}
1749
2101
  */
1750
2102
  this.execute = function(runnablesToRun, onComplete) {
2103
+ if (this._executedBefore) {
2104
+ topSuite.reset();
2105
+ }
2106
+ this._executedBefore = true;
2107
+ defaultResourcesForRunnable(topSuite.id);
1751
2108
  installGlobalErrors();
1752
2109
 
1753
2110
  if (!runnablesToRun) {
@@ -1805,65 +2162,88 @@ getJasmineRequireObj().Env = function(j$) {
1805
2162
  var jasmineTimer = new j$.Timer();
1806
2163
  jasmineTimer.start();
1807
2164
 
1808
- /**
1809
- * Information passed to the {@link Reporter#jasmineStarted} event.
1810
- * @typedef JasmineStartedInfo
1811
- * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
1812
- * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1813
- */
1814
- reporter.jasmineStarted(
1815
- {
1816
- totalSpecsDefined: totalSpecsDefined,
1817
- order: order
1818
- },
1819
- function() {
1820
- currentlyExecutingSuites.push(topSuite);
1821
-
1822
- processor.execute(function() {
1823
- clearResourcesForRunnable(topSuite.id);
1824
- currentlyExecutingSuites.pop();
1825
- var overallStatus, incompleteReason;
1826
-
1827
- if (hasFailures || topSuite.result.failedExpectations.length > 0) {
1828
- overallStatus = 'failed';
1829
- } else if (focusedRunnables.length > 0) {
1830
- overallStatus = 'incomplete';
1831
- incompleteReason = 'fit() or fdescribe() was found';
1832
- } else if (totalSpecsDefined === 0) {
1833
- overallStatus = 'incomplete';
1834
- incompleteReason = 'No specs found';
1835
- } else {
1836
- overallStatus = 'passed';
2165
+ var Promise = customPromise || global.Promise;
2166
+
2167
+ if (Promise) {
2168
+ return new Promise(function(resolve) {
2169
+ runAll(function() {
2170
+ if (onComplete) {
2171
+ onComplete();
1837
2172
  }
1838
2173
 
1839
- /**
1840
- * Information passed to the {@link Reporter#jasmineDone} event.
1841
- * @typedef JasmineDoneInfo
1842
- * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
1843
- * @property {Int} totalTime - The total time (in ms) that it took to execute the suite
1844
- * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
1845
- * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1846
- * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
1847
- * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
1848
- */
1849
- reporter.jasmineDone(
1850
- {
1851
- overallStatus: overallStatus,
1852
- totalTime: jasmineTimer.elapsed(),
1853
- incompleteReason: incompleteReason,
1854
- order: order,
1855
- failedExpectations: topSuite.result.failedExpectations,
1856
- deprecationWarnings: topSuite.result.deprecationWarnings
1857
- },
1858
- function() {
1859
- if (onComplete) {
1860
- onComplete();
1861
- }
1862
- }
1863
- );
2174
+ resolve();
1864
2175
  });
1865
- }
1866
- );
2176
+ });
2177
+ } else {
2178
+ runAll(function() {
2179
+ if (onComplete) {
2180
+ onComplete();
2181
+ }
2182
+ });
2183
+ }
2184
+
2185
+ function runAll(done) {
2186
+ /**
2187
+ * Information passed to the {@link Reporter#jasmineStarted} event.
2188
+ * @typedef JasmineStartedInfo
2189
+ * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
2190
+ * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
2191
+ * @since 2.0.0
2192
+ */
2193
+ reporter.jasmineStarted(
2194
+ {
2195
+ totalSpecsDefined: totalSpecsDefined,
2196
+ order: order
2197
+ },
2198
+ function() {
2199
+ currentlyExecutingSuites.push(topSuite);
2200
+
2201
+ processor.execute(function() {
2202
+ clearResourcesForRunnable(topSuite.id);
2203
+ currentlyExecutingSuites.pop();
2204
+ var overallStatus, incompleteReason;
2205
+
2206
+ if (
2207
+ hasFailures ||
2208
+ topSuite.result.failedExpectations.length > 0
2209
+ ) {
2210
+ overallStatus = 'failed';
2211
+ } else if (focusedRunnables.length > 0) {
2212
+ overallStatus = 'incomplete';
2213
+ incompleteReason = 'fit() or fdescribe() was found';
2214
+ } else if (totalSpecsDefined === 0) {
2215
+ overallStatus = 'incomplete';
2216
+ incompleteReason = 'No specs found';
2217
+ } else {
2218
+ overallStatus = 'passed';
2219
+ }
2220
+
2221
+ /**
2222
+ * Information passed to the {@link Reporter#jasmineDone} event.
2223
+ * @typedef JasmineDoneInfo
2224
+ * @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
2225
+ * @property {Int} totalTime - The total time (in ms) that it took to execute the suite
2226
+ * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
2227
+ * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
2228
+ * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
2229
+ * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
2230
+ * @since 2.4.0
2231
+ */
2232
+ reporter.jasmineDone(
2233
+ {
2234
+ overallStatus: overallStatus,
2235
+ totalTime: jasmineTimer.elapsed(),
2236
+ incompleteReason: incompleteReason,
2237
+ order: order,
2238
+ failedExpectations: topSuite.result.failedExpectations,
2239
+ deprecationWarnings: topSuite.result.deprecationWarnings
2240
+ },
2241
+ done
2242
+ );
2243
+ });
2244
+ }
2245
+ );
2246
+ }
1867
2247
  };
1868
2248
 
1869
2249
  /**
@@ -2011,7 +2391,8 @@ getJasmineRequireObj().Env = function(j$) {
2011
2391
  expectationFactory: expectationFactory,
2012
2392
  asyncExpectationFactory: suiteAsyncExpectationFactory,
2013
2393
  expectationResultFactory: expectationResultFactory,
2014
- throwOnExpectationFailure: config.oneFailurePerSpec
2394
+ throwOnExpectationFailure: config.oneFailurePerSpec,
2395
+ autoCleanClosures: config.autoCleanClosures
2015
2396
  });
2016
2397
 
2017
2398
  return suite;
@@ -2024,20 +2405,27 @@ getJasmineRequireObj().Env = function(j$) {
2024
2405
  if (specDefinitions.length > 0) {
2025
2406
  throw new Error('describe does not expect any arguments');
2026
2407
  }
2027
- if (currentDeclarationSuite.markedPending) {
2028
- suite.pend();
2408
+ if (currentDeclarationSuite.markedExcluding) {
2409
+ suite.exclude();
2029
2410
  }
2030
2411
  addSpecsToSuite(suite, specDefinitions);
2031
- return suite;
2412
+ if (suite.parentSuite && !suite.children.length) {
2413
+ this.deprecated(
2414
+ 'describe with no children (describe() or it()) is ' +
2415
+ 'deprecated and will be removed in a future version of Jasmine. ' +
2416
+ 'Please either remove the describe or add children to it.'
2417
+ );
2418
+ }
2419
+ return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
2032
2420
  };
2033
2421
 
2034
2422
  this.xdescribe = function(description, specDefinitions) {
2035
2423
  ensureIsNotNested('xdescribe');
2036
2424
  ensureIsFunction(specDefinitions, 'xdescribe');
2037
2425
  var suite = suiteFactory(description);
2038
- suite.pend();
2426
+ suite.exclude();
2039
2427
  addSpecsToSuite(suite, specDefinitions);
2040
- return suite;
2428
+ return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
2041
2429
  };
2042
2430
 
2043
2431
  var focusedRunnables = [];
@@ -2052,7 +2440,7 @@ getJasmineRequireObj().Env = function(j$) {
2052
2440
  unfocusAncestor();
2053
2441
  addSpecsToSuite(suite, specDefinitions);
2054
2442
 
2055
- return suite;
2443
+ return j$.deprecatingSuiteProxy(suite, suite.parentSuite, this);
2056
2444
  };
2057
2445
 
2058
2446
  function addSpecsToSuite(suite, specDefinitions) {
@@ -2062,7 +2450,7 @@ getJasmineRequireObj().Env = function(j$) {
2062
2450
 
2063
2451
  var declarationError = null;
2064
2452
  try {
2065
- specDefinitions.call(suite);
2453
+ specDefinitions.call(j$.deprecatingThisProxy(suite, self));
2066
2454
  } catch (e) {
2067
2455
  declarationError = e;
2068
2456
  }
@@ -2104,6 +2492,7 @@ getJasmineRequireObj().Env = function(j$) {
2104
2492
  beforeAndAfterFns: beforeAndAfterFns(suite),
2105
2493
  expectationFactory: expectationFactory,
2106
2494
  asyncExpectationFactory: specAsyncExpectationFactory,
2495
+ deprecated: self.deprecated,
2107
2496
  resultCallback: specResultCallback,
2108
2497
  getSpecName: function(spec) {
2109
2498
  return getSpecName(spec, suite);
@@ -2120,6 +2509,7 @@ getJasmineRequireObj().Env = function(j$) {
2120
2509
  timeout: timeout || 0
2121
2510
  },
2122
2511
  throwOnExpectationFailure: config.oneFailurePerSpec,
2512
+ autoCleanClosures: config.autoCleanClosures,
2123
2513
  timer: new j$.Timer()
2124
2514
  });
2125
2515
  return spec;
@@ -2142,21 +2532,32 @@ getJasmineRequireObj().Env = function(j$) {
2142
2532
  }
2143
2533
  };
2144
2534
 
2145
- this.it = function(description, fn, timeout) {
2535
+ this.it_ = function(description, fn, timeout) {
2146
2536
  ensureIsNotNested('it');
2147
2537
  // it() sometimes doesn't have a fn argument, so only check the type if
2148
2538
  // it's given.
2149
2539
  if (arguments.length > 1 && typeof fn !== 'undefined') {
2150
2540
  ensureIsFunctionOrAsync(fn, 'it');
2151
2541
  }
2542
+
2543
+ if (timeout) {
2544
+ j$.util.validateTimeout(timeout);
2545
+ }
2546
+
2152
2547
  var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
2153
- if (currentDeclarationSuite.markedPending) {
2154
- spec.pend();
2548
+ if (currentDeclarationSuite.markedExcluding) {
2549
+ spec.exclude();
2155
2550
  }
2156
2551
  currentDeclarationSuite.addChild(spec);
2552
+
2157
2553
  return spec;
2158
2554
  };
2159
2555
 
2556
+ this.it = function(description, fn, timeout) {
2557
+ var spec = this.it_(description, fn, timeout);
2558
+ return j$.deprecatingSpecProxy(spec, this);
2559
+ };
2560
+
2160
2561
  this.xit = function(description, fn, timeout) {
2161
2562
  ensureIsNotNested('xit');
2162
2563
  // xit(), like it(), doesn't always have a fn argument, so only check the
@@ -2164,19 +2565,23 @@ getJasmineRequireObj().Env = function(j$) {
2164
2565
  if (arguments.length > 1 && typeof fn !== 'undefined') {
2165
2566
  ensureIsFunctionOrAsync(fn, 'xit');
2166
2567
  }
2167
- var spec = this.it.apply(this, arguments);
2168
- spec.pend('Temporarily disabled with xit');
2169
- return spec;
2568
+ var spec = this.it_.apply(this, arguments);
2569
+ spec.exclude('Temporarily disabled with xit');
2570
+ return j$.deprecatingSpecProxy(spec, this);
2170
2571
  };
2171
2572
 
2172
2573
  this.fit = function(description, fn, timeout) {
2173
2574
  ensureIsNotNested('fit');
2174
2575
  ensureIsFunctionOrAsync(fn, 'fit');
2576
+
2577
+ if (timeout) {
2578
+ j$.util.validateTimeout(timeout);
2579
+ }
2175
2580
  var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
2176
2581
  currentDeclarationSuite.addChild(spec);
2177
2582
  focusedRunnables.push(spec.id);
2178
2583
  unfocusAncestor();
2179
- return spec;
2584
+ return j$.deprecatingSpecProxy(spec, this);
2180
2585
  };
2181
2586
 
2182
2587
  /**
@@ -2236,6 +2641,11 @@ getJasmineRequireObj().Env = function(j$) {
2236
2641
  this.beforeEach = function(beforeEachFunction, timeout) {
2237
2642
  ensureIsNotNested('beforeEach');
2238
2643
  ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
2644
+
2645
+ if (timeout) {
2646
+ j$.util.validateTimeout(timeout);
2647
+ }
2648
+
2239
2649
  currentDeclarationSuite.beforeEach({
2240
2650
  fn: beforeEachFunction,
2241
2651
  timeout: timeout || 0
@@ -2245,6 +2655,11 @@ getJasmineRequireObj().Env = function(j$) {
2245
2655
  this.beforeAll = function(beforeAllFunction, timeout) {
2246
2656
  ensureIsNotNested('beforeAll');
2247
2657
  ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
2658
+
2659
+ if (timeout) {
2660
+ j$.util.validateTimeout(timeout);
2661
+ }
2662
+
2248
2663
  currentDeclarationSuite.beforeAll({
2249
2664
  fn: beforeAllFunction,
2250
2665
  timeout: timeout || 0
@@ -2254,6 +2669,11 @@ getJasmineRequireObj().Env = function(j$) {
2254
2669
  this.afterEach = function(afterEachFunction, timeout) {
2255
2670
  ensureIsNotNested('afterEach');
2256
2671
  ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
2672
+
2673
+ if (timeout) {
2674
+ j$.util.validateTimeout(timeout);
2675
+ }
2676
+
2257
2677
  afterEachFunction.isCleanup = true;
2258
2678
  currentDeclarationSuite.afterEach({
2259
2679
  fn: afterEachFunction,
@@ -2264,6 +2684,11 @@ getJasmineRequireObj().Env = function(j$) {
2264
2684
  this.afterAll = function(afterAllFunction, timeout) {
2265
2685
  ensureIsNotNested('afterAll');
2266
2686
  ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
2687
+
2688
+ if (timeout) {
2689
+ j$.util.validateTimeout(timeout);
2690
+ }
2691
+
2267
2692
  currentDeclarationSuite.afterAll({
2268
2693
  fn: afterAllFunction,
2269
2694
  timeout: timeout || 0
@@ -2524,7 +2949,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
2524
2949
  if (!j$.isArray_(this.sample)) {
2525
2950
  throw new Error(
2526
2951
  'You must provide an array to arrayContaining, not ' +
2527
- j$.pp(this.sample) +
2952
+ j$.basicPrettyPrinter_(this.sample) +
2528
2953
  '.'
2529
2954
  );
2530
2955
  }
@@ -2565,7 +2990,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
2565
2990
  if (!j$.isArray_(this.sample)) {
2566
2991
  throw new Error(
2567
2992
  'You must provide an array to arrayWithExactContents, not ' +
2568
- j$.pp(this.sample) +
2993
+ j$.basicPrettyPrinter_(this.sample) +
2569
2994
  '.'
2570
2995
  );
2571
2996
  }
@@ -2634,7 +3059,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
2634
3059
  function MapContaining(sample) {
2635
3060
  if (!j$.isMap(sample)) {
2636
3061
  throw new Error(
2637
- 'You must provide a map to `mapContaining`, not ' + j$.pp(sample)
3062
+ 'You must provide a map to `mapContaining`, not ' +
3063
+ j$.basicPrettyPrinter_(sample)
2638
3064
  );
2639
3065
  }
2640
3066
 
@@ -2785,7 +3211,8 @@ getJasmineRequireObj().SetContaining = function(j$) {
2785
3211
  function SetContaining(sample) {
2786
3212
  if (!j$.isSet(sample)) {
2787
3213
  throw new Error(
2788
- 'You must provide a set to `setContaining`, not ' + j$.pp(sample)
3214
+ 'You must provide a set to `setContaining`, not ' +
3215
+ j$.basicPrettyPrinter_(sample)
2789
3216
  );
2790
3217
  }
2791
3218
 
@@ -2823,6 +3250,31 @@ getJasmineRequireObj().SetContaining = function(j$) {
2823
3250
  return SetContaining;
2824
3251
  };
2825
3252
 
3253
+ getJasmineRequireObj().StringContaining = function(j$) {
3254
+ function StringContaining(expected) {
3255
+ if (!j$.isString_(expected)) {
3256
+ throw new Error('Expected is not a String');
3257
+ }
3258
+
3259
+ this.expected = expected;
3260
+ }
3261
+
3262
+ StringContaining.prototype.asymmetricMatch = function(other) {
3263
+ if (!j$.isString_(other)) {
3264
+ // Arrays, etc. don't match no matter what their indexOf returns.
3265
+ return false;
3266
+ }
3267
+
3268
+ return other.indexOf(this.expected) !== -1;
3269
+ };
3270
+
3271
+ StringContaining.prototype.jasmineToString = function() {
3272
+ return '<jasmine.stringContaining("' + this.expected + '")>';
3273
+ };
3274
+
3275
+ return StringContaining;
3276
+ };
3277
+
2826
3278
  getJasmineRequireObj().StringMatching = function(j$) {
2827
3279
  function StringMatching(expected) {
2828
3280
  if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
@@ -2910,34 +3362,49 @@ getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
2910
3362
  matchersUtil,
2911
3363
  customEqualityTesters
2912
3364
  ) {
2913
- var self = Object.create(matchersUtil),
2914
- props,
2915
- i,
2916
- k;
3365
+ var self = Object.create(matchersUtil);
2917
3366
 
2918
- copy(self, customEqualityTesters, 'length');
3367
+ copyAndDeprecate(self, customEqualityTesters, 'length');
2919
3368
 
2920
3369
  for (i = 0; i < customEqualityTesters.length; i++) {
2921
- copy(self, customEqualityTesters, i);
3370
+ copyAndDeprecate(self, customEqualityTesters, i);
2922
3371
  }
2923
3372
 
2924
- var props = arrayProps();
3373
+ // Avoid copying array props if we've previously done so,
3374
+ // to avoid triggering our own deprecation warnings.
3375
+ if (!self.isAsymmetricEqualityTesterArgCompatShim_) {
3376
+ copyAndDeprecateArrayMethods(self);
3377
+ }
3378
+
3379
+ self.isAsymmetricEqualityTesterArgCompatShim_ = true;
3380
+ return self;
3381
+ }
3382
+
3383
+ function copyAndDeprecateArrayMethods(dest) {
3384
+ var props = arrayProps(),
3385
+ i,
3386
+ k;
2925
3387
 
2926
3388
  for (i = 0; i < props.length; i++) {
2927
3389
  k = props[i];
3390
+
2928
3391
  // Skip length (dealt with above), and anything that collides with
2929
3392
  // MatchesUtil e.g. an Array.prototype.contains method added by user code
2930
- if (k !== 'length' && !self[k]) {
2931
- copy(self, Array.prototype, k);
3393
+ if (k !== 'length' && !dest[k]) {
3394
+ copyAndDeprecate(dest, Array.prototype, k);
2932
3395
  }
2933
3396
  }
2934
-
2935
- return self;
2936
3397
  }
2937
3398
 
2938
- function copy(dest, src, propName) {
3399
+ function copyAndDeprecate(dest, src, propName) {
2939
3400
  Object.defineProperty(dest, propName, {
2940
3401
  get: function() {
3402
+ j$.getEnv().deprecated(
3403
+ 'The second argument to asymmetricMatch is now a ' +
3404
+ 'MatchersUtil. Using it as an array of custom equality testers is ' +
3405
+ 'deprecated and will stop working in a future release. ' +
3406
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#asymmetricMatch-cet> for details.'
3407
+ );
2941
3408
  return src[propName];
2942
3409
  }
2943
3410
  });
@@ -3019,6 +3486,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
3019
3486
  /**
3020
3487
  * Get the "this" object that was passed to a specific invocation of this spy.
3021
3488
  * @name Spy#calls#thisFor
3489
+ * @since 3.8.0
3022
3490
  * @function
3023
3491
  * @param {Integer} index The 0-based invocation index.
3024
3492
  * @return {Object?}
@@ -3180,6 +3648,7 @@ getJasmineRequireObj().Clock = function() {
3180
3648
 
3181
3649
  /**
3182
3650
  * @class Clock
3651
+ * @since 1.3.0
3183
3652
  * @classdesc Jasmine's mock clock is used when testing time dependent code.<br>
3184
3653
  * _Note:_ Do not construct this directly. You can get the current clock with
3185
3654
  * {@link jasmine.clock}.
@@ -3410,13 +3879,31 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
3410
3879
  var currentTime = 0;
3411
3880
  var delayedFnCount = 0;
3412
3881
  var deletedKeys = [];
3882
+ var ticking = false;
3413
3883
 
3414
3884
  self.tick = function(millis, tickDate) {
3415
- millis = millis || 0;
3416
- var endTime = currentTime + millis;
3885
+ if (ticking) {
3886
+ j$.getEnv().deprecated(
3887
+ 'The behavior of reentrant calls to jasmine.clock().tick() will ' +
3888
+ 'change in a future version. Either modify the affected spec to ' +
3889
+ 'not call tick() from within a setTimeout or setInterval handler, ' +
3890
+ 'or be aware that it may behave differently in the future. See ' +
3891
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-reentrant-calls-to-jasmine-clock-tick> ' +
3892
+ 'for details.'
3893
+ );
3894
+ }
3895
+
3896
+ ticking = true;
3417
3897
 
3418
- runScheduledFunctions(endTime, tickDate);
3419
- currentTime = endTime;
3898
+ try {
3899
+ millis = millis || 0;
3900
+ var endTime = currentTime + millis;
3901
+
3902
+ runScheduledFunctions(endTime, tickDate);
3903
+ currentTime = endTime;
3904
+ } finally {
3905
+ ticking = false;
3906
+ }
3420
3907
  };
3421
3908
 
3422
3909
  self.scheduleFunction = function(
@@ -3581,6 +4068,302 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
3581
4068
  return DelayedFunctionScheduler;
3582
4069
  };
3583
4070
 
4071
+ /* eslint-disable compat/compat */
4072
+ // TODO: Remove this in the next major release.
4073
+ getJasmineRequireObj().deprecatingSpecProxy = function(j$) {
4074
+ function isMember(target, prop) {
4075
+ return (
4076
+ Object.keys(target).indexOf(prop) !== -1 ||
4077
+ Object.keys(j$.Spec.prototype).indexOf(prop) !== -1
4078
+ );
4079
+ }
4080
+
4081
+ function isAllowedMember(prop) {
4082
+ return prop === 'id' || prop === 'description' || prop === 'getFullName';
4083
+ }
4084
+
4085
+ function msg(member) {
4086
+ var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
4087
+ return (
4088
+ 'Access to private Spec members (in this case `' +
4089
+ memberName +
4090
+ '`) is not supported and will break in ' +
4091
+ 'a future release. See <https://jasmine.github.io/api/edge/Spec.html> ' +
4092
+ 'for correct usage.'
4093
+ );
4094
+ }
4095
+
4096
+ try {
4097
+ new Proxy({}, {});
4098
+ } catch (e) {
4099
+ // Environment does not support Poxy.
4100
+ return function(spec) {
4101
+ return spec;
4102
+ };
4103
+ }
4104
+
4105
+ function DeprecatingSpecProxyHandler(env) {
4106
+ this._env = env;
4107
+ }
4108
+
4109
+ DeprecatingSpecProxyHandler.prototype.get = function(target, prop, receiver) {
4110
+ this._maybeDeprecate(target, prop);
4111
+
4112
+ if (prop === 'getFullName') {
4113
+ // getFullName calls a private method. Re-bind 'this' to avoid a bogus
4114
+ // deprecation warning.
4115
+ return target.getFullName.bind(target);
4116
+ } else {
4117
+ return target[prop];
4118
+ }
4119
+ };
4120
+
4121
+ DeprecatingSpecProxyHandler.prototype.set = function(target, prop, value) {
4122
+ this._maybeDeprecate(target, prop);
4123
+ return (target[prop] = value);
4124
+ };
4125
+
4126
+ DeprecatingSpecProxyHandler.prototype._maybeDeprecate = function(
4127
+ target,
4128
+ prop
4129
+ ) {
4130
+ if (isMember(target, prop) && !isAllowedMember(prop)) {
4131
+ this._env.deprecated(msg(prop));
4132
+ }
4133
+ };
4134
+
4135
+ function deprecatingSpecProxy(spec, env) {
4136
+ return new Proxy(spec, new DeprecatingSpecProxyHandler(env));
4137
+ }
4138
+
4139
+ return deprecatingSpecProxy;
4140
+ };
4141
+
4142
+ /* eslint-disable compat/compat */
4143
+ // TODO: Remove this in the next major release.
4144
+ getJasmineRequireObj().deprecatingSuiteProxy = function(j$) {
4145
+ var allowedMembers = [
4146
+ 'id',
4147
+ 'children',
4148
+ 'description',
4149
+ 'parentSuite',
4150
+ 'getFullName'
4151
+ ];
4152
+
4153
+ function isMember(target, prop) {
4154
+ return (
4155
+ Object.keys(target).indexOf(prop) !== -1 ||
4156
+ Object.keys(j$.Suite.prototype).indexOf(prop) !== -1
4157
+ );
4158
+ }
4159
+
4160
+ function isAllowedMember(prop) {
4161
+ return allowedMembers.indexOf(prop) !== -1;
4162
+ }
4163
+
4164
+ function msg(member) {
4165
+ var memberName = member.toString().replace(/^Symbol\((.+)\)$/, '$1');
4166
+ return (
4167
+ 'Access to private Suite members (in this case `' +
4168
+ memberName +
4169
+ '`) is not supported and will break in ' +
4170
+ 'a future release. See <https://jasmine.github.io/api/edge/Suite.html> ' +
4171
+ 'for correct usage.'
4172
+ );
4173
+ }
4174
+ try {
4175
+ new Proxy({}, {});
4176
+ } catch (e) {
4177
+ // Environment does not support Poxy.
4178
+ return function(suite) {
4179
+ return suite;
4180
+ };
4181
+ }
4182
+
4183
+ function DeprecatingSuiteProxyHandler(parentSuite, env) {
4184
+ this._parentSuite = parentSuite;
4185
+ this._env = env;
4186
+ }
4187
+
4188
+ DeprecatingSuiteProxyHandler.prototype.get = function(
4189
+ target,
4190
+ prop,
4191
+ receiver
4192
+ ) {
4193
+ if (prop === 'children') {
4194
+ if (!this._children) {
4195
+ this._children = target.children.map(
4196
+ this._proxyForChild.bind(this, receiver)
4197
+ );
4198
+ }
4199
+
4200
+ return this._children;
4201
+ } else if (prop === 'parentSuite') {
4202
+ return this._parentSuite;
4203
+ } else {
4204
+ this._maybeDeprecate(target, prop);
4205
+ return target[prop];
4206
+ }
4207
+ };
4208
+
4209
+ DeprecatingSuiteProxyHandler.prototype.set = function(target, prop, value) {
4210
+ this._maybeDeprecate(target, prop);
4211
+ return (target[prop] = value);
4212
+ };
4213
+
4214
+ DeprecatingSuiteProxyHandler.prototype._maybeDeprecate = function(
4215
+ target,
4216
+ prop
4217
+ ) {
4218
+ if (isMember(target, prop) && !isAllowedMember(prop)) {
4219
+ this._env.deprecated(msg(prop));
4220
+ }
4221
+ };
4222
+
4223
+ DeprecatingSuiteProxyHandler.prototype._proxyForChild = function(
4224
+ ownProxy,
4225
+ child
4226
+ ) {
4227
+ if (child.children) {
4228
+ return deprecatingSuiteProxy(child, ownProxy, this._env);
4229
+ } else {
4230
+ return j$.deprecatingSpecProxy(child, this._env);
4231
+ }
4232
+ };
4233
+
4234
+ function deprecatingSuiteProxy(suite, parentSuite, env) {
4235
+ return new Proxy(suite, new DeprecatingSuiteProxyHandler(parentSuite, env));
4236
+ }
4237
+
4238
+ return deprecatingSuiteProxy;
4239
+ };
4240
+
4241
+ /* eslint-disable compat/compat */
4242
+ // TODO: Remove this in the next major release.
4243
+ getJasmineRequireObj().deprecatingThisProxy = function(j$) {
4244
+ var msg =
4245
+ "Access to 'this' in describe functions (and in arrow functions " +
4246
+ 'inside describe functions) is deprecated.';
4247
+
4248
+ try {
4249
+ new Proxy({}, {});
4250
+ } catch (e) {
4251
+ // Environment does not support Poxy.
4252
+ return function(suite) {
4253
+ return suite;
4254
+ };
4255
+ }
4256
+
4257
+ function DeprecatingThisProxyHandler(env) {
4258
+ this._env = env;
4259
+ }
4260
+
4261
+ DeprecatingThisProxyHandler.prototype.get = function(target, prop, receiver) {
4262
+ this._env.deprecated(msg);
4263
+ return target[prop];
4264
+ };
4265
+
4266
+ DeprecatingThisProxyHandler.prototype.set = function(target, prop, value) {
4267
+ this._env.deprecated(msg);
4268
+ return (target[prop] = value);
4269
+ };
4270
+
4271
+ return function(suite, env) {
4272
+ return new Proxy(suite, new DeprecatingThisProxyHandler(env));
4273
+ };
4274
+ };
4275
+
4276
+ getJasmineRequireObj().Deprecator = function(j$) {
4277
+ function Deprecator(topSuite) {
4278
+ this.topSuite_ = topSuite;
4279
+ this.verbose_ = false;
4280
+ this.toSuppress_ = [];
4281
+ }
4282
+
4283
+ var verboseNote =
4284
+ 'Note: This message will be shown only once. Set the verboseDeprecations ' +
4285
+ 'config property to true to see every occurrence.';
4286
+
4287
+ Deprecator.prototype.verboseDeprecations = function(enabled) {
4288
+ this.verbose_ = enabled;
4289
+ };
4290
+
4291
+ // runnable is a spec or a suite.
4292
+ // deprecation is a string or an Error.
4293
+ // See Env#deprecated for a description of the options argument.
4294
+ Deprecator.prototype.addDeprecationWarning = function(
4295
+ runnable,
4296
+ deprecation,
4297
+ options
4298
+ ) {
4299
+ options = options || {};
4300
+
4301
+ if (!this.verbose_ && !j$.isError_(deprecation)) {
4302
+ if (this.toSuppress_.indexOf(deprecation) !== -1) {
4303
+ return;
4304
+ }
4305
+ this.toSuppress_.push(deprecation);
4306
+ }
4307
+
4308
+ this.log_(runnable, deprecation, options);
4309
+ this.report_(runnable, deprecation, options);
4310
+ };
4311
+
4312
+ Deprecator.prototype.log_ = function(runnable, deprecation, options) {
4313
+ var context;
4314
+
4315
+ if (j$.isError_(deprecation)) {
4316
+ console.error(deprecation);
4317
+ return;
4318
+ }
4319
+
4320
+ if (runnable === this.topSuite_ || options.ignoreRunnable) {
4321
+ context = '';
4322
+ } else if (runnable.children) {
4323
+ context = ' (in suite: ' + runnable.getFullName() + ')';
4324
+ } else {
4325
+ context = ' (in spec: ' + runnable.getFullName() + ')';
4326
+ }
4327
+
4328
+ if (!options.omitStackTrace) {
4329
+ context += '\n' + this.stackTrace_();
4330
+ }
4331
+
4332
+ if (!this.verbose_) {
4333
+ context += '\n' + verboseNote;
4334
+ }
4335
+
4336
+ console.error('DEPRECATION: ' + deprecation + context);
4337
+ };
4338
+
4339
+ Deprecator.prototype.stackTrace_ = function() {
4340
+ var formatter = new j$.ExceptionFormatter();
4341
+ return formatter.stack(j$.util.errorWithStack()).replace(/^Error\n/m, '');
4342
+ };
4343
+
4344
+ Deprecator.prototype.report_ = function(runnable, deprecation, options) {
4345
+ if (options.ignoreRunnable) {
4346
+ runnable = this.topSuite_;
4347
+ }
4348
+
4349
+ if (j$.isError_(deprecation)) {
4350
+ runnable.addDeprecationWarning(deprecation);
4351
+ return;
4352
+ }
4353
+
4354
+ if (!this.verbose_) {
4355
+ deprecation += '\n' + verboseNote;
4356
+ }
4357
+
4358
+ runnable.addDeprecationWarning({
4359
+ message: deprecation,
4360
+ omitStackTrace: options.omitStackTrace || false
4361
+ });
4362
+ };
4363
+
4364
+ return Deprecator;
4365
+ };
4366
+
3584
4367
  getJasmineRequireObj().errors = function() {
3585
4368
  function ExpectationFailed() {}
3586
4369
 
@@ -3684,7 +4467,7 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
3684
4467
  }
3685
4468
 
3686
4469
  if (!empty) {
3687
- return 'error properties: ' + j$.pp(result) + '\n';
4470
+ return 'error properties: ' + j$.basicPrettyPrinter_(result) + '\n';
3688
4471
  }
3689
4472
 
3690
4473
  return '';
@@ -3822,6 +4605,7 @@ getJasmineRequireObj().Expectation = function(j$) {
3822
4605
  * Otherwise evaluate the matcher.
3823
4606
  * @member
3824
4607
  * @name async-matchers#already
4608
+ * @since 3.8.0
3825
4609
  * @type {async-matchers}
3826
4610
  * @example
3827
4611
  * await expectAsync(myPromise).already.toBeResolved();
@@ -4037,7 +4821,7 @@ getJasmineRequireObj().buildExpectationResult = function(j$) {
4037
4821
  var result = {
4038
4822
  matcherName: options.matcherName,
4039
4823
  message: message(),
4040
- stack: stack(),
4824
+ stack: options.omitStackTrace ? '' : stack(),
4041
4825
  passed: options.passed
4042
4826
  };
4043
4827
 
@@ -4123,7 +4907,15 @@ getJasmineRequireObj().Expector = function(j$) {
4123
4907
 
4124
4908
  this.args.unshift(this.actual);
4125
4909
 
4126
- var matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
4910
+ // TODO: Remove support for passing customEqualityTesters in the next major release.
4911
+ var matcher;
4912
+
4913
+ if (matcherFactory.length >= 2) {
4914
+ matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
4915
+ } else {
4916
+ matcher = matcherFactory(this.matchersUtil);
4917
+ }
4918
+
4127
4919
  var comparisonFunc = this.filters.selectComparisonFunc(matcher);
4128
4920
  return comparisonFunc || matcher.compare;
4129
4921
  };
@@ -4230,16 +5022,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
4230
5022
  function taggedOnError(error) {
4231
5023
  var substituteMsg;
4232
5024
 
4233
- if (error) {
5025
+ if (j$.isError_(error)) {
4234
5026
  error.jasmineMessage = jasmineMessage + ': ' + error;
4235
5027
  } else {
4236
- substituteMsg = jasmineMessage + ' with no error or message';
5028
+ if (error) {
5029
+ substituteMsg = jasmineMessage + ': ' + error;
5030
+ } else {
5031
+ substituteMsg = jasmineMessage + ' with no error or message';
5032
+ }
4237
5033
 
4238
5034
  if (errorType === 'unhandledRejection') {
4239
5035
  substituteMsg +=
4240
5036
  '\n' +
4241
5037
  '(Tip: to get a useful stack trace, use ' +
4242
- 'Promise.reject(new Error(...)) instead of Promise.reject().)';
5038
+ 'Promise.reject(new Error(...)) instead of Promise.reject(' +
5039
+ (error ? '...' : '') +
5040
+ ').)';
4243
5041
  }
4244
5042
 
4245
5043
  error = new Error(substituteMsg);
@@ -4802,8 +5600,6 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
4802
5600
  };
4803
5601
 
4804
5602
  getJasmineRequireObj().MatchersUtil = function(j$) {
4805
- // TODO: convert all uses of j$.pp to use the injected pp
4806
-
4807
5603
  /**
4808
5604
  * @class MatchersUtil
4809
5605
  * @classdesc Utilities for use in implementing matchers.<br>
@@ -4834,10 +5630,19 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
4834
5630
  * @since 2.0.0
4835
5631
  * @param {*} haystack The collection to search
4836
5632
  * @param {*} needle The value to search for
4837
- * @param [customTesters] An array of custom equality testers
5633
+ * @param [customTesters] An array of custom equality testers. Deprecated.
5634
+ * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0.
4838
5635
  * @returns {boolean} True if `needle` was found in `haystack`
4839
5636
  */
4840
5637
  MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
5638
+ if (customTesters) {
5639
+ j$.getEnv().deprecated(
5640
+ 'Passing custom equality testers ' +
5641
+ 'to MatchersUtil#contains is deprecated. ' +
5642
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
5643
+ );
5644
+ }
5645
+
4841
5646
  if (j$.isSet(haystack)) {
4842
5647
  return haystack.has(needle);
4843
5648
  }
@@ -4847,8 +5652,13 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
4847
5652
  (!!haystack && !haystack.indexOf)
4848
5653
  ) {
4849
5654
  for (var i = 0; i < haystack.length; i++) {
4850
- if (this.equals(haystack[i], needle, customTesters)) {
4851
- return true;
5655
+ try {
5656
+ this.suppressDeprecation_ = true;
5657
+ if (this.equals(haystack[i], needle, customTesters)) {
5658
+ return true;
5659
+ }
5660
+ } finally {
5661
+ this.suppressDeprecation_ = false;
4852
5662
  }
4853
5663
  }
4854
5664
  return false;
@@ -4952,7 +5762,8 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
4952
5762
  * @since 2.0.0
4953
5763
  * @param {*} a The first value to compare
4954
5764
  * @param {*} b The second value to compare
4955
- * @param [customTesters] An array of custom equality testers
5765
+ * @param [customTesters] An array of custom equality testers. Deprecated.
5766
+ * As of 3.6 this parameter no longer needs to be passed. It will be removed in 4.0.
4956
5767
  * @returns {boolean} True if the values are equal
4957
5768
  */
4958
5769
  MatchersUtil.prototype.equals = function(
@@ -4966,6 +5777,22 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
4966
5777
  if (isDiffBuilder(customTestersOrDiffBuilder)) {
4967
5778
  diffBuilder = customTestersOrDiffBuilder;
4968
5779
  } else {
5780
+ if (customTestersOrDiffBuilder && !this.suppressDeprecation_) {
5781
+ j$.getEnv().deprecated(
5782
+ 'Passing custom equality testers ' +
5783
+ 'to MatchersUtil#equals is deprecated. ' +
5784
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
5785
+ );
5786
+ }
5787
+
5788
+ if (diffBuilderOrNothing) {
5789
+ j$.getEnv().deprecated(
5790
+ 'Diff builder should be passed ' +
5791
+ 'as the third argument to MatchersUtil#equals, not the fourth. ' +
5792
+ 'See <https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#matchers-cet> for details.'
5793
+ );
5794
+ }
5795
+
4969
5796
  customTesters = customTestersOrDiffBuilder;
4970
5797
  diffBuilder = diffBuilderOrNothing;
4971
5798
  }
@@ -5462,9 +6289,33 @@ getJasmineRequireObj().MatchersUtil = function(j$) {
5462
6289
  /**
5463
6290
  * @interface AsymmetricEqualityTester
5464
6291
  * @classdesc An asymmetric equality tester is an object that can match multiple
5465
- * objects. Examples include jasmine.any() and jasmine.stringMatching().
5466
- * User-defined asymmetric equality testers can also be defined and used in
5467
- * expectations.
6292
+ * objects. Examples include jasmine.any() and jasmine.stringMatching(). Jasmine
6293
+ * includes a number of built-in asymmetric equality testers, such as
6294
+ * {@link jasmine.objectContaining}. User-defined asymmetric equality testers are
6295
+ * also supported.
6296
+ *
6297
+ * Asymmetric equality testers work with any matcher, including user-defined
6298
+ * custom matchers, that uses {@link MatchersUtil#equals} or
6299
+ * {@link MatchersUtil#contains}.
6300
+ *
6301
+ * @example
6302
+ * function numberDivisibleBy(divisor) {
6303
+ * return {
6304
+ * asymmetricMatch: function(n) {
6305
+ * return typeof n === 'number' && n % divisor === 0;
6306
+ * },
6307
+ * jasmineToString: function() {
6308
+ * return `<a number divisible by ${divisor}>`;
6309
+ * }
6310
+ * };
6311
+ * }
6312
+ *
6313
+ * var actual = {
6314
+ * n: 2,
6315
+ * otherFields: "don't care"
6316
+ * };
6317
+ *
6318
+ * expect(actual).toEqual(jasmine.objectContaining({n: numberDivisibleBy(2)}));
5468
6319
  * @see custom_asymmetric_equality_testers
5469
6320
  * @since 2.0.0
5470
6321
  */
@@ -7087,7 +7938,7 @@ getJasmineRequireObj().toThrowMatching = function(j$) {
7087
7938
  return toThrowMatching;
7088
7939
  };
7089
7940
 
7090
- getJasmineRequireObj().MockDate = function() {
7941
+ getJasmineRequireObj().MockDate = function(j$) {
7091
7942
  function MockDate(global) {
7092
7943
  var self = this;
7093
7944
  var currentTime = 0;
@@ -7105,6 +7956,14 @@ getJasmineRequireObj().MockDate = function() {
7105
7956
  if (mockDate instanceof GlobalDate) {
7106
7957
  currentTime = mockDate.getTime();
7107
7958
  } else {
7959
+ if (!j$.util.isUndefined(mockDate)) {
7960
+ j$.getEnv().deprecated(
7961
+ 'The argument to jasmine.clock().mockDate(), if specified, ' +
7962
+ 'should be a Date instance. Passing anything other than a Date ' +
7963
+ 'will be treated as an error in a future release.'
7964
+ );
7965
+ }
7966
+
7108
7967
  currentTime = new GlobalDate().getTime();
7109
7968
  }
7110
7969
 
@@ -7606,10 +8465,14 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7606
8465
  StopExecutionError.prototype = new Error();
7607
8466
  j$.StopExecutionError = StopExecutionError;
7608
8467
 
7609
- function once(fn) {
8468
+ function once(fn, onTwice) {
7610
8469
  var called = false;
7611
8470
  return function(arg) {
7612
- if (!called) {
8471
+ if (called) {
8472
+ if (onTwice) {
8473
+ onTwice();
8474
+ }
8475
+ } else {
7613
8476
  called = true;
7614
8477
  // Direct call using single parameter, because cleanup/next does not need more
7615
8478
  fn(arg);
@@ -7618,6 +8481,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7618
8481
  };
7619
8482
  }
7620
8483
 
8484
+ function fallbackOnMultipleDone() {
8485
+ console.error(
8486
+ new Error(
8487
+ "An asynchronous function called its 'done' " +
8488
+ 'callback more than once, in a QueueRunner without a onMultipleDone ' +
8489
+ 'handler.'
8490
+ )
8491
+ );
8492
+ }
8493
+
7621
8494
  function emptyFn() {}
7622
8495
 
7623
8496
  function QueueRunner(attrs) {
@@ -7632,6 +8505,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7632
8505
  fn();
7633
8506
  };
7634
8507
  this.onException = attrs.onException || emptyFn;
8508
+ this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
7635
8509
  this.userContext = attrs.userContext || new j$.UserContext();
7636
8510
  this.timeout = attrs.timeout || {
7637
8511
  setTimeout: setTimeout,
@@ -7689,8 +8563,9 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7689
8563
  var self = this,
7690
8564
  completedSynchronously = true,
7691
8565
  handleError = function handleError(error) {
8566
+ // TODO probably shouldn't next() right away here.
8567
+ // That makes debugging async failures much more confusing.
7692
8568
  onException(error);
7693
- next(error);
7694
8569
  },
7695
8570
  cleanup = once(function cleanup() {
7696
8571
  if (timeoutId !== void 0) {
@@ -7698,31 +8573,52 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7698
8573
  }
7699
8574
  self.globalErrors.popListener(handleError);
7700
8575
  }),
7701
- next = once(function next(err) {
7702
- cleanup();
8576
+ next = once(
8577
+ function next(err) {
8578
+ cleanup();
7703
8579
 
7704
- if (j$.isError_(err)) {
7705
- if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
7706
- self.fail(err);
8580
+ if (j$.isError_(err)) {
8581
+ if (!(err instanceof StopExecutionError) && !err.jasmineMessage) {
8582
+ self.fail(err);
8583
+ }
8584
+ self.errored = errored = true;
8585
+ } else if (typeof err !== 'undefined' && !self.errored) {
8586
+ self.deprecated(
8587
+ 'Any argument passed to a done callback will be treated as an ' +
8588
+ 'error in a future release. Call the done callback without ' +
8589
+ "arguments if you don't want to trigger a spec failure."
8590
+ );
7707
8591
  }
7708
- self.errored = errored = true;
7709
- }
7710
8592
 
7711
- function runNext() {
7712
- if (self.completeOnFirstError && errored) {
7713
- self.skipToCleanup(iterativeIndex);
7714
- } else {
7715
- self.run(iterativeIndex + 1);
8593
+ function runNext() {
8594
+ if (self.completeOnFirstError && errored) {
8595
+ self.skipToCleanup(iterativeIndex);
8596
+ } else {
8597
+ self.run(iterativeIndex + 1);
8598
+ }
7716
8599
  }
7717
- }
7718
8600
 
7719
- if (completedSynchronously) {
7720
- self.setTimeout(runNext);
7721
- } else {
7722
- runNext();
8601
+ if (completedSynchronously) {
8602
+ self.setTimeout(runNext);
8603
+ } else {
8604
+ runNext();
8605
+ }
8606
+ },
8607
+ function() {
8608
+ try {
8609
+ if (!timedOut) {
8610
+ self.onMultipleDone();
8611
+ }
8612
+ } catch (error) {
8613
+ // Any error we catch here is probably due to a bug in Jasmine,
8614
+ // and it's not likely to end up anywhere useful if we let it
8615
+ // propagate. Log it so it can at least show up when debugging.
8616
+ console.error(error);
8617
+ }
7723
8618
  }
7724
- }),
8619
+ ),
7725
8620
  errored = false,
8621
+ timedOut = false,
7726
8622
  queueableFn = self.queueableFns[iterativeIndex],
7727
8623
  timeoutId,
7728
8624
  maybeThenable;
@@ -7738,6 +8634,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7738
8634
  if (queueableFn.timeout !== undefined) {
7739
8635
  var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
7740
8636
  timeoutId = self.setTimeout(function() {
8637
+ timedOut = true;
7741
8638
  var error = new Error(
7742
8639
  'Timeout - Async function did not complete within ' +
7743
8640
  timeoutInterval +
@@ -7746,6 +8643,9 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7746
8643
  ? '(custom timeout)'
7747
8644
  : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
7748
8645
  );
8646
+ // TODO Need to decide what to do about a successful completion after a
8647
+ // timeout. That should probably not be a deprecation, and maybe not
8648
+ // an error in 4.0. (But a diagnostic of some sort might be helpful.)
7749
8649
  onException(error);
7750
8650
  next();
7751
8651
  }, timeoutInterval);
@@ -7811,30 +8711,39 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7811
8711
 
7812
8712
  this.clearStack(function() {
7813
8713
  self.globalErrors.popListener(self.handleFinalError);
7814
- self.onComplete(self.errored && new StopExecutionError());
8714
+
8715
+ if (self.errored) {
8716
+ self.onComplete(new StopExecutionError());
8717
+ } else {
8718
+ self.onComplete();
8719
+ }
7815
8720
  });
7816
8721
  };
7817
8722
 
7818
8723
  QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
8724
+ var msg;
8725
+
7819
8726
  if (retval && j$.isFunction_(retval.then)) {
7820
- // Issue a warning that matches the user's code
8727
+ // Issue a warning that matches the user's code.
8728
+ // Omit the stack trace because there's almost certainly no user code
8729
+ // on the stack at this point.
7821
8730
  if (j$.isAsyncFunction_(fn)) {
7822
- this.deprecated(
8731
+ msg =
7823
8732
  'An asynchronous before/it/after ' +
7824
- 'function was defined with the async keyword but also took a ' +
7825
- 'done callback. This is not supported and will stop working in' +
7826
- ' the future. Either remove the done callback (recommended) or ' +
7827
- 'remove the async keyword.'
7828
- );
8733
+ 'function was defined with the async keyword but also took a ' +
8734
+ 'done callback. This is not supported and will stop working in' +
8735
+ ' the future. Either remove the done callback (recommended) or ' +
8736
+ 'remove the async keyword.';
7829
8737
  } else {
7830
- this.deprecated(
8738
+ msg =
7831
8739
  'An asynchronous before/it/after ' +
7832
- 'function took a done callback but also returned a promise. ' +
7833
- 'This is not supported and will stop working in the future. ' +
7834
- 'Either remove the done callback (recommended) or change the ' +
7835
- 'function to not return a promise.'
7836
- );
8740
+ 'function took a done callback but also returned a promise. ' +
8741
+ 'This is not supported and will stop working in the future. ' +
8742
+ 'Either remove the done callback (recommended) or change the ' +
8743
+ 'function to not return a promise.';
7837
8744
  }
8745
+
8746
+ this.deprecated(msg, { omitStackTrace: true });
7838
8747
  }
7839
8748
  };
7840
8749
 
@@ -7842,7 +8751,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
7842
8751
  };
7843
8752
 
7844
8753
  getJasmineRequireObj().ReportDispatcher = function(j$) {
7845
- function ReportDispatcher(methods, queueRunnerFactory) {
8754
+ function ReportDispatcher(methods, queueRunnerFactory, deprecated) {
7846
8755
  var dispatchedMethods = methods || [];
7847
8756
 
7848
8757
  for (var i = 0; i < dispatchedMethods.length; i++) {
@@ -7886,7 +8795,18 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
7886
8795
  queueRunnerFactory({
7887
8796
  queueableFns: fns,
7888
8797
  onComplete: onComplete,
7889
- isReporter: true
8798
+ isReporter: true,
8799
+ onMultipleDone: function() {
8800
+ deprecated(
8801
+ "An asynchronous reporter callback called its 'done' callback " +
8802
+ 'more than once. This is a bug in the reporter callback in ' +
8803
+ 'question. This will be treated as an error in a future ' +
8804
+ 'version. See' +
8805
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
8806
+ 'for more information.',
8807
+ { ignoreRunnable: true }
8808
+ );
8809
+ }
7890
8810
  });
7891
8811
  }
7892
8812
 
@@ -8516,7 +9436,7 @@ getJasmineRequireObj().Spy = function(j$) {
8516
9436
  "Spy '" +
8517
9437
  strategyArgs.name +
8518
9438
  "' received a call with arguments " +
8519
- j$.pp(Array.prototype.slice.call(args)) +
9439
+ j$.basicPrettyPrinter_(Array.prototype.slice.call(args)) +
8520
9440
  ' but all configured strategies specify other arguments.'
8521
9441
  );
8522
9442
  } else {
@@ -9233,9 +10153,17 @@ getJasmineRequireObj().Suite = function(j$) {
9233
10153
  /**
9234
10154
  * @interface Suite
9235
10155
  * @see Env#topSuite
10156
+ * @since 2.0.0
9236
10157
  */
9237
10158
  function Suite(attrs) {
9238
10159
  this.env = attrs.env;
10160
+ /**
10161
+ * The unique ID of this suite.
10162
+ * @name Suite#id
10163
+ * @readonly
10164
+ * @type {string}
10165
+ * @since 2.0.0
10166
+ */
9239
10167
  this.id = attrs.id;
9240
10168
  /**
9241
10169
  * The parent of this suite, or null if this is the top suite.
@@ -9249,12 +10177,15 @@ getJasmineRequireObj().Suite = function(j$) {
9249
10177
  * @name Suite#description
9250
10178
  * @readonly
9251
10179
  * @type {string}
10180
+ * @since 2.0.0
9252
10181
  */
9253
10182
  this.description = attrs.description;
9254
10183
  this.expectationFactory = attrs.expectationFactory;
9255
10184
  this.asyncExpectationFactory = attrs.asyncExpectationFactory;
9256
10185
  this.expectationResultFactory = attrs.expectationResultFactory;
9257
10186
  this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
10187
+ this.autoCleanClosures =
10188
+ attrs.autoCleanClosures === undefined ? true : !!attrs.autoCleanClosures;
9258
10189
 
9259
10190
  this.beforeFns = [];
9260
10191
  this.afterFns = [];
@@ -9267,29 +10198,11 @@ getJasmineRequireObj().Suite = function(j$) {
9267
10198
  * The suite's children.
9268
10199
  * @name Suite#children
9269
10200
  * @type {Array.<(Spec|Suite)>}
10201
+ * @since 2.0.0
9270
10202
  */
9271
10203
  this.children = [];
9272
10204
 
9273
- /**
9274
- * @typedef SuiteResult
9275
- * @property {Int} id - The unique id of this suite.
9276
- * @property {String} description - The description text passed to the {@link describe} that made this suite.
9277
- * @property {String} fullName - The full description including all ancestors of this suite.
9278
- * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
9279
- * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
9280
- * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
9281
- * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
9282
- * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
9283
- */
9284
- this.result = {
9285
- id: this.id,
9286
- description: this.description,
9287
- fullName: this.getFullName(),
9288
- failedExpectations: [],
9289
- deprecationWarnings: [],
9290
- duration: null,
9291
- properties: null
9292
- };
10205
+ this.reset();
9293
10206
  }
9294
10207
 
9295
10208
  Suite.prototype.setSuiteProperty = function(key, value) {
@@ -9310,6 +10223,7 @@ getJasmineRequireObj().Suite = function(j$) {
9310
10223
  * @name Suite#getFullName
9311
10224
  * @function
9312
10225
  * @returns {string}
10226
+ * @since 2.0.0
9313
10227
  */
9314
10228
  Suite.prototype.getFullName = function() {
9315
10229
  var fullName = [];
@@ -9325,10 +10239,22 @@ getJasmineRequireObj().Suite = function(j$) {
9325
10239
  return fullName.join(' ');
9326
10240
  };
9327
10241
 
10242
+ /*
10243
+ * Mark the suite with "pending" status
10244
+ */
9328
10245
  Suite.prototype.pend = function() {
9329
10246
  this.markedPending = true;
9330
10247
  };
9331
10248
 
10249
+ /*
10250
+ * Like {@link Suite#pend}, but pending state will survive {@link Spec#reset}
10251
+ * Useful for fdescribe, xdescribe, where pending state should remain.
10252
+ */
10253
+ Suite.prototype.exclude = function() {
10254
+ this.pend();
10255
+ this.markedExcluding = true;
10256
+ };
10257
+
9332
10258
  Suite.prototype.beforeEach = function(fn) {
9333
10259
  this.beforeFns.unshift(fn);
9334
10260
  };
@@ -9360,10 +10286,40 @@ getJasmineRequireObj().Suite = function(j$) {
9360
10286
  }
9361
10287
 
9362
10288
  Suite.prototype.cleanupBeforeAfter = function() {
9363
- removeFns(this.beforeAllFns);
9364
- removeFns(this.afterAllFns);
9365
- removeFns(this.beforeFns);
9366
- removeFns(this.afterFns);
10289
+ if (this.autoCleanClosures) {
10290
+ removeFns(this.beforeAllFns);
10291
+ removeFns(this.afterAllFns);
10292
+ removeFns(this.beforeFns);
10293
+ removeFns(this.afterFns);
10294
+ }
10295
+ };
10296
+
10297
+ Suite.prototype.reset = function() {
10298
+ /**
10299
+ * @typedef SuiteResult
10300
+ * @property {Int} id - The unique id of this suite.
10301
+ * @property {String} description - The description text passed to the {@link describe} that made this suite.
10302
+ * @property {String} fullName - The full description including all ancestors of this suite.
10303
+ * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
10304
+ * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
10305
+ * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
10306
+ * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
10307
+ * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
10308
+ * @since 2.0.0
10309
+ */
10310
+ this.result = {
10311
+ id: this.id,
10312
+ description: this.description,
10313
+ fullName: this.getFullName(),
10314
+ failedExpectations: [],
10315
+ deprecationWarnings: [],
10316
+ duration: null,
10317
+ properties: null
10318
+ };
10319
+ this.markedPending = this.markedExcluding;
10320
+ this.children.forEach(function(child) {
10321
+ child.reset();
10322
+ });
9367
10323
  };
9368
10324
 
9369
10325
  Suite.prototype.addChild = function(child) {
@@ -9426,6 +10382,36 @@ getJasmineRequireObj().Suite = function(j$) {
9426
10382
  this.result.failedExpectations.push(failedExpectation);
9427
10383
  };
9428
10384
 
10385
+ Suite.prototype.onMultipleDone = function() {
10386
+ var msg;
10387
+
10388
+ // Issue a deprecation. Include the context ourselves and pass
10389
+ // ignoreRunnable: true, since getting here always means that we've already
10390
+ // moved on and the current runnable isn't the one that caused the problem.
10391
+ if (this.parentSuite) {
10392
+ msg =
10393
+ "An asynchronous function called its 'done' callback more than " +
10394
+ 'once. This is a bug in the spec, beforeAll, beforeEach, afterAll, ' +
10395
+ 'or afterEach function in question. This will be treated as an error ' +
10396
+ 'in a future version. See' +
10397
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
10398
+ 'for more information.\n' +
10399
+ '(in suite: ' +
10400
+ this.getFullName() +
10401
+ ')';
10402
+ } else {
10403
+ msg =
10404
+ 'A top-level beforeAll or afterAll function called its ' +
10405
+ "'done' callback more than once. This is a bug in the beforeAll " +
10406
+ 'or afterAll function in question. This will be treated as an ' +
10407
+ 'error in a future version. See' +
10408
+ '<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> ' +
10409
+ 'for more information.';
10410
+ }
10411
+
10412
+ this.env.deprecated(msg, { ignoreRunnable: true });
10413
+ };
10414
+
9429
10415
  Suite.prototype.addExpectationResult = function() {
9430
10416
  if (isFailure(arguments)) {
9431
10417
  var data = arguments[1];
@@ -9528,7 +10514,10 @@ getJasmineRequireObj().TreeProcessor = function() {
9528
10514
  onException: function() {
9529
10515
  tree.onException.apply(tree, arguments);
9530
10516
  },
9531
- onComplete: done
10517
+ onComplete: done,
10518
+ onMultipleDone: tree.onMultipleDone
10519
+ ? tree.onMultipleDone.bind(tree)
10520
+ : null
9532
10521
  });
9533
10522
  };
9534
10523
 
@@ -9700,7 +10689,10 @@ getJasmineRequireObj().TreeProcessor = function() {
9700
10689
  userContext: node.sharedUserContext(),
9701
10690
  onException: function() {
9702
10691
  node.onException.apply(node, arguments);
9703
- }
10692
+ },
10693
+ onMultipleDone: node.onMultipleDone
10694
+ ? node.onMultipleDone.bind(node)
10695
+ : null
9704
10696
  });
9705
10697
  }
9706
10698
  };
@@ -9757,5 +10749,5 @@ getJasmineRequireObj().UserContext = function(j$) {
9757
10749
  };
9758
10750
 
9759
10751
  getJasmineRequireObj().version = function() {
9760
- return '3.8.0';
10752
+ return '3.99.0';
9761
10753
  };