jasmine-core 3.8.0 → 3.99.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  };