jasmine-core 3.5.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 413ab14189e6f5e61e2b520bdcaf065d5c5fe1ba21106bc2749b6c5016fa5fdd
4
- data.tar.gz: 04006ebef8702957e1b784275e0d6fda55c2c0315472ca8e8d4d7dbb488d6918
3
+ metadata.gz: 6f216c9ede11495c789c3403db642a8ff9fc5aee6d25ad22356d80acbc528059
4
+ data.tar.gz: 9e2cc50ac86cfd8672e138165552c36d3a31d237639b3f8b069bcd0d8321b133
5
5
  SHA512:
6
- metadata.gz: 6259f1b56267cf39e368b3d4f3933eeb0b4d34e256d41377c352c68e082e3db02a423333cac6f22cc99afb14319cfa91fbf64e1beeba3ec80c78dc1105fa76c3
7
- data.tar.gz: 6adee23b1047e3c5152194336ebfafda90835fefffd84994d36c031edbdc8a5c7caedf212a12436ee26dbcecc001f987dbb1ac15fd90df68164b961e9cc0fe45
6
+ metadata.gz: fe9be17fe38e5345998145c7ce83527a847f16a2710b163ab4231d3f6fc7ce092cb41e25375905391484f1357b8b4e00e7cbc3a2ae3cbefeaa841ca1bcfab57d
7
+ data.tar.gz: ea5cf016d142717bdf613ea3b66597ee2a7fbc28965427ee3257abc40ba1901ef23af788d681e0eaf208ec0ff7210c19c888571515ed1b8f5f06834ed8151539
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (c) 2008-2019 Pivotal Labs
2
+ Copyright (c) 2008-2020 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
@@ -31,13 +31,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
31
  */
32
32
 
33
33
  (function() {
34
+ var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
34
35
 
35
36
  /**
36
37
  * ## Require & Instantiate
37
38
  *
38
39
  * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
39
40
  */
40
- window.jasmine = jasmineRequire.core(jasmineRequire);
41
+ var jasmine = jasmineRequire.core(jasmineRequire),
42
+ global = jasmine.getGlobal();
43
+ global.jasmine = jasmine;
41
44
 
42
45
  /**
43
46
  * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
@@ -59,7 +62,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59
62
  /**
60
63
  * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
61
64
  */
62
- extend(window, jasmineInterface);
65
+ extend(global, jasmineInterface);
63
66
 
64
67
  /**
65
68
  * ## Runner Parameters
@@ -9,13 +9,16 @@
9
9
  */
10
10
 
11
11
  (function() {
12
+ var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
12
13
 
13
14
  /**
14
15
  * ## Require & Instantiate
15
16
  *
16
17
  * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
17
18
  */
18
- window.jasmine = jasmineRequire.core(jasmineRequire);
19
+ var jasmine = jasmineRequire.core(jasmineRequire),
20
+ global = jasmine.getGlobal();
21
+ global.jasmine = jasmine;
19
22
 
20
23
  /**
21
24
  * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
@@ -37,7 +40,7 @@
37
40
  /**
38
41
  * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
39
42
  */
40
- extend(window, jasmineInterface);
43
+ extend(global, jasmineInterface);
41
44
 
42
45
  /**
43
46
  * ## Runner Parameters
@@ -19,4 +19,4 @@ Player.prototype.resume = function() {
19
19
 
20
20
  Player.prototype.makeFavorite = function() {
21
21
  this.currentlyPlayingSong.persistFavoriteStatus(true);
22
- };
22
+ };
@@ -4,4 +4,4 @@ function Song() {
4
4
  Song.prototype.persistFavoriteStatus = function(value) {
5
5
  // something complicated
6
6
  throw new Error("not yet implemented");
7
- };
7
+ };
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (c) 2008-2019 Pivotal Labs
2
+ Copyright (c) 2008-2020 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
@@ -20,6 +20,8 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
20
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
+ var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
24
+
23
25
  jasmineRequire.html = function(j$) {
24
26
  j$.ResultsNode = jasmineRequire.ResultsNode();
25
27
  j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
@@ -350,9 +352,11 @@ jasmineRequire.HtmlReporter = function(j$) {
350
352
 
351
353
  find('.jasmine-failures-menu').onclick = function() {
352
354
  setMenuModeTo('jasmine-failure-list');
355
+ return false;
353
356
  };
354
357
  find('.jasmine-spec-list-menu').onclick = function() {
355
358
  setMenuModeTo('jasmine-spec-list');
359
+ return false;
356
360
  };
357
361
 
358
362
  setMenuModeTo('jasmine-failure-list');
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (c) 2008-2019 Pivotal Labs
2
+ Copyright (c) 2008-2020 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
@@ -70,16 +70,24 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
70
70
  j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
71
71
  j$.Expector = jRequire.Expector(j$);
72
72
  j$.Expectation = jRequire.Expectation(j$);
73
- j$.buildExpectationResult = jRequire.buildExpectationResult();
74
- j$.noopTimer = jRequire.noopTimer();
73
+ j$.buildExpectationResult = jRequire.buildExpectationResult(j$);
75
74
  j$.JsApiReporter = jRequire.JsApiReporter(j$);
76
- j$.matchersUtil = jRequire.matchersUtil(j$);
75
+ j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim(
76
+ j$
77
+ );
78
+ j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
79
+ j$.pp = j$.makePrettyPrinter();
80
+ j$.MatchersUtil = jRequire.MatchersUtil(j$);
81
+ j$.matchersUtil = new j$.MatchersUtil({
82
+ customTesters: [],
83
+ pp: j$.pp
84
+ });
85
+
77
86
  j$.ObjectContaining = jRequire.ObjectContaining(j$);
78
87
  j$.ArrayContaining = jRequire.ArrayContaining(j$);
79
88
  j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
80
89
  j$.MapContaining = jRequire.MapContaining(j$);
81
90
  j$.SetContaining = jRequire.SetContaining(j$);
82
- j$.pp = jRequire.pp(j$);
83
91
  j$.QueueRunner = jRequire.QueueRunner(j$);
84
92
  j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
85
93
  j$.Spec = jRequire.Spec(j$);
@@ -97,6 +105,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
97
105
  j$.DiffBuilder = jRequire.DiffBuilder(j$);
98
106
  j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
99
107
  j$.ObjectPath = jRequire.ObjectPath(j$);
108
+ j$.MismatchTree = jRequire.MismatchTree(j$);
100
109
  j$.GlobalErrors = jRequire.GlobalErrors(j$);
101
110
 
102
111
  j$.Truthy = jRequire.Truthy(j$);
@@ -135,8 +144,10 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
135
144
  'toBeUndefined',
136
145
  'toContain',
137
146
  'toEqual',
147
+ 'toHaveSize',
138
148
  'toHaveBeenCalled',
139
149
  'toHaveBeenCalledBefore',
150
+ 'toHaveBeenCalledOnceWith',
140
151
  'toHaveBeenCalledTimes',
141
152
  'toHaveBeenCalledWith',
142
153
  'toHaveClass',
@@ -268,6 +279,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
268
279
  return false;
269
280
  };
270
281
 
282
+ j$.isAsymmetricEqualityTester_ = function(obj) {
283
+ return obj ? j$.isA_('Function', obj.asymmetricMatch) : false;
284
+ };
285
+
271
286
  j$.getType_ = function(value) {
272
287
  return Object.prototype.toString.apply(value);
273
288
  };
@@ -301,6 +316,24 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
301
316
  );
302
317
  };
303
318
 
319
+ j$.isWeakMap = function(obj) {
320
+ return (
321
+ obj !== null &&
322
+ typeof obj !== 'undefined' &&
323
+ typeof jasmineGlobal.WeakMap !== 'undefined' &&
324
+ obj.constructor === jasmineGlobal.WeakMap
325
+ );
326
+ };
327
+
328
+ j$.isDataView = function(obj) {
329
+ return (
330
+ obj !== null &&
331
+ typeof obj !== 'undefined' &&
332
+ typeof jasmineGlobal.DataView !== 'undefined' &&
333
+ obj.constructor === jasmineGlobal.DataView
334
+ );
335
+ };
336
+
304
337
  j$.isPromise = function(obj) {
305
338
  return (
306
339
  typeof jasmineGlobal.Promise !== 'undefined' &&
@@ -667,7 +700,7 @@ getJasmineRequireObj().Spec = function(j$) {
667
700
  return true;
668
701
  };
669
702
  this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
670
- this.timer = attrs.timer || j$.noopTimer;
703
+ this.timer = attrs.timer || new j$.Timer();
671
704
 
672
705
  if (!this.queueableFn.fn) {
673
706
  this.pend();
@@ -684,6 +717,7 @@ getJasmineRequireObj().Spec = function(j$) {
684
717
  * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
685
718
  * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
686
719
  * @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
720
+ * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
687
721
  */
688
722
  this.result = {
689
723
  id: this.id,
@@ -693,7 +727,8 @@ getJasmineRequireObj().Spec = function(j$) {
693
727
  passedExpectations: [],
694
728
  deprecationWarnings: [],
695
729
  pendingReason: '',
696
- duration: null
730
+ duration: null,
731
+ properties: null
697
732
  };
698
733
  }
699
734
 
@@ -710,6 +745,11 @@ getJasmineRequireObj().Spec = function(j$) {
710
745
  }
711
746
  };
712
747
 
748
+ Spec.prototype.setSpecProperty = function(key, value) {
749
+ this.result.properties = this.result.properties || {};
750
+ this.result.properties[key] = value;
751
+ };
752
+
713
753
  Spec.prototype.expect = function(actual) {
714
754
  return this.expectationFactory(actual, this);
715
755
  };
@@ -732,6 +772,7 @@ getJasmineRequireObj().Spec = function(j$) {
732
772
  fn: function(done) {
733
773
  self.queueableFn.fn = null;
734
774
  self.result.status = self.status(excluded, failSpecWithNoExp);
775
+ self.result.duration = self.timer.elapsed();
735
776
  self.resultCallback(self.result, done);
736
777
  }
737
778
  };
@@ -747,7 +788,6 @@ getJasmineRequireObj().Spec = function(j$) {
747
788
  self.onException.apply(self, arguments);
748
789
  },
749
790
  onComplete: function() {
750
- self.result.duration = self.timer.elapsed();
751
791
  onComplete(
752
792
  self.result.status === 'failed' &&
753
793
  new j$.StopExecutionError('spec failed')
@@ -1188,6 +1228,7 @@ getJasmineRequireObj().Env = function(j$) {
1188
1228
  }
1189
1229
  var customMatchers =
1190
1230
  runnableResources[currentRunnable().id].customMatchers;
1231
+
1191
1232
  for (var matcherName in matchersToAdd) {
1192
1233
  customMatchers[matcherName] = matchersToAdd[matcherName];
1193
1234
  }
@@ -1201,11 +1242,24 @@ getJasmineRequireObj().Env = function(j$) {
1201
1242
  }
1202
1243
  var customAsyncMatchers =
1203
1244
  runnableResources[currentRunnable().id].customAsyncMatchers;
1245
+
1204
1246
  for (var matcherName in matchersToAdd) {
1205
1247
  customAsyncMatchers[matcherName] = matchersToAdd[matcherName];
1206
1248
  }
1207
1249
  };
1208
1250
 
1251
+ this.addCustomObjectFormatter = function(formatter) {
1252
+ if (!currentRunnable()) {
1253
+ throw new Error(
1254
+ 'Custom object formatters must be added in a before function or a spec'
1255
+ );
1256
+ }
1257
+
1258
+ runnableResources[currentRunnable().id].customObjectFormatters.push(
1259
+ formatter
1260
+ );
1261
+ };
1262
+
1209
1263
  j$.Expectation.addCoreMatchers(j$.matchers);
1210
1264
  j$.Expectation.addAsyncCoreMatchers(j$.asyncMatchers);
1211
1265
 
@@ -1219,10 +1273,28 @@ getJasmineRequireObj().Env = function(j$) {
1219
1273
  return 'suite' + nextSuiteId++;
1220
1274
  };
1221
1275
 
1276
+ var makePrettyPrinter = function() {
1277
+ var customObjectFormatters =
1278
+ runnableResources[currentRunnable().id].customObjectFormatters;
1279
+ return j$.makePrettyPrinter(customObjectFormatters);
1280
+ };
1281
+
1282
+ var makeMatchersUtil = function() {
1283
+ var customEqualityTesters =
1284
+ runnableResources[currentRunnable().id].customEqualityTesters;
1285
+ return new j$.MatchersUtil({
1286
+ customTesters: customEqualityTesters,
1287
+ pp: makePrettyPrinter()
1288
+ });
1289
+ };
1290
+
1222
1291
  var expectationFactory = function(actual, spec) {
1292
+ var customEqualityTesters =
1293
+ runnableResources[spec.id].customEqualityTesters;
1294
+
1223
1295
  return j$.Expectation.factory({
1224
- util: j$.matchersUtil,
1225
- customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
1296
+ matchersUtil: makeMatchersUtil(),
1297
+ customEqualityTesters: customEqualityTesters,
1226
1298
  customMatchers: runnableResources[spec.id].customMatchers,
1227
1299
  actual: actual,
1228
1300
  addExpectationResult: addExpectationResult
@@ -1233,9 +1305,35 @@ getJasmineRequireObj().Env = function(j$) {
1233
1305
  }
1234
1306
  };
1235
1307
 
1236
- var asyncExpectationFactory = function(actual, spec) {
1308
+ function recordLateExpectation(runable, runableType, result) {
1309
+ var delayedExpectationResult = {};
1310
+ Object.keys(result).forEach(function(k) {
1311
+ delayedExpectationResult[k] = result[k];
1312
+ });
1313
+ delayedExpectationResult.passed = false;
1314
+ delayedExpectationResult.globalErrorType = 'lateExpectation';
1315
+ delayedExpectationResult.message =
1316
+ runableType +
1317
+ ' "' +
1318
+ runable.getFullName() +
1319
+ '" ran a "' +
1320
+ result.matcherName +
1321
+ '" expectation after it finished.\n';
1322
+
1323
+ if (result.message) {
1324
+ delayedExpectationResult.message +=
1325
+ 'Message: "' + result.message + '"\n';
1326
+ }
1327
+
1328
+ delayedExpectationResult.message +=
1329
+ 'Did you forget to return or await the result of expectAsync?';
1330
+
1331
+ topSuite.result.failedExpectations.push(delayedExpectationResult);
1332
+ }
1333
+
1334
+ var asyncExpectationFactory = function(actual, spec, runableType) {
1237
1335
  return j$.Expectation.asyncFactory({
1238
- util: j$.matchersUtil,
1336
+ matchersUtil: makeMatchersUtil(),
1239
1337
  customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
1240
1338
  customAsyncMatchers: runnableResources[spec.id].customAsyncMatchers,
1241
1339
  actual: actual,
@@ -1243,9 +1341,19 @@ getJasmineRequireObj().Env = function(j$) {
1243
1341
  });
1244
1342
 
1245
1343
  function addExpectationResult(passed, result) {
1344
+ if (currentRunnable() !== spec) {
1345
+ recordLateExpectation(spec, runableType, result);
1346
+ }
1246
1347
  return spec.addExpectationResult(passed, result);
1247
1348
  }
1248
1349
  };
1350
+ var suiteAsyncExpectationFactory = function(actual, suite) {
1351
+ return asyncExpectationFactory(actual, suite, 'Suite');
1352
+ };
1353
+
1354
+ var specAsyncExpectationFactory = function(actual, suite) {
1355
+ return asyncExpectationFactory(actual, suite, 'Spec');
1356
+ };
1249
1357
 
1250
1358
  var defaultResourcesForRunnable = function(id, parentRunnableId) {
1251
1359
  var resources = {
@@ -1254,7 +1362,8 @@ getJasmineRequireObj().Env = function(j$) {
1254
1362
  customMatchers: {},
1255
1363
  customAsyncMatchers: {},
1256
1364
  customSpyStrategies: {},
1257
- defaultStrategyFn: undefined
1365
+ defaultStrategyFn: undefined,
1366
+ customObjectFormatters: []
1258
1367
  };
1259
1368
 
1260
1369
  if (runnableResources[parentRunnableId]) {
@@ -1463,7 +1572,7 @@ getJasmineRequireObj().Env = function(j$) {
1463
1572
  id: getNextSuiteId(),
1464
1573
  description: 'Jasmine__TopLevel__Suite',
1465
1574
  expectationFactory: expectationFactory,
1466
- asyncExpectationFactory: asyncExpectationFactory,
1575
+ asyncExpectationFactory: suiteAsyncExpectationFactory,
1467
1576
  expectationResultFactory: expectationResultFactory
1468
1577
  });
1469
1578
  defaultResourcesForRunnable(topSuite.id);
@@ -1795,8 +1904,9 @@ getJasmineRequireObj().Env = function(j$) {
1795
1904
  id: getNextSuiteId(),
1796
1905
  description: description,
1797
1906
  parentSuite: currentDeclarationSuite,
1907
+ timer: new j$.Timer(),
1798
1908
  expectationFactory: expectationFactory,
1799
- asyncExpectationFactory: asyncExpectationFactory,
1909
+ asyncExpectationFactory: suiteAsyncExpectationFactory,
1800
1910
  expectationResultFactory: expectationResultFactory,
1801
1911
  throwOnExpectationFailure: config.oneFailurePerSpec
1802
1912
  });
@@ -1890,7 +2000,7 @@ getJasmineRequireObj().Env = function(j$) {
1890
2000
  id: getNextSpecId(),
1891
2001
  beforeAndAfterFns: beforeAndAfterFns(suite),
1892
2002
  expectationFactory: expectationFactory,
1893
- asyncExpectationFactory: asyncExpectationFactory,
2003
+ asyncExpectationFactory: specAsyncExpectationFactory,
1894
2004
  resultCallback: specResultCallback,
1895
2005
  getSpecName: function(spec) {
1896
2006
  return getSpecName(spec, suite);
@@ -1966,6 +2076,40 @@ getJasmineRequireObj().Env = function(j$) {
1966
2076
  return spec;
1967
2077
  };
1968
2078
 
2079
+ /**
2080
+ * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult}
2081
+ * @name Env#setSpecProperty
2082
+ * @since 3.6.0
2083
+ * @function
2084
+ * @param {String} key The name of the property
2085
+ * @param {*} value The value of the property
2086
+ */
2087
+ this.setSpecProperty = function(key, value) {
2088
+ if (!currentRunnable() || currentRunnable() == currentSuite()) {
2089
+ throw new Error(
2090
+ "'setSpecProperty' was used when there was no current spec"
2091
+ );
2092
+ }
2093
+ currentRunnable().setSpecProperty(key, value);
2094
+ };
2095
+
2096
+ /**
2097
+ * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult}
2098
+ * @name Env#setSuiteProperty
2099
+ * @since 3.6.0
2100
+ * @function
2101
+ * @param {String} key The name of the property
2102
+ * @param {*} value The value of the property
2103
+ */
2104
+ this.setSuiteProperty = function(key, value) {
2105
+ if (!currentSuite()) {
2106
+ throw new Error(
2107
+ "'setSuiteProperty' was used when there was no current suite"
2108
+ );
2109
+ }
2110
+ currentSuite().setSuiteProperty(key, value);
2111
+ };
2112
+
1969
2113
  this.expect = function(actual) {
1970
2114
  if (!currentRunnable()) {
1971
2115
  throw new Error(
@@ -2047,7 +2191,7 @@ getJasmineRequireObj().Env = function(j$) {
2047
2191
  message += error;
2048
2192
  } else {
2049
2193
  // pretty print all kind of objects. This includes arrays.
2050
- message += j$.pp(error);
2194
+ message += makePrettyPrinter()(error);
2051
2195
  }
2052
2196
  }
2053
2197
 
@@ -2064,6 +2208,12 @@ getJasmineRequireObj().Env = function(j$) {
2064
2208
  throw new Error(message);
2065
2209
  }
2066
2210
  };
2211
+
2212
+ this.cleanup_ = function() {
2213
+ if (globalErrors) {
2214
+ globalErrors.uninstall();
2215
+ }
2216
+ };
2067
2217
  }
2068
2218
 
2069
2219
  return Env;
@@ -2077,7 +2227,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
2077
2227
  * @hideconstructor
2078
2228
  */
2079
2229
  function JsApiReporter(options) {
2080
- var timer = options.timer || j$.noopTimer,
2230
+ var timer = options.timer || new j$.Timer(),
2081
2231
  status = 'loaded';
2082
2232
 
2083
2233
  this.started = false;
@@ -2269,7 +2419,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
2269
2419
  this.sample = sample;
2270
2420
  }
2271
2421
 
2272
- ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
2422
+ ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
2273
2423
  if (!j$.isArray_(this.sample)) {
2274
2424
  throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
2275
2425
  }
@@ -2283,7 +2433,7 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
2283
2433
 
2284
2434
  for (var i = 0; i < this.sample.length; i++) {
2285
2435
  var item = this.sample[i];
2286
- if (!j$.matchersUtil.contains(other, item, customTesters)) {
2436
+ if (!matchersUtil.contains(other, item)) {
2287
2437
  return false;
2288
2438
  }
2289
2439
  }
@@ -2291,8 +2441,8 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
2291
2441
  return true;
2292
2442
  };
2293
2443
 
2294
- ArrayContaining.prototype.jasmineToString = function () {
2295
- return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
2444
+ ArrayContaining.prototype.jasmineToString = function (pp) {
2445
+ return '<jasmine.arrayContaining(' + pp(this.sample) +')>';
2296
2446
  };
2297
2447
 
2298
2448
  return ArrayContaining;
@@ -2304,7 +2454,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
2304
2454
  this.sample = sample;
2305
2455
  }
2306
2456
 
2307
- ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
2457
+ ArrayWithExactContents.prototype.asymmetricMatch = function(other, matchersUtil) {
2308
2458
  if (!j$.isArray_(this.sample)) {
2309
2459
  throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
2310
2460
  }
@@ -2315,7 +2465,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
2315
2465
 
2316
2466
  for (var i = 0; i < this.sample.length; i++) {
2317
2467
  var item = this.sample[i];
2318
- if (!j$.matchersUtil.contains(other, item, customTesters)) {
2468
+ if (!matchersUtil.contains(other, item)) {
2319
2469
  return false;
2320
2470
  }
2321
2471
  }
@@ -2323,8 +2473,8 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
2323
2473
  return true;
2324
2474
  };
2325
2475
 
2326
- ArrayWithExactContents.prototype.jasmineToString = function() {
2327
- return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
2476
+ ArrayWithExactContents.prototype.jasmineToString = function(pp) {
2477
+ return '<jasmine.arrayWithExactContents(' + pp(this.sample) + ')>';
2328
2478
  };
2329
2479
 
2330
2480
  return ArrayWithExactContents;
@@ -2380,7 +2530,7 @@ getJasmineRequireObj().MapContaining = function(j$) {
2380
2530
  this.sample = sample;
2381
2531
  }
2382
2532
 
2383
- MapContaining.prototype.asymmetricMatch = function(other, customTesters) {
2533
+ MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
2384
2534
  if (!j$.isMap(other)) return false;
2385
2535
 
2386
2536
  var hasAllMatches = true;
@@ -2390,8 +2540,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
2390
2540
  var hasMatch = false;
2391
2541
  j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
2392
2542
  if (
2393
- j$.matchersUtil.equals(oKey, key, customTesters)
2394
- && j$.matchersUtil.equals(oValue, value, customTesters)
2543
+ matchersUtil.equals(oKey, key)
2544
+ && matchersUtil.equals(oValue, value)
2395
2545
  ) {
2396
2546
  hasMatch = true;
2397
2547
  oBreakLoop();
@@ -2406,8 +2556,8 @@ getJasmineRequireObj().MapContaining = function(j$) {
2406
2556
  return hasAllMatches;
2407
2557
  };
2408
2558
 
2409
- MapContaining.prototype.jasmineToString = function() {
2410
- return '<jasmine.mapContaining(' + j$.pp(this.sample) + ')>';
2559
+ MapContaining.prototype.jasmineToString = function(pp) {
2560
+ return '<jasmine.mapContaining(' + pp(this.sample) + ')>';
2411
2561
  };
2412
2562
 
2413
2563
  return MapContaining;
@@ -2459,7 +2609,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
2459
2609
  }
2460
2610
 
2461
2611
  function hasProperty(obj, property) {
2462
- if (!obj) {
2612
+ if (!obj || typeof(obj) !== 'object') {
2463
2613
  return false;
2464
2614
  }
2465
2615
 
@@ -2470,12 +2620,13 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
2470
2620
  return hasProperty(getPrototype(obj), property);
2471
2621
  }
2472
2622
 
2473
- ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
2623
+ ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
2474
2624
  if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
2625
+ if (typeof(other) !== 'object') { return false; }
2475
2626
 
2476
2627
  for (var property in this.sample) {
2477
2628
  if (!hasProperty(other, property) ||
2478
- !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
2629
+ !matchersUtil.equals(this.sample[property], other[property])) {
2479
2630
  return false;
2480
2631
  }
2481
2632
  }
@@ -2483,8 +2634,29 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
2483
2634
  return true;
2484
2635
  };
2485
2636
 
2486
- ObjectContaining.prototype.jasmineToString = function() {
2487
- return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
2637
+ ObjectContaining.prototype.valuesForDiff_ = function(other, pp) {
2638
+ if (!j$.isObject_(other)) {
2639
+ return {
2640
+ self: this.jasmineToString(pp),
2641
+ other: other
2642
+ };
2643
+ }
2644
+
2645
+ var filteredOther = {};
2646
+ Object.keys(this.sample).forEach(function (k) {
2647
+ // eq short-circuits comparison of objects that have different key sets,
2648
+ // so include all keys even if undefined.
2649
+ filteredOther[k] = other[k];
2650
+ });
2651
+
2652
+ return {
2653
+ self: this.sample,
2654
+ other: filteredOther
2655
+ };
2656
+ };
2657
+
2658
+ ObjectContaining.prototype.jasmineToString = function(pp) {
2659
+ return '<jasmine.objectContaining(' + pp(this.sample) + ')>';
2488
2660
  };
2489
2661
 
2490
2662
  return ObjectContaining;
@@ -2499,17 +2671,17 @@ getJasmineRequireObj().SetContaining = function(j$) {
2499
2671
  this.sample = sample;
2500
2672
  }
2501
2673
 
2502
- SetContaining.prototype.asymmetricMatch = function(other, customTesters) {
2674
+ SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
2503
2675
  if (!j$.isSet(other)) return false;
2504
2676
 
2505
2677
  var hasAllMatches = true;
2506
2678
  j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
2507
2679
  // for each item in `sample` there should be at least one matching item in `other`
2508
- // (not using `j$.matchersUtil.contains` because it compares set members by reference,
2680
+ // (not using `matchersUtil.contains` because it compares set members by reference,
2509
2681
  // not by deep value equality)
2510
2682
  var hasMatch = false;
2511
2683
  j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
2512
- if (j$.matchersUtil.equals(oItem, item, customTesters)) {
2684
+ if (matchersUtil.equals(oItem, item)) {
2513
2685
  hasMatch = true;
2514
2686
  oBreakLoop();
2515
2687
  }
@@ -2523,8 +2695,8 @@ getJasmineRequireObj().SetContaining = function(j$) {
2523
2695
  return hasAllMatches;
2524
2696
  };
2525
2697
 
2526
- SetContaining.prototype.jasmineToString = function() {
2527
- return '<jasmine.setContaining(' + j$.pp(this.sample) + ')>';
2698
+ SetContaining.prototype.jasmineToString = function(pp) {
2699
+ return '<jasmine.setContaining(' + pp(this.sample) + ')>';
2528
2700
  };
2529
2701
 
2530
2702
  return SetContaining;
@@ -2566,6 +2738,112 @@ getJasmineRequireObj().Truthy = function(j$) {
2566
2738
  return Truthy;
2567
2739
  };
2568
2740
 
2741
+ getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
2742
+ /*
2743
+ Older versions of Jasmine passed an array of custom equality testers as the
2744
+ second argument to each asymmetric equality tester's `asymmetricMatch`
2745
+ method. Newer versions will pass a `MatchersUtil` instance. The
2746
+ asymmetricEqualityTesterArgCompatShim allows for a graceful migration from
2747
+ the old interface to the new by "being" both an array of custom equality
2748
+ testers and a `MatchersUtil` at the same time.
2749
+
2750
+ This code should be removed in the next major release.
2751
+ */
2752
+
2753
+ var likelyArrayProps = [
2754
+ 'concat',
2755
+ 'constructor',
2756
+ 'copyWithin',
2757
+ 'entries',
2758
+ 'every',
2759
+ 'fill',
2760
+ 'filter',
2761
+ 'find',
2762
+ 'findIndex',
2763
+ 'flat',
2764
+ 'flatMap',
2765
+ 'forEach',
2766
+ 'includes',
2767
+ 'indexOf',
2768
+ 'join',
2769
+ 'keys',
2770
+ 'lastIndexOf',
2771
+ 'length',
2772
+ 'map',
2773
+ 'pop',
2774
+ 'push',
2775
+ 'reduce',
2776
+ 'reduceRight',
2777
+ 'reverse',
2778
+ 'shift',
2779
+ 'slice',
2780
+ 'some',
2781
+ 'sort',
2782
+ 'splice',
2783
+ 'toLocaleString',
2784
+ 'toSource',
2785
+ 'toString',
2786
+ 'unshift',
2787
+ 'values'
2788
+ ];
2789
+
2790
+ function asymmetricEqualityTesterArgCompatShim(
2791
+ matchersUtil,
2792
+ customEqualityTesters
2793
+ ) {
2794
+ var self = Object.create(matchersUtil),
2795
+ props,
2796
+ i,
2797
+ k;
2798
+
2799
+ copy(self, customEqualityTesters, 'length');
2800
+
2801
+ for (i = 0; i < customEqualityTesters.length; i++) {
2802
+ copy(self, customEqualityTesters, i);
2803
+ }
2804
+
2805
+ var props = arrayProps();
2806
+
2807
+ for (i = 0; i < props.length; i++) {
2808
+ k = props[i];
2809
+ if (k !== 'length') {
2810
+ copy(self, Array.prototype, k);
2811
+ }
2812
+ }
2813
+
2814
+ return self;
2815
+ }
2816
+
2817
+ function copy(dest, src, propName) {
2818
+ Object.defineProperty(dest, propName, {
2819
+ get: function() {
2820
+ return src[propName];
2821
+ }
2822
+ });
2823
+ }
2824
+
2825
+ function arrayProps() {
2826
+ var props, a, k;
2827
+
2828
+ if (!Object.getOwnPropertyDescriptors) {
2829
+ return likelyArrayProps.filter(function(k) {
2830
+ return Array.prototype.hasOwnProperty(k);
2831
+ });
2832
+ }
2833
+
2834
+ props = Object.getOwnPropertyDescriptors(Array.prototype); // eslint-disable-line compat/compat
2835
+ a = [];
2836
+
2837
+ for (k in props) {
2838
+ a.push(k);
2839
+ }
2840
+
2841
+ return a;
2842
+ }
2843
+
2844
+ return asymmetricEqualityTesterArgCompatShim;
2845
+ };
2846
+
2569
2847
  getJasmineRequireObj().CallTracker = function(j$) {
2570
2848
  /**
2571
2849
  * @namespace Spy#calls
@@ -3412,7 +3690,7 @@ getJasmineRequireObj().Expectation = function(j$) {
3412
3690
  return result;
3413
3691
  }
3414
3692
 
3415
- function negatedFailureMessage(result, matcherName, args, util) {
3693
+ function negatedFailureMessage(result, matcherName, args, matchersUtil) {
3416
3694
  if (result.message) {
3417
3695
  if (j$.isFunction_(result.message)) {
3418
3696
  return result.message();
@@ -3424,7 +3702,7 @@ getJasmineRequireObj().Expectation = function(j$) {
3424
3702
  args = args.slice();
3425
3703
  args.unshift(true);
3426
3704
  args.unshift(matcherName);
3427
- return util.buildFailureMessage.apply(null, args);
3705
+ return matchersUtil.buildFailureMessage.apply(matchersUtil, args);
3428
3706
  }
3429
3707
 
3430
3708
  function negate(result) {
@@ -3459,9 +3737,19 @@ getJasmineRequireObj().Expectation = function(j$) {
3459
3737
  }
3460
3738
 
3461
3739
  ContextAddingFilter.prototype.modifyFailureMessage = function(msg) {
3462
- return this.message + ': ' + msg;
3740
+ var nl = msg.indexOf('\n');
3741
+
3742
+ if (nl === -1) {
3743
+ return this.message + ': ' + msg;
3744
+ } else {
3745
+ return this.message + ':\n' + indent(msg);
3746
+ }
3463
3747
  };
3464
3748
 
3749
+ function indent(s) {
3750
+ return s.replace(/^/gm, ' ');
3751
+ }
3752
+
3465
3753
  return {
3466
3754
  factory: function(options) {
3467
3755
  return new Expectation(options || {});
@@ -3496,7 +3784,7 @@ getJasmineRequireObj().ExpectationFilterChain = function() {
3496
3784
  result,
3497
3785
  matcherName,
3498
3786
  args,
3499
- util
3787
+ matchersUtil
3500
3788
  ) {
3501
3789
  return this.callFirst_('buildFailureMessage', arguments).result;
3502
3790
  };
@@ -3531,7 +3819,7 @@ getJasmineRequireObj().ExpectationFilterChain = function() {
3531
3819
  };
3532
3820
 
3533
3821
  //TODO: expectation result may make more sense as a presentation of an expectation.
3534
- getJasmineRequireObj().buildExpectationResult = function() {
3822
+ getJasmineRequireObj().buildExpectationResult = function(j$) {
3535
3823
  function buildExpectationResult(options) {
3536
3824
  var messageFormatter = options.messageFormatter || function() {},
3537
3825
  stackFormatter = options.stackFormatter || function() {};
@@ -3555,6 +3843,22 @@ getJasmineRequireObj().buildExpectationResult = function() {
3555
3843
  if (!result.passed) {
3556
3844
  result.expected = options.expected;
3557
3845
  result.actual = options.actual;
3846
+
3847
+ if (options.error && !j$.isString_(options.error)) {
3848
+ if ('code' in options.error) {
3849
+ result.code = options.error.code;
3850
+ }
3851
+
3852
+ if (
3853
+ options.error.code === 'ERR_ASSERTION' &&
3854
+ options.expected === '' &&
3855
+ options.actual === ''
3856
+ ) {
3857
+ result.expected = options.error.expected;
3858
+ result.actual = options.error.actual;
3859
+ result.matcherName = 'assert ' + options.error.operator;
3860
+ }
3861
+ }
3558
3862
  }
3559
3863
 
3560
3864
  return result;
@@ -3598,7 +3902,9 @@ getJasmineRequireObj().buildExpectationResult = function() {
3598
3902
 
3599
3903
  getJasmineRequireObj().Expector = function(j$) {
3600
3904
  function Expector(options) {
3601
- this.util = options.util || { buildFailureMessage: function() {} };
3905
+ this.matchersUtil = options.matchersUtil || {
3906
+ buildFailureMessage: function() {}
3907
+ };
3602
3908
  this.customEqualityTesters = options.customEqualityTesters || [];
3603
3909
  this.actual = options.actual;
3604
3910
  this.addExpectationResult = options.addExpectationResult || function() {};
@@ -3616,7 +3922,7 @@ getJasmineRequireObj().Expector = function(j$) {
3616
3922
 
3617
3923
  this.args.unshift(this.actual);
3618
3924
 
3619
- var matcher = matcherFactory(this.util, this.customEqualityTesters);
3925
+ var matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
3620
3926
  var comparisonFunc = this.filters.selectComparisonFunc(matcher);
3621
3927
  return comparisonFunc || matcher.compare;
3622
3928
  };
@@ -3632,7 +3938,7 @@ getJasmineRequireObj().Expector = function(j$) {
3632
3938
  result,
3633
3939
  this.matcherName,
3634
3940
  this.args,
3635
- this.util,
3941
+ this.matchersUtil,
3636
3942
  defaultMessage
3637
3943
  );
3638
3944
  return this.filters.modifyFailureMessage(msg || defaultMessage());
@@ -3642,7 +3948,10 @@ getJasmineRequireObj().Expector = function(j$) {
3642
3948
  var args = self.args.slice();
3643
3949
  args.unshift(false);
3644
3950
  args.unshift(self.matcherName);
3645
- return self.util.buildFailureMessage.apply(null, args);
3951
+ return self.matchersUtil.buildFailureMessage.apply(
3952
+ self.matchersUtil,
3953
+ args
3954
+ );
3646
3955
  } else if (j$.isFunction_(result.message)) {
3647
3956
  return result.message();
3648
3957
  } else {
@@ -3764,8 +4073,31 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
3764
4073
  var originalHandler = global.onerror;
3765
4074
  global.onerror = onerror;
3766
4075
 
4076
+ var browserRejectionHandler = function browserRejectionHandler(event) {
4077
+ if (j$.isError_(event.reason)) {
4078
+ event.reason.jasmineMessage =
4079
+ 'Unhandled promise rejection: ' + event.reason;
4080
+ onerror(event.reason);
4081
+ } else {
4082
+ onerror('Unhandled promise rejection: ' + event.reason);
4083
+ }
4084
+ };
4085
+
4086
+ if (global.addEventListener) {
4087
+ global.addEventListener(
4088
+ 'unhandledrejection',
4089
+ browserRejectionHandler
4090
+ );
4091
+ }
4092
+
3767
4093
  this.uninstall = function uninstall() {
3768
4094
  global.onerror = originalHandler;
4095
+ if (global.removeEventListener) {
4096
+ global.removeEventListener(
4097
+ 'unhandledrejection',
4098
+ browserRejectionHandler
4099
+ );
4100
+ }
3769
4101
  };
3770
4102
  }
3771
4103
  };
@@ -3782,6 +4114,33 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
3782
4114
  return GlobalErrors;
3783
4115
  };
3784
4116
 
4117
+ /* eslint-disable compat/compat */
4118
+ getJasmineRequireObj().toBePending = function(j$) {
4119
+ /**
4120
+ * Expect a promise to be pending, ie. the promise is neither resolved nor rejected.
4121
+ * @function
4122
+ * @async
4123
+ * @name async-matchers#toBePending
4124
+ * @since 3.6
4125
+ * @example
4126
+ * await expectAsync(aPromise).toBePending();
4127
+ */
4128
+ return function toBePending() {
4129
+ return {
4130
+ compare: function(actual) {
4131
+ if (!j$.isPromiseLike(actual)) {
4132
+ throw new Error('Expected toBePending to be called on a promise.');
4133
+ }
4134
+ var want = {};
4135
+ return Promise.race([actual, Promise.resolve(want)]).then(
4136
+ function(got) { return {pass: want === got}; },
4137
+ function() { return {pass: false}; }
4138
+ );
4139
+ }
4140
+ };
4141
+ };
4142
+ };
4143
+
3785
4144
  getJasmineRequireObj().toBeRejected = function(j$) {
3786
4145
  /**
3787
4146
  * Expect a promise to be rejected.
@@ -3794,7 +4153,7 @@ getJasmineRequireObj().toBeRejected = function(j$) {
3794
4153
  * @example
3795
4154
  * return expectAsync(aPromise).toBeRejected();
3796
4155
  */
3797
- return function toBeRejected(util) {
4156
+ return function toBeRejected() {
3798
4157
  return {
3799
4158
  compare: function(actual) {
3800
4159
  if (!j$.isPromiseLike(actual)) {
@@ -3822,7 +4181,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
3822
4181
  * @example
3823
4182
  * return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
3824
4183
  */
3825
- return function toBeRejectedWith(util, customEqualityTesters) {
4184
+ return function toBeRejectedWith(matchersUtil) {
3826
4185
  return {
3827
4186
  compare: function(actualPromise, expectedValue) {
3828
4187
  if (!j$.isPromiseLike(actualPromise)) {
@@ -3832,7 +4191,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
3832
4191
  function prefix(passed) {
3833
4192
  return 'Expected a promise ' +
3834
4193
  (passed ? 'not ' : '') +
3835
- 'to be rejected with ' + j$.pp(expectedValue);
4194
+ 'to be rejected with ' + matchersUtil.pp(expectedValue);
3836
4195
  }
3837
4196
 
3838
4197
  return actualPromise.then(
@@ -3843,7 +4202,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
3843
4202
  };
3844
4203
  },
3845
4204
  function(actualValue) {
3846
- if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
4205
+ if (matchersUtil.equals(actualValue, expectedValue)) {
3847
4206
  return {
3848
4207
  pass: true,
3849
4208
  message: prefix(true) + '.'
@@ -3851,7 +4210,7 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
3851
4210
  } else {
3852
4211
  return {
3853
4212
  pass: false,
3854
- message: prefix(false) + ' but it was rejected with ' + j$.pp(actualValue) + '.'
4213
+ message: prefix(false) + ' but it was rejected with ' + matchersUtil.pp(actualValue) + '.'
3855
4214
  };
3856
4215
  }
3857
4216
  }
@@ -3877,14 +4236,14 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
3877
4236
  * await expectAsync(aPromise).toBeRejectedWithError('Error message');
3878
4237
  * return expectAsync(aPromise).toBeRejectedWithError(/Error message/);
3879
4238
  */
3880
- return function toBeRejectedWithError() {
4239
+ return function toBeRejectedWithError(matchersUtil) {
3881
4240
  return {
3882
4241
  compare: function(actualPromise, arg1, arg2) {
3883
4242
  if (!j$.isPromiseLike(actualPromise)) {
3884
4243
  throw new Error('Expected toBeRejectedWithError to be called on a promise.');
3885
4244
  }
3886
4245
 
3887
- var expected = getExpectedFromArgs(arg1, arg2);
4246
+ var expected = getExpectedFromArgs(arg1, arg2, matchersUtil);
3888
4247
 
3889
4248
  return actualPromise.then(
3890
4249
  function() {
@@ -3893,15 +4252,15 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
3893
4252
  message: 'Expected a promise to be rejected but it was resolved.'
3894
4253
  };
3895
4254
  },
3896
- function(actualValue) { return matchError(actualValue, expected); }
4255
+ function(actualValue) { return matchError(actualValue, expected, matchersUtil); }
3897
4256
  );
3898
4257
  }
3899
4258
  };
3900
4259
  };
3901
4260
 
3902
- function matchError(actual, expected) {
4261
+ function matchError(actual, expected, matchersUtil) {
3903
4262
  if (!j$.isError_(actual)) {
3904
- return fail(expected, 'rejected with ' + j$.pp(actual));
4263
+ return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
3905
4264
  }
3906
4265
 
3907
4266
  if (!(actual instanceof expected.error)) {
@@ -3918,7 +4277,7 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
3918
4277
  return pass(expected);
3919
4278
  }
3920
4279
 
3921
- return fail(expected, 'rejected with ' + j$.pp(actual));
4280
+ return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
3922
4281
  }
3923
4282
 
3924
4283
  function pass(expected) {
@@ -3936,7 +4295,7 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
3936
4295
  }
3937
4296
 
3938
4297
 
3939
- function getExpectedFromArgs(arg1, arg2) {
4298
+ function getExpectedFromArgs(arg1, arg2, matchersUtil) {
3940
4299
  var error, message;
3941
4300
 
3942
4301
  if (isErrorConstructor(arg1)) {
@@ -3950,7 +4309,7 @@ getJasmineRequireObj().toBeRejectedWithError = function(j$) {
3950
4309
  return {
3951
4310
  error: error,
3952
4311
  message: message,
3953
- printValue: j$.fnNameFor(error) + (typeof message === 'undefined' ? '' : ': ' + j$.pp(message))
4312
+ printValue: j$.fnNameFor(error) + (typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message))
3954
4313
  };
3955
4314
  }
3956
4315
 
@@ -3971,7 +4330,7 @@ getJasmineRequireObj().toBeResolved = function(j$) {
3971
4330
  * @example
3972
4331
  * return expectAsync(aPromise).toBeResolved();
3973
4332
  */
3974
- return function toBeResolved(util) {
4333
+ return function toBeResolved() {
3975
4334
  return {
3976
4335
  compare: function(actual) {
3977
4336
  if (!j$.isPromiseLike(actual)) {
@@ -4000,7 +4359,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
4000
4359
  * @example
4001
4360
  * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
4002
4361
  */
4003
- return function toBeResolvedTo(util, customEqualityTesters) {
4362
+ return function toBeResolvedTo(matchersUtil) {
4004
4363
  return {
4005
4364
  compare: function(actualPromise, expectedValue) {
4006
4365
  if (!j$.isPromiseLike(actualPromise)) {
@@ -4010,12 +4369,12 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
4010
4369
  function prefix(passed) {
4011
4370
  return 'Expected a promise ' +
4012
4371
  (passed ? 'not ' : '') +
4013
- 'to be resolved to ' + j$.pp(expectedValue);
4372
+ 'to be resolved to ' + matchersUtil.pp(expectedValue);
4014
4373
  }
4015
4374
 
4016
4375
  return actualPromise.then(
4017
4376
  function(actualValue) {
4018
- if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
4377
+ if (matchersUtil.equals(actualValue, expectedValue)) {
4019
4378
  return {
4020
4379
  pass: true,
4021
4380
  message: prefix(true) + '.'
@@ -4023,7 +4382,7 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
4023
4382
  } else {
4024
4383
  return {
4025
4384
  pass: false,
4026
- message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
4385
+ message: prefix(false) + ' but it was resolved to ' + matchersUtil.pp(actualValue) + '.'
4027
4386
  };
4028
4387
  }
4029
4388
  },
@@ -4039,19 +4398,55 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
4039
4398
  };
4040
4399
  };
4041
4400
 
4042
- getJasmineRequireObj().DiffBuilder = function(j$) {
4043
- return function DiffBuilder() {
4044
- var path = new j$.ObjectPath(),
4045
- mismatches = [];
4401
+ getJasmineRequireObj().DiffBuilder = function (j$) {
4402
+ return function DiffBuilder(config) {
4403
+ var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(),
4404
+ mismatches = new j$.MismatchTree(),
4405
+ path = new j$.ObjectPath(),
4406
+ actualRoot = undefined,
4407
+ expectedRoot = undefined;
4046
4408
 
4047
4409
  return {
4048
- record: function (actual, expected, formatter) {
4049
- formatter = formatter || defaultFormatter;
4050
- mismatches.push(formatter(actual, expected, path));
4410
+ setRoots: function (actual, expected) {
4411
+ actualRoot = actual;
4412
+ expectedRoot = expected;
4413
+ },
4414
+
4415
+ recordMismatch: function (formatter) {
4416
+ mismatches.add(path, formatter);
4051
4417
  },
4052
4418
 
4053
4419
  getMessage: function () {
4054
- return mismatches.join('\n');
4420
+ var messages = [];
4421
+
4422
+ mismatches.traverse(function (path, isLeaf, formatter) {
4423
+ var actualCustom, expectedCustom, useCustom,
4424
+ derefResult = dereferencePath(path, actualRoot, expectedRoot, prettyPrinter),
4425
+ actual = derefResult.actual,
4426
+ expected = derefResult.expected;
4427
+
4428
+ if (formatter) {
4429
+ messages.push(formatter(actual, expected, path, prettyPrinter));
4430
+ return true;
4431
+ }
4432
+
4433
+ actualCustom = prettyPrinter.customFormat_(actual);
4434
+ expectedCustom = prettyPrinter.customFormat_(expected);
4435
+ useCustom = !(j$.util.isUndefined(actualCustom) && j$.util.isUndefined(expectedCustom));
4436
+
4437
+ if (useCustom) {
4438
+ messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
4439
+ return false; // don't recurse further
4440
+ }
4441
+
4442
+ if (isLeaf) {
4443
+ messages.push(defaultFormatter(actual, expected, path, prettyPrinter));
4444
+ }
4445
+
4446
+ return true;
4447
+ });
4448
+
4449
+ return messages.join('\n');
4055
4450
  },
4056
4451
 
4057
4452
  withPath: function (pathComponent, block) {
@@ -4062,113 +4457,195 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
4062
4457
  }
4063
4458
  };
4064
4459
 
4065
- function defaultFormatter (actual, expected, path) {
4460
+ function defaultFormatter(actual, expected, path, prettyPrinter) {
4461
+ return wrapPrettyPrinted(prettyPrinter(actual), prettyPrinter(expected), path);
4462
+ }
4463
+
4464
+ function wrapPrettyPrinted(actual, expected, path) {
4066
4465
  return 'Expected ' +
4067
4466
  path + (path.depth() ? ' = ' : '') +
4068
- j$.pp(actual) +
4467
+ actual +
4069
4468
  ' to equal ' +
4070
- j$.pp(expected) +
4469
+ expected +
4071
4470
  '.';
4072
4471
  }
4073
4472
  };
4074
- };
4075
4473
 
4076
- getJasmineRequireObj().matchersUtil = function(j$) {
4077
- // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
4474
+ function dereferencePath(objectPath, actual, expected, pp) {
4475
+ function handleAsymmetricExpected() {
4476
+ if (j$.isAsymmetricEqualityTester_(expected) && j$.isFunction_(expected.valuesForDiff_)) {
4477
+ var asymmetricResult = expected.valuesForDiff_(actual, pp);
4478
+ expected = asymmetricResult.self;
4479
+ actual = asymmetricResult.other;
4480
+ }
4481
+ }
4078
4482
 
4079
- return {
4080
- equals: equals,
4483
+ var i;
4484
+ handleAsymmetricExpected();
4081
4485
 
4082
- contains: function(haystack, needle, customTesters) {
4083
- customTesters = customTesters || [];
4486
+ for (i = 0; i < objectPath.components.length; i++) {
4487
+ actual = actual[objectPath.components[i]];
4488
+ expected = expected[objectPath.components[i]];
4489
+ handleAsymmetricExpected();
4490
+ }
4084
4491
 
4085
- if (j$.isSet(haystack)) {
4086
- return haystack.has(needle);
4087
- }
4492
+ return {actual: actual, expected: expected};
4493
+ }
4088
4494
 
4089
- if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
4090
- (!!haystack && !haystack.indexOf))
4091
- {
4092
- for (var i = 0; i < haystack.length; i++) {
4093
- if (equals(haystack[i], needle, customTesters)) {
4094
- return true;
4095
- }
4495
+ };
4496
+
4497
+ getJasmineRequireObj().MatchersUtil = function(j$) {
4498
+ // TODO: convert all uses of j$.pp to use the injected pp
4499
+
4500
+ /**
4501
+ * _Note:_ Do not construct this directly. Jasmine will construct one and
4502
+ * pass it to matchers and asymmetric equality testers.
4503
+ * @name MatchersUtil
4504
+ * @classdesc Utilities for use in implementing matchers
4505
+ * @constructor
4506
+ */
4507
+ function MatchersUtil(options) {
4508
+ options = options || {};
4509
+ this.customTesters_ = options.customTesters || [];
4510
+ /**
4511
+ * Formats a value for use in matcher failure messages and similar contexts,
4512
+ * taking into account the current set of custom value formatters.
4513
+ * @function
4514
+ * @name MatchersUtil#pp
4515
+ * @since 3.6.0
4516
+ * @param {*} value The value to pretty-print
4517
+ * @return {string} The pretty-printed value
4518
+ */
4519
+ this.pp = options.pp || function() {};
4520
+ };
4521
+
4522
+ /**
4523
+ * Determines whether `haystack` contains `needle`, using the same comparison
4524
+ * logic as {@link MatchersUtil#equals}.
4525
+ * @function
4526
+ * @name MatchersUtil#contains
4527
+ * @since 2.0.0
4528
+ * @param {*} haystack The collection to search
4529
+ * @param {*} needle The value to search for
4530
+ * @param [customTesters] An array of custom equality testers
4531
+ * @returns {boolean} True if `needle` was found in `haystack`
4532
+ */
4533
+ MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
4534
+ if (j$.isSet(haystack)) {
4535
+ return haystack.has(needle);
4536
+ }
4537
+
4538
+ if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
4539
+ (!!haystack && !haystack.indexOf))
4540
+ {
4541
+ for (var i = 0; i < haystack.length; i++) {
4542
+ if (this.equals(haystack[i], needle, customTesters)) {
4543
+ return true;
4096
4544
  }
4097
- return false;
4098
4545
  }
4546
+ return false;
4547
+ }
4099
4548
 
4100
- return !!haystack && haystack.indexOf(needle) >= 0;
4101
- },
4549
+ return !!haystack && haystack.indexOf(needle) >= 0;
4550
+ };
4102
4551
 
4103
- buildFailureMessage: function() {
4104
- var args = Array.prototype.slice.call(arguments, 0),
4105
- matcherName = args[0],
4106
- isNot = args[1],
4107
- actual = args[2],
4108
- expected = args.slice(3),
4109
- englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
4110
-
4111
- var message = 'Expected ' +
4112
- j$.pp(actual) +
4113
- (isNot ? ' not ' : ' ') +
4114
- englishyPredicate;
4115
-
4116
- if (expected.length > 0) {
4117
- for (var i = 0; i < expected.length; i++) {
4118
- if (i > 0) {
4119
- message += ',';
4120
- }
4121
- message += ' ' + j$.pp(expected[i]);
4552
+ MatchersUtil.prototype.buildFailureMessage = function() {
4553
+ var self = this;
4554
+ var args = Array.prototype.slice.call(arguments, 0),
4555
+ matcherName = args[0],
4556
+ isNot = args[1],
4557
+ actual = args[2],
4558
+ expected = args.slice(3),
4559
+ englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
4560
+
4561
+ var message = 'Expected ' +
4562
+ self.pp(actual) +
4563
+ (isNot ? ' not ' : ' ') +
4564
+ englishyPredicate;
4565
+
4566
+ if (expected.length > 0) {
4567
+ for (var i = 0; i < expected.length; i++) {
4568
+ if (i > 0) {
4569
+ message += ',';
4122
4570
  }
4571
+ message += ' ' + self.pp(expected[i]);
4123
4572
  }
4124
-
4125
- return message + '.';
4126
4573
  }
4574
+
4575
+ return message + '.';
4127
4576
  };
4128
4577
 
4129
- function isAsymmetric(obj) {
4130
- return obj && j$.isA_('Function', obj.asymmetricMatch);
4131
- }
4578
+ MatchersUtil.prototype.asymmetricDiff_ = function(a, b, aStack, bStack, customTesters, diffBuilder) {
4579
+ if (j$.isFunction_(b.valuesForDiff_)) {
4580
+ var values = b.valuesForDiff_(a, this.pp);
4581
+ this.eq_(values.other, values.self, aStack, bStack, customTesters, diffBuilder);
4582
+ } else {
4583
+ diffBuilder.recordMismatch();
4584
+ }
4585
+ };
4132
4586
 
4133
- function asymmetricMatch(a, b, customTesters, diffBuilder) {
4134
- var asymmetricA = isAsymmetric(a),
4135
- asymmetricB = isAsymmetric(b),
4587
+ MatchersUtil.prototype.asymmetricMatch_ = function(a, b, aStack, bStack, customTesters, diffBuilder) {
4588
+ var asymmetricA = j$.isAsymmetricEqualityTester_(a),
4589
+ asymmetricB = j$.isAsymmetricEqualityTester_(b),
4590
+ shim,
4136
4591
  result;
4137
4592
 
4138
- if (asymmetricA && asymmetricB) {
4593
+ if (asymmetricA === asymmetricB) {
4139
4594
  return undefined;
4140
4595
  }
4141
4596
 
4597
+ shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters);
4598
+
4142
4599
  if (asymmetricA) {
4143
- result = a.asymmetricMatch(b, customTesters);
4600
+ result = a.asymmetricMatch(b, shim);
4144
4601
  if (!result) {
4145
- diffBuilder.record(a, b);
4602
+ diffBuilder.recordMismatch();
4146
4603
  }
4147
4604
  return result;
4148
4605
  }
4149
4606
 
4150
4607
  if (asymmetricB) {
4151
- result = b.asymmetricMatch(a, customTesters);
4608
+ result = b.asymmetricMatch(a, shim);
4152
4609
  if (!result) {
4153
- diffBuilder.record(a, b);
4610
+ this.asymmetricDiff_(a, b, aStack, bStack, customTesters, diffBuilder);
4154
4611
  }
4155
4612
  return result;
4156
4613
  }
4157
- }
4614
+ };
4615
+
4616
+ /**
4617
+ * Determines whether two values are deeply equal to each other.
4618
+ * @function
4619
+ * @name MatchersUtil#equals
4620
+ * @since 2.0.0
4621
+ * @param {*} a The first value to compare
4622
+ * @param {*} b The second value to compare
4623
+ * @param [customTesters] An array of custom equality testers
4624
+ * @returns {boolean} True if the values are equal
4625
+ */
4626
+ MatchersUtil.prototype.equals = function(a, b, customTestersOrDiffBuilder, diffBuilderOrNothing) {
4627
+ var customTesters, diffBuilder;
4628
+
4629
+ if (isDiffBuilder(customTestersOrDiffBuilder)) {
4630
+ diffBuilder = customTestersOrDiffBuilder;
4631
+ } else {
4632
+ customTesters = customTestersOrDiffBuilder;
4633
+ diffBuilder = diffBuilderOrNothing;
4634
+ }
4158
4635
 
4159
- function equals(a, b, customTesters, diffBuilder) {
4160
- customTesters = customTesters || [];
4636
+ customTesters = customTesters || this.customTesters_;
4161
4637
  diffBuilder = diffBuilder || j$.NullDiffBuilder();
4638
+ diffBuilder.setRoots(a, b);
4162
4639
 
4163
- return eq(a, b, [], [], customTesters, diffBuilder);
4164
- }
4640
+ return this.eq_(a, b, [], [], customTesters, diffBuilder);
4641
+ };
4165
4642
 
4166
4643
  // Equality function lovingly adapted from isEqual in
4167
4644
  // [Underscore](http://underscorejs.org)
4168
- function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
4169
- var result = true, i;
4645
+ MatchersUtil.prototype.eq_ = function(a, b, aStack, bStack, customTesters, diffBuilder) {
4646
+ var result = true, self = this, i;
4170
4647
 
4171
- var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
4648
+ var asymmetricResult = this.asymmetricMatch_(a, b, aStack, bStack, customTesters, diffBuilder);
4172
4649
  if (!j$.util.isUndefined(asymmetricResult)) {
4173
4650
  return asymmetricResult;
4174
4651
  }
@@ -4177,7 +4654,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4177
4654
  var customTesterResult = customTesters[i](a, b);
4178
4655
  if (!j$.util.isUndefined(customTesterResult)) {
4179
4656
  if (!customTesterResult) {
4180
- diffBuilder.record(a, b);
4657
+ diffBuilder.recordMismatch();
4181
4658
  }
4182
4659
  return customTesterResult;
4183
4660
  }
@@ -4186,7 +4663,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4186
4663
  if (a instanceof Error && b instanceof Error) {
4187
4664
  result = a.message == b.message;
4188
4665
  if (!result) {
4189
- diffBuilder.record(a, b);
4666
+ diffBuilder.recordMismatch();
4190
4667
  }
4191
4668
  return result;
4192
4669
  }
@@ -4196,7 +4673,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4196
4673
  if (a === b) {
4197
4674
  result = a !== 0 || 1 / a == 1 / b;
4198
4675
  if (!result) {
4199
- diffBuilder.record(a, b);
4676
+ diffBuilder.recordMismatch();
4200
4677
  }
4201
4678
  return result;
4202
4679
  }
@@ -4204,13 +4681,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4204
4681
  if (a === null || b === null) {
4205
4682
  result = a === b;
4206
4683
  if (!result) {
4207
- diffBuilder.record(a, b);
4684
+ diffBuilder.recordMismatch();
4208
4685
  }
4209
4686
  return result;
4210
4687
  }
4211
4688
  var className = Object.prototype.toString.call(a);
4212
4689
  if (className != Object.prototype.toString.call(b)) {
4213
- diffBuilder.record(a, b);
4690
+ diffBuilder.recordMismatch();
4214
4691
  return false;
4215
4692
  }
4216
4693
  switch (className) {
@@ -4220,15 +4697,15 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4220
4697
  // equivalent to `new String("5")`.
4221
4698
  result = a == String(b);
4222
4699
  if (!result) {
4223
- diffBuilder.record(a, b);
4700
+ diffBuilder.recordMismatch();
4224
4701
  }
4225
4702
  return result;
4226
4703
  case '[object Number]':
4227
4704
  // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
4228
4705
  // other numeric values.
4229
- result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
4706
+ result = a != +a ? b != +b : (a === 0 && b === 0 ? 1 / a == 1 / b : a == +b);
4230
4707
  if (!result) {
4231
- diffBuilder.record(a, b);
4708
+ diffBuilder.recordMismatch();
4232
4709
  }
4233
4710
  return result;
4234
4711
  case '[object Date]':
@@ -4238,7 +4715,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4238
4715
  // of `NaN` are not equivalent.
4239
4716
  result = +a == +b;
4240
4717
  if (!result) {
4241
- diffBuilder.record(a, b);
4718
+ diffBuilder.recordMismatch();
4242
4719
  }
4243
4720
  return result;
4244
4721
  // RegExps are compared by their source patterns and flags.
@@ -4249,7 +4726,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4249
4726
  a.ignoreCase == b.ignoreCase;
4250
4727
  }
4251
4728
  if (typeof a != 'object' || typeof b != 'object') {
4252
- diffBuilder.record(a, b);
4729
+ diffBuilder.recordMismatch();
4253
4730
  return false;
4254
4731
  }
4255
4732
 
@@ -4259,12 +4736,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4259
4736
  // At first try to use DOM3 method isEqualNode
4260
4737
  result = a.isEqualNode(b);
4261
4738
  if (!result) {
4262
- diffBuilder.record(a, b);
4739
+ diffBuilder.recordMismatch();
4263
4740
  }
4264
4741
  return result;
4265
4742
  }
4266
4743
  if (aIsDomNode || bIsDomNode) {
4267
- diffBuilder.record(a, b);
4744
+ diffBuilder.recordMismatch();
4268
4745
  return false;
4269
4746
  }
4270
4747
 
@@ -4294,7 +4771,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4294
4771
 
4295
4772
  diffBuilder.withPath('length', function() {
4296
4773
  if (aLength !== bLength) {
4297
- diffBuilder.record(aLength, bLength);
4774
+ diffBuilder.recordMismatch();
4298
4775
  result = false;
4299
4776
  }
4300
4777
  });
@@ -4302,10 +4779,10 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4302
4779
  for (i = 0; i < aLength || i < bLength; i++) {
4303
4780
  diffBuilder.withPath(i, function() {
4304
4781
  if (i >= bLength) {
4305
- diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
4782
+ diffBuilder.recordMismatch(actualArrayIsLongerFormatter.bind(null, self.pp));
4306
4783
  result = false;
4307
4784
  } else {
4308
- result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
4785
+ result = self.eq_(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
4309
4786
  }
4310
4787
  });
4311
4788
  }
@@ -4314,7 +4791,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4314
4791
  }
4315
4792
  } else if (j$.isMap(a) && j$.isMap(b)) {
4316
4793
  if (a.size != b.size) {
4317
- diffBuilder.record(a, b);
4794
+ diffBuilder.recordMismatch();
4318
4795
  return false;
4319
4796
  }
4320
4797
 
@@ -4345,23 +4822,23 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4345
4822
  // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
4346
4823
  // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
4347
4824
  // obj identity (that are otherwise equal) to not match.
4348
- if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
4349
- eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
4825
+ if (j$.isAsymmetricEqualityTester_(mapKey) || j$.isAsymmetricEqualityTester_(cmpKey) &&
4826
+ this.eq_(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
4350
4827
  mapValueB = b.get(cmpKey);
4351
4828
  } else {
4352
4829
  mapValueB = b.get(mapKey);
4353
4830
  }
4354
- result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
4831
+ result = this.eq_(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
4355
4832
  }
4356
4833
  }
4357
4834
 
4358
4835
  if (!result) {
4359
- diffBuilder.record(a, b);
4836
+ diffBuilder.recordMismatch();
4360
4837
  return false;
4361
4838
  }
4362
4839
  } else if (j$.isSet(a) && j$.isSet(b)) {
4363
4840
  if (a.size != b.size) {
4364
- diffBuilder.record(a, b);
4841
+ diffBuilder.recordMismatch();
4365
4842
  return false;
4366
4843
  }
4367
4844
 
@@ -4395,7 +4872,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4395
4872
  otherValue = otherValues[l];
4396
4873
  prevStackSize = baseStack.length;
4397
4874
  // compare by value equality
4398
- found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
4875
+ found = this.eq_(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
4399
4876
  if (!found && prevStackSize !== baseStack.length) {
4400
4877
  baseStack.splice(prevStackSize);
4401
4878
  otherStack.splice(prevStackSize);
@@ -4406,7 +4883,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4406
4883
  }
4407
4884
 
4408
4885
  if (!result) {
4409
- diffBuilder.record(a, b);
4886
+ diffBuilder.recordMismatch();
4410
4887
  return false;
4411
4888
  }
4412
4889
  } else {
@@ -4419,7 +4896,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4419
4896
  a instanceof aCtor && b instanceof bCtor &&
4420
4897
  !(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
4421
4898
 
4422
- diffBuilder.record(a, b, constructorsAreDifferentFormatter);
4899
+ diffBuilder.recordMismatch(constructorsAreDifferentFormatter.bind(null, this.pp));
4423
4900
  return false;
4424
4901
  }
4425
4902
  }
@@ -4430,7 +4907,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4430
4907
 
4431
4908
  // Ensure that both objects contain the same number of properties before comparing deep equality.
4432
4909
  if (keys(b, className == '[object Array]').length !== size) {
4433
- diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
4910
+ diffBuilder.recordMismatch(objectKeysAreDifferentFormatter.bind(null, this.pp));
4434
4911
  return false;
4435
4912
  }
4436
4913
 
@@ -4438,13 +4915,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4438
4915
  key = aKeys[i];
4439
4916
  // Deep compare each member
4440
4917
  if (!j$.util.has(b, key)) {
4441
- diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
4918
+ diffBuilder.recordMismatch(objectKeysAreDifferentFormatter.bind(null, this.pp));
4442
4919
  result = false;
4443
4920
  continue;
4444
4921
  }
4445
4922
 
4446
4923
  diffBuilder.withPath(key, function() {
4447
- if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
4924
+ if(!self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
4448
4925
  result = false;
4449
4926
  }
4450
4927
  });
@@ -4459,7 +4936,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4459
4936
  bStack.pop();
4460
4937
 
4461
4938
  return result;
4462
- }
4939
+ };
4463
4940
 
4464
4941
  function keys(obj, isArray) {
4465
4942
  var allKeys = Object.keys ? Object.keys(obj) :
@@ -4495,11 +4972,11 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4495
4972
  return typeof obj === 'function';
4496
4973
  }
4497
4974
 
4498
- function objectKeysAreDifferentFormatter(actual, expected, path) {
4975
+ function objectKeysAreDifferentFormatter(pp, actual, expected, path) {
4499
4976
  var missingProperties = j$.util.objectDifference(expected, actual),
4500
4977
  extraProperties = j$.util.objectDifference(actual, expected),
4501
- missingPropertiesMessage = formatKeyValuePairs(missingProperties),
4502
- extraPropertiesMessage = formatKeyValuePairs(extraProperties),
4978
+ missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties),
4979
+ extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties),
4503
4980
  messages = [];
4504
4981
 
4505
4982
  if (!path.depth()) {
@@ -4517,7 +4994,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4517
4994
  return messages.join('\n');
4518
4995
  }
4519
4996
 
4520
- function constructorsAreDifferentFormatter(actual, expected, path) {
4997
+ function constructorsAreDifferentFormatter(pp, actual, expected, path) {
4521
4998
  if (!path.depth()) {
4522
4999
  path = 'object';
4523
5000
  }
@@ -4525,25 +5002,94 @@ getJasmineRequireObj().matchersUtil = function(j$) {
4525
5002
  return 'Expected ' +
4526
5003
  path + ' to be a kind of ' +
4527
5004
  j$.fnNameFor(expected.constructor) +
4528
- ', but was ' + j$.pp(actual) + '.';
5005
+ ', but was ' + pp(actual) + '.';
4529
5006
  }
4530
5007
 
4531
- function actualArrayIsLongerFormatter(actual, expected, path) {
5008
+ function actualArrayIsLongerFormatter(pp, actual, expected, path) {
4532
5009
  return 'Unexpected ' +
4533
5010
  path + (path.depth() ? ' = ' : '') +
4534
- j$.pp(actual) +
5011
+ pp(actual) +
4535
5012
  ' in array.';
4536
5013
  }
4537
5014
 
4538
- function formatKeyValuePairs(obj) {
5015
+ function formatKeyValuePairs(pp, obj) {
4539
5016
  var formatted = '';
4540
5017
  for (var key in obj) {
4541
- formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
5018
+ formatted += '\n ' + key + ': ' + pp(obj[key]);
4542
5019
  }
4543
5020
  return formatted;
4544
5021
  }
5022
+
5023
+ function isDiffBuilder(obj) {
5024
+ return obj && typeof obj.recordMismatch === 'function';
5025
+ }
5026
+
5027
+ return MatchersUtil;
5028
+ };
5029
+
5030
+ getJasmineRequireObj().MismatchTree = function (j$) {
5031
+
5032
+ /*
5033
+ To be able to apply custom object formatters at all possible levels of an
5034
+ object graph, DiffBuilder needs to be able to know not just where the
5035
+ mismatch occurred but also all ancestors of the mismatched value in both
5036
+ the expected and actual object graphs. MismatchTree maintains that context
5037
+ and provides it via the traverse method.
5038
+ */
5039
+ function MismatchTree(path) {
5040
+ this.path = path || new j$.ObjectPath([]);
5041
+ this.formatter = undefined;
5042
+ this.children = [];
5043
+ this.isMismatch = false;
5044
+ }
5045
+
5046
+ MismatchTree.prototype.add = function (path, formatter) {
5047
+ var key, child;
5048
+
5049
+ if (path.depth() === 0) {
5050
+ this.formatter = formatter;
5051
+ this.isMismatch = true;
5052
+ } else {
5053
+ key = path.components[0];
5054
+ path = path.shift();
5055
+ child = this.child(key);
5056
+
5057
+ if (!child) {
5058
+ child = new MismatchTree(this.path.add(key));
5059
+ this.children.push(child);
5060
+ }
5061
+
5062
+ child.add(path, formatter);
5063
+ }
5064
+ };
5065
+
5066
+ MismatchTree.prototype.traverse = function (visit) {
5067
+ var i, hasChildren = this.children.length > 0;
5068
+
5069
+ if (this.isMismatch || hasChildren) {
5070
+ if (visit(this.path, !hasChildren, this.formatter)) {
5071
+ for (i = 0; i < this.children.length; i++) {
5072
+ this.children[i].traverse(visit);
5073
+ }
5074
+ }
5075
+ }
5076
+ };
5077
+
5078
+ MismatchTree.prototype.child = function(key) {
5079
+ var i, pathEls;
5080
+
5081
+ for (i = 0; i < this.children.length; i++) {
5082
+ pathEls = this.children[i].path.components;
5083
+ if (pathEls[pathEls.length - 1] === key) {
5084
+ return this.children[i];
5085
+ }
5086
+ }
5087
+ };
5088
+
5089
+ return MismatchTree;
4545
5090
  };
4546
5091
 
5092
+
4547
5093
  getJasmineRequireObj().nothing = function() {
4548
5094
  /**
4549
5095
  * {@link expect} nothing explicitly.
@@ -4572,7 +5118,8 @@ getJasmineRequireObj().NullDiffBuilder = function(j$) {
4572
5118
  withPath: function(_, block) {
4573
5119
  block();
4574
5120
  },
4575
- record: function() {}
5121
+ setRoots: function() {},
5122
+ recordMismatch: function() {}
4576
5123
  };
4577
5124
  };
4578
5125
  };
@@ -4594,6 +5141,10 @@ getJasmineRequireObj().ObjectPath = function(j$) {
4594
5141
  return new ObjectPath(this.components.concat([component]));
4595
5142
  };
4596
5143
 
5144
+ ObjectPath.prototype.shift = function() {
5145
+ return new ObjectPath(this.components.slice(1));
5146
+ };
5147
+
4597
5148
  ObjectPath.prototype.depth = function() {
4598
5149
  return this.components.length;
4599
5150
  };
@@ -4627,6 +5178,7 @@ getJasmineRequireObj().ObjectPath = function(j$) {
4627
5178
 
4628
5179
  getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) {
4629
5180
  var availableMatchers = [
5181
+ 'toBePending',
4630
5182
  'toBeResolved',
4631
5183
  'toBeRejected',
4632
5184
  'toBeResolvedTo',
@@ -4653,7 +5205,7 @@ getJasmineRequireObj().toBe = function(j$) {
4653
5205
  * @example
4654
5206
  * expect(thing).toBe(realThing);
4655
5207
  */
4656
- function toBe(util) {
5208
+ function toBe(matchersUtil) {
4657
5209
  var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
4658
5210
 
4659
5211
  return {
@@ -4663,7 +5215,7 @@ getJasmineRequireObj().toBe = function(j$) {
4663
5215
  };
4664
5216
 
4665
5217
  if (typeof expected === 'object') {
4666
- result.message = util.buildFailureMessage('toBe', result.pass, actual, expected) + tip;
5218
+ result.message = matchersUtil.buildFailureMessage('toBe', result.pass, actual, expected) + tip;
4667
5219
  }
4668
5220
 
4669
5221
  return result;
@@ -4839,11 +5391,11 @@ getJasmineRequireObj().toBeInstanceOf = function(j$) {
4839
5391
  * expect(3).toBeInstanceOf(Number);
4840
5392
  * expect(new Error()).toBeInstanceOf(Error);
4841
5393
  */
4842
- function toBeInstanceOf(util, customEqualityTesters) {
5394
+ function toBeInstanceOf(matchersUtil) {
4843
5395
  return {
4844
5396
  compare: function(actual, expected) {
4845
- var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : j$.pp(actual),
4846
- expectedType = expected ? j$.fnNameFor(expected) : j$.pp(expected),
5397
+ var actualType = actual && actual.constructor ? j$.fnNameFor(actual.constructor) : matchersUtil.pp(actual),
5398
+ expectedType = expected ? j$.fnNameFor(expected) : matchersUtil.pp(expected),
4847
5399
  expectedMatcher,
4848
5400
  pass;
4849
5401
 
@@ -4929,7 +5481,7 @@ getJasmineRequireObj().toBeNaN = function(j$) {
4929
5481
  * @example
4930
5482
  * expect(thing).toBeNaN();
4931
5483
  */
4932
- function toBeNaN() {
5484
+ function toBeNaN(matchersUtil) {
4933
5485
  return {
4934
5486
  compare: function(actual) {
4935
5487
  var result = {
@@ -4939,7 +5491,7 @@ getJasmineRequireObj().toBeNaN = function(j$) {
4939
5491
  if (result.pass) {
4940
5492
  result.message = 'Expected actual not to be NaN.';
4941
5493
  } else {
4942
- result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
5494
+ result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.'; };
4943
5495
  }
4944
5496
 
4945
5497
  return result;
@@ -4959,7 +5511,7 @@ getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
4959
5511
  * @example
4960
5512
  * expect(thing).toBeNegativeInfinity();
4961
5513
  */
4962
- function toBeNegativeInfinity() {
5514
+ function toBeNegativeInfinity(matchersUtil) {
4963
5515
  return {
4964
5516
  compare: function(actual) {
4965
5517
  var result = {
@@ -4969,7 +5521,7 @@ getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
4969
5521
  if (result.pass) {
4970
5522
  result.message = 'Expected actual not to be -Infinity.';
4971
5523
  } else {
4972
- result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be -Infinity.'; };
5524
+ result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.'; };
4973
5525
  }
4974
5526
 
4975
5527
  return result;
@@ -5011,7 +5563,7 @@ getJasmineRequireObj().toBePositiveInfinity = function(j$) {
5011
5563
  * @example
5012
5564
  * expect(thing).toBePositiveInfinity();
5013
5565
  */
5014
- function toBePositiveInfinity() {
5566
+ function toBePositiveInfinity(matchersUtil) {
5015
5567
  return {
5016
5568
  compare: function(actual) {
5017
5569
  var result = {
@@ -5021,7 +5573,7 @@ getJasmineRequireObj().toBePositiveInfinity = function(j$) {
5021
5573
  if (result.pass) {
5022
5574
  result.message = 'Expected actual not to be Infinity.';
5023
5575
  } else {
5024
- result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be Infinity.'; };
5576
+ result.message = function() { return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.'; };
5025
5577
  }
5026
5578
 
5027
5579
  return result;
@@ -5109,14 +5661,12 @@ getJasmineRequireObj().toContain = function() {
5109
5661
  * expect(array).toContain(anElement);
5110
5662
  * expect(string).toContain(substring);
5111
5663
  */
5112
- function toContain(util, customEqualityTesters) {
5113
- customEqualityTesters = customEqualityTesters || [];
5114
-
5664
+ function toContain(matchersUtil) {
5115
5665
  return {
5116
5666
  compare: function(actual, expected) {
5117
5667
 
5118
5668
  return {
5119
- pass: util.contains(actual, expected, customEqualityTesters)
5669
+ pass: matchersUtil.contains(actual, expected)
5120
5670
  };
5121
5671
  }
5122
5672
  };
@@ -5135,17 +5685,15 @@ getJasmineRequireObj().toEqual = function(j$) {
5135
5685
  * @example
5136
5686
  * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
5137
5687
  */
5138
- function toEqual(util, customEqualityTesters) {
5139
- customEqualityTesters = customEqualityTesters || [];
5140
-
5688
+ function toEqual(matchersUtil) {
5141
5689
  return {
5142
5690
  compare: function(actual, expected) {
5143
5691
  var result = {
5144
5692
  pass: false
5145
5693
  },
5146
- diffBuilder = j$.DiffBuilder();
5694
+ diffBuilder = j$.DiffBuilder({prettyPrinter: matchersUtil.pp});
5147
5695
 
5148
- result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
5696
+ result.pass = matchersUtil.equals(actual, expected, diffBuilder);
5149
5697
 
5150
5698
  // TODO: only set error message if test fails
5151
5699
  result.message = diffBuilder.getMessage();
@@ -5171,13 +5719,13 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
5171
5719
  * expect(mySpy).toHaveBeenCalled();
5172
5720
  * expect(mySpy).not.toHaveBeenCalled();
5173
5721
  */
5174
- function toHaveBeenCalled() {
5722
+ function toHaveBeenCalled(matchersUtil) {
5175
5723
  return {
5176
5724
  compare: function(actual) {
5177
5725
  var result = {};
5178
5726
 
5179
5727
  if (!j$.isSpy(actual)) {
5180
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
5728
+ throw new Error(getErrorMsg('Expected a spy, but got ' + matchersUtil.pp(actual) + '.'));
5181
5729
  }
5182
5730
 
5183
5731
  if (arguments.length > 1) {
@@ -5211,14 +5759,14 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
5211
5759
  * @example
5212
5760
  * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
5213
5761
  */
5214
- function toHaveBeenCalledBefore() {
5762
+ function toHaveBeenCalledBefore(matchersUtil) {
5215
5763
  return {
5216
5764
  compare: function(firstSpy, latterSpy) {
5217
5765
  if (!j$.isSpy(firstSpy)) {
5218
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
5766
+ throw new Error(getErrorMsg('Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.'));
5219
5767
  }
5220
5768
  if (!j$.isSpy(latterSpy)) {
5221
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
5769
+ throw new Error(getErrorMsg('Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.'));
5222
5770
  }
5223
5771
 
5224
5772
  var result = { pass: false };
@@ -5260,6 +5808,76 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
5260
5808
  return toHaveBeenCalledBefore;
5261
5809
  };
5262
5810
 
5811
+ getJasmineRequireObj().toHaveBeenCalledOnceWith = function (j$) {
5812
+
5813
+ var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledOnceWith>', 'expect(<spyObj>).toHaveBeenCalledOnceWith(...arguments)');
5814
+
5815
+ /**
5816
+ * {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments.
5817
+ * @function
5818
+ * @name matchers#toHaveBeenCalledOnceWith
5819
+ * @since 3.6.0
5820
+ * @param {...Object} - The arguments to look for
5821
+ * @example
5822
+ * expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2);
5823
+ */
5824
+ function toHaveBeenCalledOnceWith(util) {
5825
+ return {
5826
+ compare: function () {
5827
+ var args = Array.prototype.slice.call(arguments, 0),
5828
+ actual = args[0],
5829
+ expectedArgs = args.slice(1);
5830
+
5831
+ if (!j$.isSpy(actual)) {
5832
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
5833
+ }
5834
+
5835
+ var prettyPrintedCalls = actual.calls.allArgs().map(function (argsForCall) {
5836
+ return ' ' + j$.pp(argsForCall);
5837
+ });
5838
+
5839
+ if (actual.calls.count() === 1 && util.contains(actual.calls.allArgs(), expectedArgs)) {
5840
+ return {
5841
+ pass: true,
5842
+ message: 'Expected spy ' + actual.and.identity + ' to have been called 0 times, multiple times, or once, but with arguments different from:\n'
5843
+ + ' ' + j$.pp(expectedArgs) + '\n'
5844
+ + 'But the actual call was:\n'
5845
+ + prettyPrintedCalls.join(',\n') + '.\n\n'
5846
+ };
5847
+ }
5848
+
5849
+ function getDiffs() {
5850
+ return actual.calls.allArgs().map(function (argsForCall, callIx) {
5851
+ var diffBuilder = new j$.DiffBuilder();
5852
+ util.equals(argsForCall, expectedArgs, diffBuilder);
5853
+ return diffBuilder.getMessage();
5854
+ });
5855
+ }
5856
+
5857
+ function butString() {
5858
+ switch (actual.calls.count()) {
5859
+ case 0:
5860
+ return 'But it was never called.\n\n';
5861
+ case 1:
5862
+ return 'But the actual call was:\n' + prettyPrintedCalls.join(',\n') + '.\n' + getDiffs().join('\n') + '\n\n';
5863
+ default:
5864
+ return 'But the actual calls were:\n' + prettyPrintedCalls.join(',\n') + '.\n\n';
5865
+ }
5866
+ }
5867
+
5868
+ return {
5869
+ pass: false,
5870
+ message: 'Expected spy ' + actual.and.identity + ' to have been called only once, and with given args:\n'
5871
+ + ' ' + j$.pp(expectedArgs) + '\n'
5872
+ + butString()
5873
+ };
5874
+ }
5875
+ };
5876
+ }
5877
+
5878
+ return toHaveBeenCalledOnceWith;
5879
+ };
5880
+
5263
5881
  getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
5264
5882
 
5265
5883
  var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
@@ -5273,11 +5891,11 @@ getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
5273
5891
  * @example
5274
5892
  * expect(mySpy).toHaveBeenCalledTimes(3);
5275
5893
  */
5276
- function toHaveBeenCalledTimes() {
5894
+ function toHaveBeenCalledTimes(matchersUtil) {
5277
5895
  return {
5278
5896
  compare: function(actual, expected) {
5279
5897
  if (!j$.isSpy(actual)) {
5280
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
5898
+ throw new Error(getErrorMsg('Expected a spy, but got ' + matchersUtil.pp(actual) + '.'));
5281
5899
  }
5282
5900
 
5283
5901
  var args = Array.prototype.slice.call(arguments, 0),
@@ -5315,7 +5933,7 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
5315
5933
  * @example
5316
5934
  * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
5317
5935
  */
5318
- function toHaveBeenCalledWith(util, customEqualityTesters) {
5936
+ function toHaveBeenCalledWith(matchersUtil) {
5319
5937
  return {
5320
5938
  compare: function() {
5321
5939
  var args = Array.prototype.slice.call(arguments, 0),
@@ -5324,40 +5942,40 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
5324
5942
  result = { pass: false };
5325
5943
 
5326
5944
  if (!j$.isSpy(actual)) {
5327
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
5945
+ throw new Error(getErrorMsg('Expected a spy, but got ' + matchersUtil.pp(actual) + '.'));
5328
5946
  }
5329
5947
 
5330
5948
  if (!actual.calls.any()) {
5331
5949
  result.message = function() {
5332
5950
  return 'Expected spy ' + actual.and.identity + ' to have been called with:\n' +
5333
- ' ' + j$.pp(expectedArgs) +
5951
+ ' ' + matchersUtil.pp(expectedArgs) +
5334
5952
  '\nbut it was never called.';
5335
5953
  };
5336
5954
  return result;
5337
5955
  }
5338
5956
 
5339
- if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
5957
+ if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) {
5340
5958
  result.pass = true;
5341
5959
  result.message = function() {
5342
5960
  return 'Expected spy ' + actual.and.identity + ' not to have been called with:\n' +
5343
- ' ' + j$.pp(expectedArgs) +
5961
+ ' ' + matchersUtil.pp(expectedArgs) +
5344
5962
  '\nbut it was.';
5345
5963
  };
5346
5964
  } else {
5347
5965
  result.message = function() {
5348
5966
  var prettyPrintedCalls = actual.calls.allArgs().map(function(argsForCall) {
5349
- return ' ' + j$.pp(argsForCall);
5967
+ return ' ' + matchersUtil.pp(argsForCall);
5350
5968
  });
5351
5969
 
5352
5970
  var diffs = actual.calls.allArgs().map(function(argsForCall, callIx) {
5353
5971
  var diffBuilder = new j$.DiffBuilder();
5354
- util.equals(argsForCall, expectedArgs, customEqualityTesters, diffBuilder);
5972
+ matchersUtil.equals(argsForCall, expectedArgs, diffBuilder);
5355
5973
  return 'Call ' + callIx + ':\n' +
5356
5974
  diffBuilder.getMessage().replace(/^/mg, ' ');
5357
5975
  });
5358
5976
 
5359
5977
  return 'Expected spy ' + actual.and.identity + ' to have been called with:\n' +
5360
- ' ' + j$.pp(expectedArgs) + '\n' + '' +
5978
+ ' ' + matchersUtil.pp(expectedArgs) + '\n' + '' +
5361
5979
  'but actual calls were:\n' +
5362
5980
  prettyPrintedCalls.join(',\n') + '.\n\n' +
5363
5981
  diffs.join('\n');
@@ -5384,11 +6002,11 @@ getJasmineRequireObj().toHaveClass = function(j$) {
5384
6002
  * el.className = 'foo bar baz';
5385
6003
  * expect(el).toHaveClass('bar');
5386
6004
  */
5387
- function toHaveClass(util, customEqualityTesters) {
6005
+ function toHaveClass(matchersUtil) {
5388
6006
  return {
5389
6007
  compare: function(actual, expected) {
5390
6008
  if (!isElement(actual)) {
5391
- throw new Error(j$.pp(actual) + ' is not a DOM element');
6009
+ throw new Error(matchersUtil.pp(actual) + ' is not a DOM element');
5392
6010
  }
5393
6011
 
5394
6012
  return {
@@ -5407,6 +6025,49 @@ getJasmineRequireObj().toHaveClass = function(j$) {
5407
6025
  return toHaveClass;
5408
6026
  };
5409
6027
 
6028
+ getJasmineRequireObj().toHaveSize = function(j$) {
6029
+ /**
6030
+ * {@link expect} the actual size to be equal to the expected, using array-like length or object keys size.
6031
+ * @function
6032
+ * @name matchers#toHaveSize
6033
+ * @since 3.6.0
6034
+ * @param {Object} expected - Expected size
6035
+ * @example
6036
+ * array = [1,2];
6037
+ * expect(array).toHaveSize(2);
6038
+ */
6039
+ function toHaveSize() {
6040
+ return {
6041
+ compare: function(actual, expected) {
6042
+ var result = {
6043
+ pass: false
6044
+ };
6045
+
6046
+ if (j$.isA_('WeakSet', actual) || j$.isWeakMap(actual) || j$.isDataView(actual)) {
6047
+ throw new Error('Cannot get size of ' + actual + '.');
6048
+ }
6049
+
6050
+ if (j$.isSet(actual) || j$.isMap(actual)) {
6051
+ result.pass = actual.size === expected;
6052
+ } else if (isLength(actual.length)) {
6053
+ result.pass = actual.length === expected;
6054
+ } else {
6055
+ result.pass = Object.keys(actual).length === expected;
6056
+ }
6057
+
6058
+ return result;
6059
+ }
6060
+ };
6061
+ }
6062
+
6063
+ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; // eslint-disable-line compat/compat
6064
+ function isLength(value) {
6065
+ return (typeof value == 'number') && value > -1 && value % 1 === 0 && value <= MAX_SAFE_INTEGER;
6066
+ }
6067
+
6068
+ return toHaveSize;
6069
+ };
6070
+
5410
6071
  getJasmineRequireObj().toMatch = function(j$) {
5411
6072
 
5412
6073
  var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
@@ -5454,7 +6115,7 @@ getJasmineRequireObj().toThrow = function(j$) {
5454
6115
  * expect(function() { return 'things'; }).toThrow('foo');
5455
6116
  * expect(function() { return 'stuff'; }).toThrow();
5456
6117
  */
5457
- function toThrow(util) {
6118
+ function toThrow(matchersUtil) {
5458
6119
  return {
5459
6120
  compare: function(actual, expected) {
5460
6121
  var result = { pass: false },
@@ -5479,16 +6140,16 @@ getJasmineRequireObj().toThrow = function(j$) {
5479
6140
 
5480
6141
  if (arguments.length == 1) {
5481
6142
  result.pass = true;
5482
- result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
6143
+ result.message = function() { return 'Expected function not to throw, but it threw ' + matchersUtil.pp(thrown) + '.'; };
5483
6144
 
5484
6145
  return result;
5485
6146
  }
5486
6147
 
5487
- if (util.equals(thrown, expected)) {
6148
+ if (matchersUtil.equals(thrown, expected)) {
5488
6149
  result.pass = true;
5489
- result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
6150
+ result.message = function() { return 'Expected function not to throw ' + matchersUtil.pp(expected) + '.'; };
5490
6151
  } else {
5491
- result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
6152
+ result.message = function() { return 'Expected function to throw ' + matchersUtil.pp(expected) + ', but it threw ' + matchersUtil.pp(thrown) + '.'; };
5492
6153
  }
5493
6154
 
5494
6155
  return result;
@@ -5517,7 +6178,7 @@ getJasmineRequireObj().toThrowError = function(j$) {
5517
6178
  * expect(function() { return 'other'; }).toThrowError(/foo/);
5518
6179
  * expect(function() { return 'other'; }).toThrowError();
5519
6180
  */
5520
- function toThrowError () {
6181
+ function toThrowError(matchersUtil) {
5521
6182
  return {
5522
6183
  compare: function(actual) {
5523
6184
  var errorMatcher = getMatcher.apply(null, arguments),
@@ -5535,7 +6196,7 @@ getJasmineRequireObj().toThrowError = function(j$) {
5535
6196
  }
5536
6197
 
5537
6198
  if (!j$.isError_(thrown)) {
5538
- return fail(function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; });
6199
+ return fail(function() { return 'Expected function to throw an Error, but it threw ' + matchersUtil.pp(thrown) + '.'; });
5539
6200
  }
5540
6201
 
5541
6202
  return errorMatcher.match(thrown);
@@ -5598,7 +6259,7 @@ getJasmineRequireObj().toThrowError = function(j$) {
5598
6259
  thrownMessage = '';
5599
6260
 
5600
6261
  if (expected) {
5601
- thrownMessage = ' with message ' + j$.pp(thrown.message);
6262
+ thrownMessage = ' with message ' + matchersUtil.pp(thrown.message);
5602
6263
  }
5603
6264
 
5604
6265
  return thrownName + thrownMessage;
@@ -5608,9 +6269,9 @@ getJasmineRequireObj().toThrowError = function(j$) {
5608
6269
  if (expected === null) {
5609
6270
  return '';
5610
6271
  } else if (expected instanceof RegExp) {
5611
- return ' with a message matching ' + j$.pp(expected);
6272
+ return ' with a message matching ' + matchersUtil.pp(expected);
5612
6273
  } else {
5613
- return ' with message ' + j$.pp(expected);
6274
+ return ' with message ' + matchersUtil.pp(expected);
5614
6275
  }
5615
6276
  }
5616
6277
 
@@ -5679,7 +6340,7 @@ getJasmineRequireObj().toThrowMatching = function(j$) {
5679
6340
  * @example
5680
6341
  * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
5681
6342
  */
5682
- function toThrowMatching() {
6343
+ function toThrowMatching(matchersUtil) {
5683
6344
  return {
5684
6345
  compare: function(actual, predicate) {
5685
6346
  var thrown;
@@ -5709,14 +6370,14 @@ getJasmineRequireObj().toThrowMatching = function(j$) {
5709
6370
  }
5710
6371
  }
5711
6372
  };
5712
- }
5713
6373
 
5714
- function thrownDescription(thrown) {
5715
- if (thrown && thrown.constructor) {
5716
- return j$.fnNameFor(thrown.constructor) + ' with message ' +
5717
- j$.pp(thrown.message);
5718
- } else {
5719
- return j$.pp(thrown);
6374
+ function thrownDescription(thrown) {
6375
+ if (thrown && thrown.constructor) {
6376
+ return j$.fnNameFor(thrown.constructor) + ' with message ' +
6377
+ matchersUtil.pp(thrown.message);
6378
+ } else {
6379
+ return matchersUtil.pp(thrown);
6380
+ }
5720
6381
  }
5721
6382
  }
5722
6383
 
@@ -5843,12 +6504,14 @@ getJasmineRequireObj().MockDate = function() {
5843
6504
  return MockDate;
5844
6505
  };
5845
6506
 
5846
- getJasmineRequireObj().pp = function(j$) {
5847
- function PrettyPrinter() {
6507
+ getJasmineRequireObj().makePrettyPrinter = function(j$) {
6508
+ function SinglePrettyPrintRun(customObjectFormatters, pp) {
6509
+ this.customObjectFormatters_ = customObjectFormatters;
5848
6510
  this.ppNestLevel_ = 0;
5849
6511
  this.seen = [];
5850
6512
  this.length = 0;
5851
6513
  this.stringParts = [];
6514
+ this.pp_ = pp;
5852
6515
  }
5853
6516
 
5854
6517
  function hasCustomToString(value) {
@@ -5866,10 +6529,14 @@ getJasmineRequireObj().pp = function(j$) {
5866
6529
  }
5867
6530
  }
5868
6531
 
5869
- PrettyPrinter.prototype.format = function(value) {
6532
+ SinglePrettyPrintRun.prototype.format = function(value) {
5870
6533
  this.ppNestLevel_++;
5871
6534
  try {
5872
- if (j$.util.isUndefined(value)) {
6535
+ var customFormatResult = this.applyCustomFormatters_(value);
6536
+
6537
+ if (customFormatResult) {
6538
+ this.emitScalar(customFormatResult);
6539
+ } else if (j$.util.isUndefined(value)) {
5873
6540
  this.emitScalar('undefined');
5874
6541
  } else if (value === null) {
5875
6542
  this.emitScalar('null');
@@ -5878,7 +6545,7 @@ getJasmineRequireObj().pp = function(j$) {
5878
6545
  } else if (value === j$.getGlobal()) {
5879
6546
  this.emitScalar('<global>');
5880
6547
  } else if (value.jasmineToString) {
5881
- this.emitScalar(value.jasmineToString());
6548
+ this.emitScalar(value.jasmineToString(this.pp_));
5882
6549
  } else if (typeof value === 'string') {
5883
6550
  this.emitString(value);
5884
6551
  } else if (j$.isSpy(value)) {
@@ -5940,7 +6607,11 @@ getJasmineRequireObj().pp = function(j$) {
5940
6607
  }
5941
6608
  };
5942
6609
 
5943
- PrettyPrinter.prototype.iterateObject = function(obj, fn) {
6610
+ SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
6611
+ return customFormat(value, this.customObjectFormatters_);
6612
+ };
6613
+
6614
+ SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
5944
6615
  var objKeys = keys(obj, j$.isArray_(obj));
5945
6616
  var isGetter = function isGetter(prop) {};
5946
6617
 
@@ -5959,15 +6630,15 @@ getJasmineRequireObj().pp = function(j$) {
5959
6630
  return objKeys.length > length;
5960
6631
  };
5961
6632
 
5962
- PrettyPrinter.prototype.emitScalar = function(value) {
6633
+ SinglePrettyPrintRun.prototype.emitScalar = function(value) {
5963
6634
  this.append(value);
5964
6635
  };
5965
6636
 
5966
- PrettyPrinter.prototype.emitString = function(value) {
6637
+ SinglePrettyPrintRun.prototype.emitString = function(value) {
5967
6638
  this.append("'" + value + "'");
5968
6639
  };
5969
6640
 
5970
- PrettyPrinter.prototype.emitArray = function(array) {
6641
+ SinglePrettyPrintRun.prototype.emitArray = function(array) {
5971
6642
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
5972
6643
  this.append('Array');
5973
6644
  return;
@@ -6003,7 +6674,7 @@ getJasmineRequireObj().pp = function(j$) {
6003
6674
  this.append(' ]');
6004
6675
  };
6005
6676
 
6006
- PrettyPrinter.prototype.emitSet = function(set) {
6677
+ SinglePrettyPrintRun.prototype.emitSet = function(set) {
6007
6678
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
6008
6679
  this.append('Set');
6009
6680
  return;
@@ -6028,7 +6699,7 @@ getJasmineRequireObj().pp = function(j$) {
6028
6699
  this.append(' )');
6029
6700
  };
6030
6701
 
6031
- PrettyPrinter.prototype.emitMap = function(map) {
6702
+ SinglePrettyPrintRun.prototype.emitMap = function(map) {
6032
6703
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
6033
6704
  this.append('Map');
6034
6705
  return;
@@ -6053,7 +6724,7 @@ getJasmineRequireObj().pp = function(j$) {
6053
6724
  this.append(' )');
6054
6725
  };
6055
6726
 
6056
- PrettyPrinter.prototype.emitObject = function(obj) {
6727
+ SinglePrettyPrintRun.prototype.emitObject = function(obj) {
6057
6728
  var ctor = obj.constructor,
6058
6729
  constructorName;
6059
6730
 
@@ -6089,7 +6760,7 @@ getJasmineRequireObj().pp = function(j$) {
6089
6760
  this.append(' })');
6090
6761
  };
6091
6762
 
6092
- PrettyPrinter.prototype.emitTypedArray = function(arr) {
6763
+ SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
6093
6764
  var constructorName = j$.fnNameFor(arr.constructor),
6094
6765
  limitedArray = Array.prototype.slice.call(
6095
6766
  arr,
@@ -6105,7 +6776,7 @@ getJasmineRequireObj().pp = function(j$) {
6105
6776
  this.append(constructorName + ' [ ' + itemsString + ' ]');
6106
6777
  };
6107
6778
 
6108
- PrettyPrinter.prototype.emitDomElement = function(el) {
6779
+ SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
6109
6780
  var tagName = el.tagName.toLowerCase(),
6110
6781
  attrs = el.attributes,
6111
6782
  i,
@@ -6131,7 +6802,11 @@ getJasmineRequireObj().pp = function(j$) {
6131
6802
  this.append(out);
6132
6803
  };
6133
6804
 
6134
- PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
6805
+ SinglePrettyPrintRun.prototype.formatProperty = function(
6806
+ obj,
6807
+ property,
6808
+ isGetter
6809
+ ) {
6135
6810
  this.append(property);
6136
6811
  this.append(': ');
6137
6812
  if (isGetter) {
@@ -6141,7 +6816,7 @@ getJasmineRequireObj().pp = function(j$) {
6141
6816
  }
6142
6817
  };
6143
6818
 
6144
- PrettyPrinter.prototype.append = function(value) {
6819
+ SinglePrettyPrintRun.prototype.append = function(value) {
6145
6820
  // This check protects us from the rare case where an object has overriden
6146
6821
  // `toString()` with an invalid implementation (returning a non-string).
6147
6822
  if (typeof value !== 'string') {
@@ -6205,10 +6880,33 @@ getJasmineRequireObj().pp = function(j$) {
6205
6880
 
6206
6881
  return extraKeys;
6207
6882
  }
6208
- return function(value) {
6209
- var prettyPrinter = new PrettyPrinter();
6210
- prettyPrinter.format(value);
6211
- return prettyPrinter.stringParts.join('');
6883
+
6884
+ function customFormat(value, customObjectFormatters) {
6885
+ var i, result;
6886
+
6887
+ for (i = 0; i < customObjectFormatters.length; i++) {
6888
+ result = customObjectFormatters[i](value);
6889
+
6890
+ if (result !== undefined) {
6891
+ return result;
6892
+ }
6893
+ }
6894
+ }
6895
+
6896
+ return function(customObjectFormatters) {
6897
+ customObjectFormatters = customObjectFormatters || [];
6898
+
6899
+ var pp = function(value) {
6900
+ var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp);
6901
+ prettyPrinter.format(value);
6902
+ return prettyPrinter.stringParts.join('');
6903
+ };
6904
+
6905
+ pp.customFormat_ = function(value) {
6906
+ return customFormat(value, customObjectFormatters);
6907
+ };
6908
+
6909
+ return pp;
6212
6910
  };
6213
6911
  };
6214
6912
 
@@ -6563,6 +7261,9 @@ getJasmineRequireObj().interface = function(jasmine, env) {
6563
7261
  * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
6564
7262
  *
6565
7263
  * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
7264
+ * The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the
7265
+ * spec more readable by connecting the function name `it` and the argument `description` as a
7266
+ * complete sentence.
6566
7267
  * @name it
6567
7268
  * @since 1.3.0
6568
7269
  * @function
@@ -6668,6 +7369,30 @@ getJasmineRequireObj().interface = function(jasmine, env) {
6668
7369
  return env.afterAll.apply(env, arguments);
6669
7370
  },
6670
7371
 
7372
+ /**
7373
+ * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult}
7374
+ * @name setSpecProperty
7375
+ * @since 3.6.0
7376
+ * @function
7377
+ * @param {String} key The name of the property
7378
+ * @param {*} value The value of the property
7379
+ */
7380
+ setSpecProperty: function(key, value) {
7381
+ return env.setSpecProperty(key, value);
7382
+ },
7383
+
7384
+ /**
7385
+ * Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult}
7386
+ * @name setSuiteProperty
7387
+ * @since 3.6.0
7388
+ * @function
7389
+ * @param {String} key The name of the property
7390
+ * @param {*} value The value of the property
7391
+ */
7392
+ setSuiteProperty: function(key, value) {
7393
+ return env.setSuiteProperty(key, value);
7394
+ },
7395
+
6671
7396
  /**
6672
7397
  * Create an expectation for a spec.
6673
7398
  * @name expect
@@ -6819,6 +7544,20 @@ getJasmineRequireObj().interface = function(jasmine, env) {
6819
7544
  return env.addAsyncMatchers(matchers);
6820
7545
  };
6821
7546
 
7547
+ /**
7548
+ * Add a custom object formatter for the current scope of specs.
7549
+ *
7550
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
7551
+ * @name jasmine.addCustomObjectFormatter
7552
+ * @since 3.6.0
7553
+ * @function
7554
+ * @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise.
7555
+ * @see custom_object_formatter
7556
+ */
7557
+ jasmine.addCustomObjectFormatter = function(formatter) {
7558
+ return env.addCustomObjectFormatter(formatter);
7559
+ };
7560
+
6822
7561
  /**
6823
7562
  * Get the currently booted mock {Clock} for this Jasmine environment.
6824
7563
  * @name jasmine.clock
@@ -6899,6 +7638,11 @@ getJasmineRequireObj().Spy = function(j$) {
6899
7638
  };
6900
7639
  })();
6901
7640
 
7641
+ var matchersUtil = new j$.MatchersUtil({
7642
+ customTesters: [],
7643
+ pp: j$.makePrettyPrinter()
7644
+ });
7645
+
6902
7646
  /**
6903
7647
  * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
6904
7648
  * @constructor
@@ -6912,8 +7656,8 @@ getJasmineRequireObj().Spy = function(j$) {
6912
7656
  getPromise
6913
7657
  ) {
6914
7658
  var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
6915
- wrapper = makeFunc(numArgs, function() {
6916
- return spy.apply(this, Array.prototype.slice.call(arguments));
7659
+ wrapper = makeFunc(numArgs, function(context, args, invokeNew) {
7660
+ return spy(context, args, invokeNew);
6917
7661
  }),
6918
7662
  strategyDispatcher = new SpyStrategyDispatcher({
6919
7663
  name: name,
@@ -6925,7 +7669,7 @@ getJasmineRequireObj().Spy = function(j$) {
6925
7669
  getPromise: getPromise
6926
7670
  }),
6927
7671
  callTracker = new j$.CallTracker(),
6928
- spy = function() {
7672
+ spy = function(context, args, invokeNew) {
6929
7673
  /**
6930
7674
  * @name Spy.callData
6931
7675
  * @property {object} object - `this` context for the invocation.
@@ -6933,13 +7677,13 @@ getJasmineRequireObj().Spy = function(j$) {
6933
7677
  * @property {Array} args - The arguments passed for this invocation.
6934
7678
  */
6935
7679
  var callData = {
6936
- object: this,
7680
+ object: context,
6937
7681
  invocationOrder: nextOrder(),
6938
- args: Array.prototype.slice.apply(arguments)
7682
+ args: Array.prototype.slice.apply(args)
6939
7683
  };
6940
7684
 
6941
7685
  callTracker.track(callData);
6942
- var returnValue = strategyDispatcher.exec(this, arguments);
7686
+ var returnValue = strategyDispatcher.exec(context, args, invokeNew);
6943
7687
  callData.returnValue = returnValue;
6944
7688
 
6945
7689
  return returnValue;
@@ -6948,44 +7692,44 @@ getJasmineRequireObj().Spy = function(j$) {
6948
7692
  function makeFunc(length, fn) {
6949
7693
  switch (length) {
6950
7694
  case 1:
6951
- return function(a) {
6952
- return fn.apply(this, arguments);
7695
+ return function wrap1(a) {
7696
+ return fn(this, arguments, this instanceof wrap1);
6953
7697
  };
6954
7698
  case 2:
6955
- return function(a, b) {
6956
- return fn.apply(this, arguments);
7699
+ return function wrap2(a, b) {
7700
+ return fn(this, arguments, this instanceof wrap2);
6957
7701
  };
6958
7702
  case 3:
6959
- return function(a, b, c) {
6960
- return fn.apply(this, arguments);
7703
+ return function wrap3(a, b, c) {
7704
+ return fn(this, arguments, this instanceof wrap3);
6961
7705
  };
6962
7706
  case 4:
6963
- return function(a, b, c, d) {
6964
- return fn.apply(this, arguments);
7707
+ return function wrap4(a, b, c, d) {
7708
+ return fn(this, arguments, this instanceof wrap4);
6965
7709
  };
6966
7710
  case 5:
6967
- return function(a, b, c, d, e) {
6968
- return fn.apply(this, arguments);
7711
+ return function wrap5(a, b, c, d, e) {
7712
+ return fn(this, arguments, this instanceof wrap5);
6969
7713
  };
6970
7714
  case 6:
6971
- return function(a, b, c, d, e, f) {
6972
- return fn.apply(this, arguments);
7715
+ return function wrap6(a, b, c, d, e, f) {
7716
+ return fn(this, arguments, this instanceof wrap6);
6973
7717
  };
6974
7718
  case 7:
6975
- return function(a, b, c, d, e, f, g) {
6976
- return fn.apply(this, arguments);
7719
+ return function wrap7(a, b, c, d, e, f, g) {
7720
+ return fn(this, arguments, this instanceof wrap7);
6977
7721
  };
6978
7722
  case 8:
6979
- return function(a, b, c, d, e, f, g, h) {
6980
- return fn.apply(this, arguments);
7723
+ return function wrap8(a, b, c, d, e, f, g, h) {
7724
+ return fn(this, arguments, this instanceof wrap8);
6981
7725
  };
6982
7726
  case 9:
6983
- return function(a, b, c, d, e, f, g, h, i) {
6984
- return fn.apply(this, arguments);
7727
+ return function wrap9(a, b, c, d, e, f, g, h, i) {
7728
+ return fn(this, arguments, this instanceof wrap9);
6985
7729
  };
6986
7730
  default:
6987
- return function() {
6988
- return fn.apply(this, arguments);
7731
+ return function wrap() {
7732
+ return fn(this, arguments, this instanceof wrap);
6989
7733
  };
6990
7734
  }
6991
7735
  }
@@ -7042,7 +7786,7 @@ getJasmineRequireObj().Spy = function(j$) {
7042
7786
 
7043
7787
  this.and = baseStrategy;
7044
7788
 
7045
- this.exec = function(spy, args) {
7789
+ this.exec = function(spy, args, invokeNew) {
7046
7790
  var strategy = argsStrategies.get(args);
7047
7791
 
7048
7792
  if (!strategy) {
@@ -7059,7 +7803,7 @@ getJasmineRequireObj().Spy = function(j$) {
7059
7803
  }
7060
7804
  }
7061
7805
 
7062
- return strategy.exec(spy, args);
7806
+ return strategy.exec(spy, args, invokeNew);
7063
7807
  };
7064
7808
 
7065
7809
  this.withArgs = function() {
@@ -7094,7 +7838,7 @@ getJasmineRequireObj().Spy = function(j$) {
7094
7838
  var i;
7095
7839
 
7096
7840
  for (i = 0; i < this.strategies.length; i++) {
7097
- if (j$.matchersUtil.equals(args, this.strategies[i].args)) {
7841
+ if (matchersUtil.equals(args, this.strategies[i].args)) {
7098
7842
  return this.strategies[i].strategy;
7099
7843
  }
7100
7844
  }
@@ -7492,8 +8236,13 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
7492
8236
  * @since 2.0.0
7493
8237
  * @function
7494
8238
  */
7495
- SpyStrategy.prototype.exec = function(context, args) {
7496
- return this.plan.apply(context, args);
8239
+ SpyStrategy.prototype.exec = function(context, args, invokeNew) {
8240
+ var contextArgs = [context].concat(
8241
+ args ? Array.prototype.slice.call(args) : []
8242
+ );
8243
+ var target = this.plan.bind.apply(this.plan, contextArgs);
8244
+
8245
+ return invokeNew ? new target() : target();
7497
8246
  };
7498
8247
 
7499
8248
  /**
@@ -7541,10 +8290,10 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
7541
8290
  * @name SpyStrategy#throwError
7542
8291
  * @since 2.0.0
7543
8292
  * @function
7544
- * @param {Error|String} something Thing to throw
8293
+ * @param {Error|Object|String} something Thing to throw
7545
8294
  */
7546
8295
  SpyStrategy.prototype.throwError = function(something) {
7547
- var error = something instanceof Error ? something : new Error(something);
8296
+ var error = j$.isString_(something) ? new Error(something) : something;
7548
8297
  this.plan = function() {
7549
8298
  throw error;
7550
8299
  };
@@ -7692,7 +8441,7 @@ getJasmineRequireObj().StackTrace = function(j$) {
7692
8441
  }
7693
8442
 
7694
8443
  function messagePrefixLength(message, stackLines) {
7695
- if (!stackLines[0].match(/^Error/)) {
8444
+ if (!stackLines[0].match(/^\w*Error/)) {
7696
8445
  return 0;
7697
8446
  }
7698
8447
 
@@ -7727,7 +8476,7 @@ getJasmineRequireObj().Suite = function(j$) {
7727
8476
  this.beforeAllFns = [];
7728
8477
  this.afterAllFns = [];
7729
8478
 
7730
- this.timer = attrs.timer || j$.noopTimer;
8479
+ this.timer = attrs.timer || new j$.Timer();
7731
8480
 
7732
8481
  this.children = [];
7733
8482
 
@@ -7740,6 +8489,7 @@ getJasmineRequireObj().Suite = function(j$) {
7740
8489
  * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
7741
8490
  * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
7742
8491
  * @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
8492
+ * @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
7743
8493
  */
7744
8494
  this.result = {
7745
8495
  id: this.id,
@@ -7747,10 +8497,16 @@ getJasmineRequireObj().Suite = function(j$) {
7747
8497
  fullName: this.getFullName(),
7748
8498
  failedExpectations: [],
7749
8499
  deprecationWarnings: [],
7750
- duration: null
8500
+ duration: null,
8501
+ properties: null
7751
8502
  };
7752
8503
  }
7753
8504
 
8505
+ Suite.prototype.setSuiteProperty = function(key, value) {
8506
+ this.result.properties = this.result.properties || {};
8507
+ this.result.properties[key] = value;
8508
+ };
8509
+
7754
8510
  Suite.prototype.expect = function(actual) {
7755
8511
  return this.expectationFactory(actual, this);
7756
8512
  };
@@ -7930,15 +8686,6 @@ getJasmineRequireObj().Timer = function() {
7930
8686
  return Timer;
7931
8687
  };
7932
8688
 
7933
- getJasmineRequireObj().noopTimer = function() {
7934
- return {
7935
- start: function() {},
7936
- elapsed: function() {
7937
- return 0;
7938
- }
7939
- };
7940
- };
7941
-
7942
8689
  getJasmineRequireObj().TreeProcessor = function() {
7943
8690
  function TreeProcessor(attrs) {
7944
8691
  var tree = attrs.tree,
@@ -8214,5 +8961,5 @@ getJasmineRequireObj().UserContext = function(j$) {
8214
8961
  };
8215
8962
 
8216
8963
  getJasmineRequireObj().version = function() {
8217
- return '3.5.0';
8964
+ return '3.6.0';
8218
8965
  };