jasmine-core 2.99.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jasmine-core/boot.js +7 -6
  3. data/lib/jasmine-core/boot/boot.js +7 -6
  4. data/lib/jasmine-core/boot/node_boot.js +0 -3
  5. data/lib/jasmine-core/jasmine-html.js +228 -137
  6. data/lib/jasmine-core/jasmine.css +11 -5
  7. data/lib/jasmine-core/jasmine.js +1046 -608
  8. data/lib/jasmine-core/node_boot.js +0 -3
  9. data/lib/jasmine-core/spec/core/CallTrackerSpec.js +130 -0
  10. data/lib/jasmine-core/spec/core/ClearStackSpec.js +137 -0
  11. data/lib/jasmine-core/spec/core/ClockSpec.js +710 -0
  12. data/lib/jasmine-core/spec/core/DelayedFunctionSchedulerSpec.js +286 -0
  13. data/lib/jasmine-core/spec/core/EnvSpec.js +200 -0
  14. data/lib/jasmine-core/spec/core/ExceptionFormatterSpec.js +120 -0
  15. data/lib/jasmine-core/spec/core/ExceptionsSpec.js +46 -0
  16. data/lib/jasmine-core/spec/core/ExpectationResultSpec.js +61 -0
  17. data/lib/jasmine-core/spec/core/ExpectationSpec.js +434 -0
  18. data/lib/jasmine-core/spec/core/GlobalErrorsSpec.js +110 -0
  19. data/lib/jasmine-core/spec/core/JsApiReporterSpec.js +259 -0
  20. data/lib/jasmine-core/spec/core/MockDateSpec.js +200 -0
  21. data/lib/jasmine-core/spec/core/PrettyPrintSpec.js +332 -0
  22. data/lib/jasmine-core/spec/core/QueueRunnerSpec.js +670 -0
  23. data/lib/jasmine-core/spec/core/ReportDispatcherSpec.js +140 -0
  24. data/lib/jasmine-core/spec/core/SpecSpec.js +407 -0
  25. data/lib/jasmine-core/spec/core/SpyRegistrySpec.js +364 -0
  26. data/lib/jasmine-core/spec/core/SpySpec.js +177 -0
  27. data/lib/jasmine-core/spec/core/SpyStrategySpec.js +202 -0
  28. data/lib/jasmine-core/spec/core/StackTraceSpec.js +166 -0
  29. data/lib/jasmine-core/spec/core/SuiteSpec.js +123 -0
  30. data/lib/jasmine-core/spec/core/TimerSpec.js +31 -0
  31. data/lib/jasmine-core/spec/core/TreeProcessorSpec.js +794 -0
  32. data/lib/jasmine-core/spec/core/UserContextSpec.js +54 -0
  33. data/lib/jasmine-core/spec/core/UtilSpec.js +105 -0
  34. data/lib/jasmine-core/spec/core/asymmetric_equality/AnySpec.js +91 -0
  35. data/lib/jasmine-core/spec/core/asymmetric_equality/AnythingSpec.js +76 -0
  36. data/lib/jasmine-core/spec/core/asymmetric_equality/ArrayContainingSpec.js +52 -0
  37. data/lib/jasmine-core/spec/core/asymmetric_equality/ArrayWithExactContentsSpec.js +47 -0
  38. data/lib/jasmine-core/spec/core/asymmetric_equality/ObjectContainingSpec.js +99 -0
  39. data/lib/jasmine-core/spec/core/asymmetric_equality/StringMatchingSpec.js +27 -0
  40. data/lib/jasmine-core/spec/core/formatErrorMsgSpec.js +13 -0
  41. data/lib/jasmine-core/spec/core/integration/CustomMatchersSpec.js +200 -0
  42. data/lib/jasmine-core/spec/core/integration/CustomSpyStrategiesSpec.js +138 -0
  43. data/lib/jasmine-core/spec/core/integration/EnvSpec.js +2344 -0
  44. data/lib/jasmine-core/spec/core/integration/SpecRunningSpec.js +976 -0
  45. data/lib/jasmine-core/spec/core/matchers/DiffBuilderSpec.js +47 -0
  46. data/lib/jasmine-core/spec/core/matchers/NullDiffBuilderSpec.js +13 -0
  47. data/lib/jasmine-core/spec/core/matchers/ObjectPathSpec.js +43 -0
  48. data/lib/jasmine-core/spec/core/matchers/matchersUtilSpec.js +645 -0
  49. data/lib/jasmine-core/spec/core/matchers/nothingSpec.js +8 -0
  50. data/lib/jasmine-core/spec/core/matchers/toBeCloseToSpec.js +93 -0
  51. data/lib/jasmine-core/spec/core/matchers/toBeDefinedSpec.js +18 -0
  52. data/lib/jasmine-core/spec/core/matchers/toBeFalsySpec.js +38 -0
  53. data/lib/jasmine-core/spec/core/matchers/toBeGreaterThanOrEqualSpec.js +29 -0
  54. data/lib/jasmine-core/spec/core/matchers/toBeGreaterThanSpec.js +20 -0
  55. data/lib/jasmine-core/spec/core/matchers/toBeLessThanOrEqualSpec.js +29 -0
  56. data/lib/jasmine-core/spec/core/matchers/toBeLessThanSpec.js +20 -0
  57. data/lib/jasmine-core/spec/core/matchers/toBeNaNSpec.js +37 -0
  58. data/lib/jasmine-core/spec/core/matchers/toBeNegativeInfinitySpec.js +31 -0
  59. data/lib/jasmine-core/spec/core/matchers/toBeNullSpec.js +17 -0
  60. data/lib/jasmine-core/spec/core/matchers/toBePositiveInfinitySpec.js +31 -0
  61. data/lib/jasmine-core/spec/core/matchers/toBeSpec.js +17 -0
  62. data/lib/jasmine-core/spec/core/matchers/toBeTruthySpec.js +38 -0
  63. data/lib/jasmine-core/spec/core/matchers/toBeUndefinedSpec.js +18 -0
  64. data/lib/jasmine-core/spec/core/matchers/toContainSpec.js +26 -0
  65. data/lib/jasmine-core/spec/core/matchers/toEqualSpec.js +785 -0
  66. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledBeforeSpec.js +99 -0
  67. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledSpec.js +47 -0
  68. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledTimesSpec.js +86 -0
  69. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledWithSpec.js +67 -0
  70. data/lib/jasmine-core/spec/core/matchers/toMatchSpec.js +43 -0
  71. data/lib/jasmine-core/spec/core/matchers/toThrowErrorSpec.js +315 -0
  72. data/lib/jasmine-core/spec/core/matchers/toThrowMatchingSpec.js +73 -0
  73. data/lib/jasmine-core/spec/core/matchers/toThrowSpec.js +100 -0
  74. data/lib/jasmine-core/spec/helpers/BrowserFlags.js +15 -0
  75. data/lib/jasmine-core/spec/helpers/asyncAwait.js +27 -0
  76. data/lib/jasmine-core/spec/helpers/checkForMap.js +37 -0
  77. data/lib/jasmine-core/spec/helpers/checkForSet.js +41 -0
  78. data/lib/jasmine-core/spec/helpers/checkForSymbol.js +28 -0
  79. data/lib/jasmine-core/spec/helpers/checkForTypedArrays.js +20 -0
  80. data/lib/jasmine-core/spec/helpers/defineJasmineUnderTest.js +6 -0
  81. data/lib/jasmine-core/spec/helpers/integrationMatchers.js +43 -0
  82. data/lib/jasmine-core/spec/helpers/nodeDefineJasmineUnderTest.js +30 -0
  83. data/lib/jasmine-core/spec/html/HtmlReporterSpec.js +1261 -0
  84. data/lib/jasmine-core/spec/html/HtmlSpecFilterSpec.js +18 -0
  85. data/lib/jasmine-core/spec/html/MatchersHtmlSpec.js +37 -0
  86. data/lib/jasmine-core/spec/html/PrettyPrintHtmlSpec.js +27 -0
  87. data/lib/jasmine-core/spec/html/QueryStringSpec.js +72 -0
  88. data/lib/jasmine-core/spec/html/ResultsNodeSpec.js +62 -0
  89. data/lib/jasmine-core/spec/html/SpyRegistryHtmlSpec.js +39 -0
  90. data/lib/jasmine-core/spec/html/matchers/toHaveClassSpec.js +48 -0
  91. data/lib/jasmine-core/spec/npmPackage/npmPackageSpec.js +101 -0
  92. data/lib/jasmine-core/spec/performance/large_object_test.js +36 -0
  93. data/lib/jasmine-core/spec/performance/performance_test.js +10 -0
  94. data/lib/jasmine-core/version.rb +1 -1
  95. metadata +88 -4
  96. data/lib/console/console.js +0 -190
@@ -18,8 +18,8 @@ body { overflow-y: scroll; }
18
18
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed:before { color: #007069; content: "\02022"; }
19
19
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed { line-height: 9px; }
20
20
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; }
21
- .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-disabled { font-size: 14px; }
22
- .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-disabled:before { color: #bababa; content: "\02022"; }
21
+ .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded { font-size: 14px; }
22
+ .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-excluded:before { color: #bababa; content: "\02022"; }
23
23
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { line-height: 17px; }
24
24
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { color: #ba9d37; content: "*"; }
25
25
  .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { font-size: 14px; }
@@ -29,11 +29,17 @@ body { overflow-y: scroll; }
29
29
  .jasmine_html-reporter .jasmine-run-options .jasmine-payload { position: absolute; display: none; right: -1px; border: 1px solid #8a4182; background-color: #eee; white-space: nowrap; padding: 4px 8px; }
30
30
  .jasmine_html-reporter .jasmine-run-options .jasmine-payload.jasmine-open { display: block; }
31
31
  .jasmine_html-reporter .jasmine-bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
32
- .jasmine_html-reporter .jasmine-bar.jasmine-failed { background-color: #ca3a11; }
32
+ .jasmine_html-reporter .jasmine-bar.jasmine-failed, .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; border-bottom: 1px solid #eee; }
33
33
  .jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; }
34
+ .jasmine_html-reporter .jasmine-bar.jasmine-incomplete { background-color: #bababa; }
34
35
  .jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; }
36
+ <<<<<<< HEAD
37
+ ||||||| merged common ancestors
38
+ .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; }
39
+ =======
35
40
  .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; }
36
41
  .jasmine_html-reporter .jasmine-bar.jasmine-warning { background-color: #ba9d37; color: #333; }
42
+ >>>>>>> master
37
43
  .jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; }
38
44
  .jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; }
39
45
  .jasmine_html-reporter .jasmine-bar a { color: white; }
@@ -47,12 +53,12 @@ body { overflow-y: scroll; }
47
53
  .jasmine_html-reporter .jasmine-summary li.jasmine-failed a { color: #ca3a11; }
48
54
  .jasmine_html-reporter .jasmine-summary li.jasmine-empty a { color: #ba9d37; }
49
55
  .jasmine_html-reporter .jasmine-summary li.jasmine-pending a { color: #ba9d37; }
50
- .jasmine_html-reporter .jasmine-summary li.jasmine-disabled a { color: #bababa; }
56
+ .jasmine_html-reporter .jasmine-summary li.jasmine-excluded a { color: #bababa; }
51
57
  .jasmine_html-reporter .jasmine-description + .jasmine-suite { margin-top: 0; }
52
58
  .jasmine_html-reporter .jasmine-suite { margin-top: 14px; }
53
59
  .jasmine_html-reporter .jasmine-suite a { color: #333; }
54
60
  .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { margin-bottom: 28px; }
55
- .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; }
61
+ .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; color: white; }
56
62
  .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { color: white; }
57
63
  .jasmine_html-reporter .jasmine-result-message { padding-top: 14px; color: #333; white-space: pre; }
58
64
  .jasmine_html-reporter .jasmine-result-message span.jasmine-result { display: block; }
@@ -56,7 +56,8 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
56
56
  j$.Clock = jRequire.Clock();
57
57
  j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
58
58
  j$.Env = jRequire.Env(j$);
59
- j$.ExceptionFormatter = jRequire.ExceptionFormatter();
59
+ j$.StackTrace = jRequire.StackTrace(j$);
60
+ j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
60
61
  j$.Expectation = jRequire.Expectation();
61
62
  j$.buildExpectationResult = jRequire.buildExpectationResult();
62
63
  j$.JsApiReporter = jRequire.JsApiReporter();
@@ -69,6 +70,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
69
70
  j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
70
71
  j$.Spec = jRequire.Spec(j$);
71
72
  j$.Spy = jRequire.Spy(j$);
73
+ j$.SpyFactory = jRequire.SpyFactory(j$);
72
74
  j$.SpyRegistry = jRequire.SpyRegistry(j$);
73
75
  j$.SpyStrategy = jRequire.SpyStrategy(j$);
74
76
  j$.StringMatching = jRequire.StringMatching(j$);
@@ -116,7 +118,8 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
116
118
  'toHaveBeenCalledWith',
117
119
  'toMatch',
118
120
  'toThrow',
119
- 'toThrowError'
121
+ 'toThrowError',
122
+ 'toThrowMatching',
120
123
  ],
121
124
  matchers = {};
122
125
 
@@ -215,6 +218,17 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
215
218
  return j$.getType_(value) === '[object ' + typeName + ']';
216
219
  };
217
220
 
221
+ j$.isError_ = function(value) {
222
+ if (value instanceof Error) {
223
+ return true;
224
+ }
225
+ if (value && value.constructor && value.constructor.constructor &&
226
+ (value instanceof (value.constructor.constructor('return this')()).Error)) {
227
+ return true;
228
+ }
229
+ return false;
230
+ };
231
+
218
232
  j$.getType_ = function(value) {
219
233
  return Object.prototype.toString.apply(value);
220
234
  };
@@ -311,18 +325,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
311
325
  return new j$.ArrayWithExactContents(sample);
312
326
  };
313
327
 
314
- /**
315
- * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
316
- * @name jasmine.createSpy
317
- * @function
318
- * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
319
- * @param {Function} [originalFn] - Function to act as the real implementation.
320
- * @return {Spy}
321
- */
322
- j$.createSpy = function(name, originalFn) {
323
- return j$.Spy(name, originalFn);
324
- };
325
-
326
328
  j$.isSpy = function(putativeSpy) {
327
329
  if (!putativeSpy) {
328
330
  return false;
@@ -330,47 +332,6 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
330
332
  return putativeSpy.and instanceof j$.SpyStrategy &&
331
333
  putativeSpy.calls instanceof j$.CallTracker;
332
334
  };
333
-
334
- /**
335
- * Create an object with multiple {@link Spy}s as its members.
336
- * @name jasmine.createSpyObj
337
- * @function
338
- * @param {String} [baseName] - Base name for the spies in the object.
339
- * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
340
- * @return {Object}
341
- */
342
- j$.createSpyObj = function(baseName, methodNames) {
343
- var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
344
-
345
- if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
346
- methodNames = baseName;
347
- baseName = 'unknown';
348
- }
349
-
350
- var obj = {};
351
- var spiesWereSet = false;
352
-
353
- if (j$.isArray_(methodNames)) {
354
- for (var i = 0; i < methodNames.length; i++) {
355
- obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
356
- spiesWereSet = true;
357
- }
358
- } else if (j$.isObject_(methodNames)) {
359
- for (var key in methodNames) {
360
- if (methodNames.hasOwnProperty(key)) {
361
- obj[key] = j$.createSpy(baseName + '.' + key);
362
- obj[key].and.returnValue(methodNames[key]);
363
- spiesWereSet = true;
364
- }
365
- }
366
- }
367
-
368
- if (!spiesWereSet) {
369
- throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
370
- }
371
-
372
- return obj;
373
- };
374
335
  };
375
336
 
376
337
  getJasmineRequireObj().util = function(j$) {
@@ -475,6 +436,54 @@ getJasmineRequireObj().util = function(j$) {
475
436
  return Object.prototype.hasOwnProperty.call(obj, key);
476
437
  };
477
438
 
439
+ function anyMatch(pattern, lines) {
440
+ var i;
441
+
442
+ for (i = 0; i < lines.length; i++) {
443
+ if (lines[i].match(pattern)) {
444
+ return true;
445
+ }
446
+ }
447
+
448
+ return false;
449
+ }
450
+
451
+ function errorWithStack() {
452
+ // Don't throw and catch if we don't have to, because it makes it harder
453
+ // for users to debug their code with exception breakpoints.
454
+ var error = new Error();
455
+
456
+ if (error.stack) {
457
+ return error;
458
+ }
459
+
460
+ // But some browsers (e.g. Phantom) only provide a stack trace if we throw.
461
+ try {
462
+ throw new Error();
463
+ } catch (e) {
464
+ return e;
465
+ }
466
+ }
467
+
468
+ function callerFile() {
469
+ var trace = new j$.StackTrace(errorWithStack().stack);
470
+ return trace.frames[2].file;
471
+ }
472
+
473
+ util.jasmineFile = (function() {
474
+ var result;
475
+
476
+ return function() {
477
+ var trace;
478
+
479
+ if (!result) {
480
+ result = callerFile();
481
+ }
482
+
483
+ return result;
484
+ };
485
+ }());
486
+
478
487
  return util;
479
488
  };
480
489
 
@@ -537,10 +546,22 @@ getJasmineRequireObj().Spec = function(j$) {
537
546
  return this.expectationFactory(actual, this);
538
547
  };
539
548
 
540
- Spec.prototype.execute = function(onComplete, enabled) {
549
+ Spec.prototype.execute = function(onComplete, excluded) {
541
550
  var self = this;
542
551
 
543
- this.onStart(this);
552
+ var onStart = {
553
+ fn: function(done) {
554
+ self.onStart(self, done);
555
+ }
556
+ };
557
+
558
+ var complete = {
559
+ fn: function(done) {
560
+ self.queueableFn.fn = null;
561
+ self.result.status = self.status(excluded);
562
+ self.resultCallback(self.result, done);
563
+ }
564
+ };
544
565
 
545
566
  var fns = this.beforeAndAfterFns();
546
567
  var regularFns = fns.befores.concat(this.queueableFn);
@@ -549,27 +570,24 @@ getJasmineRequireObj().Spec = function(j$) {
549
570
  isLeaf: true,
550
571
  queueableFns: regularFns,
551
572
  cleanupFns: fns.afters,
552
- onException: function() { self.onException.apply(self, arguments); },
553
- onComplete: complete,
573
+ onException: function () {
574
+ self.onException.apply(self, arguments);
575
+ },
576
+ onComplete: function() {
577
+ onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed'));
578
+ },
554
579
  userContext: this.userContext()
555
580
  };
556
581
 
557
- if (!this.isExecutable() || this.markedPending || enabled === false) {
582
+ if (this.markedPending || excluded === true) {
558
583
  runnerConfig.queueableFns = [];
559
584
  runnerConfig.cleanupFns = [];
560
- runnerConfig.onComplete = function() { complete(enabled); };
561
585
  }
562
586
 
563
- this.queueRunnerFactory(runnerConfig);
564
-
565
- function complete(enabledAgain) {
566
- self.result.status = self.status(enabledAgain);
567
- self.resultCallback(self.result);
587
+ runnerConfig.queueableFns.unshift(onStart);
588
+ runnerConfig.cleanupFns.push(complete);
568
589
 
569
- if (onComplete) {
570
- onComplete();
571
- }
572
- }
590
+ this.queueRunnerFactory(runnerConfig);
573
591
  };
574
592
 
575
593
  Spec.prototype.onException = function onException(e) {
@@ -591,10 +609,6 @@ getJasmineRequireObj().Spec = function(j$) {
591
609
  }, true);
592
610
  };
593
611
 
594
- Spec.prototype.disable = function() {
595
- this.disabled = true;
596
- };
597
-
598
612
  Spec.prototype.pend = function(message) {
599
613
  this.markedPending = true;
600
614
  if (message) {
@@ -607,9 +621,9 @@ getJasmineRequireObj().Spec = function(j$) {
607
621
  return this.result;
608
622
  };
609
623
 
610
- Spec.prototype.status = function(enabled) {
611
- if (this.disabled || enabled === false) {
612
- return 'disabled';
624
+ Spec.prototype.status = function(excluded) {
625
+ if (excluded === true) {
626
+ return 'excluded';
613
627
  }
614
628
 
615
629
  if (this.markedPending) {
@@ -623,10 +637,6 @@ getJasmineRequireObj().Spec = function(j$) {
623
637
  }
624
638
  };
625
639
 
626
- Spec.prototype.isExecutable = function() {
627
- return !this.disabled;
628
- };
629
-
630
640
  Spec.prototype.getFullName = function() {
631
641
  return this.getSpecName(this);
632
642
  };
@@ -716,12 +726,8 @@ getJasmineRequireObj().Env = function(j$) {
716
726
  var self = this;
717
727
  var global = options.global || j$.getGlobal();
718
728
 
719
- var hasExecuted = false;
720
-
721
729
  var totalSpecsDefined = 0;
722
730
 
723
- var catchExceptions = true;
724
-
725
731
  var realSetTimeout = j$.getGlobal().setTimeout;
726
732
  var realClearTimeout = j$.getGlobal().clearTimeout;
727
733
  var clearStack = j$.getClearStack(j$.getGlobal());
@@ -733,8 +739,11 @@ getJasmineRequireObj().Env = function(j$) {
733
739
  var currentlyExecutingSuites = [];
734
740
  var currentDeclarationSuite = null;
735
741
  var throwOnExpectationFailure = false;
736
- var random = false;
742
+ var stopOnSpecFailure = false;
743
+ var random = true;
737
744
  var seed = null;
745
+ var handlingLoadErrors = true;
746
+ var hasFailures = false;
738
747
 
739
748
  var currentSuite = function() {
740
749
  return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
@@ -744,65 +753,29 @@ getJasmineRequireObj().Env = function(j$) {
744
753
  return currentSpec || currentSuite();
745
754
  };
746
755
 
747
- /**
748
- * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
749
- * @interface Reporter
750
- */
751
- var reporter = new j$.ReportDispatcher([
752
- /**
753
- * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
754
- * @function
755
- * @name Reporter#jasmineStarted
756
- * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
757
- */
758
- 'jasmineStarted',
759
- /**
760
- * When the entire suite has finished execution `jasmineDone` is called
761
- * @function
762
- * @name Reporter#jasmineDone
763
- * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
764
- */
765
- 'jasmineDone',
766
- /**
767
- * `suiteStarted` is invoked when a `describe` starts to run
768
- * @function
769
- * @name Reporter#suiteStarted
770
- * @param {SuiteResult} result Information about the individual {@link describe} being run
771
- */
772
- 'suiteStarted',
773
- /**
774
- * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
775
- *
776
- * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
777
- * @function
778
- * @name Reporter#suiteDone
779
- * @param {SuiteResult} result
780
- */
781
- 'suiteDone',
782
- /**
783
- * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
784
- * @function
785
- * @name Reporter#specStarted
786
- * @param {SpecResult} result Information about the individual {@link it} being run
787
- */
788
- 'specStarted',
789
- /**
790
- * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
791
- *
792
- * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
793
- * @function
794
- * @name Reporter#specDone
795
- * @param {SpecResult} result
796
- */
797
- 'specDone'
798
- ]);
799
-
800
756
  var globalErrors = new j$.GlobalErrors();
757
+ globalErrors.install();
758
+ globalErrors.pushListener(function(message, filename, lineno) {
759
+ topSuite.result.failedExpectations.push({
760
+ passed: false,
761
+ globalErrorType: 'load',
762
+ message: message,
763
+ filename: filename,
764
+ lineno: lineno
765
+ });
766
+ });
801
767
 
802
768
  this.specFilter = function() {
803
769
  return true;
804
770
  };
805
771
 
772
+ this.addSpyStrategy = function(name, fn) {
773
+ if(!currentRunnable()) {
774
+ throw new Error('Custom spy strategies must be added in a before function or a spec');
775
+ }
776
+ runnableResources[currentRunnable().id].customSpyStrategies[name] = fn;
777
+ };
778
+
806
779
  this.addCustomEqualityTester = function(tester) {
807
780
  if(!currentRunnable()) {
808
781
  throw new Error('Custom Equalities must be added in a before function or a spec');
@@ -847,7 +820,7 @@ getJasmineRequireObj().Env = function(j$) {
847
820
  };
848
821
 
849
822
  var defaultResourcesForRunnable = function(id, parentRunnableId) {
850
- var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
823
+ var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}};
851
824
 
852
825
  if(runnableResources[parentRunnableId]){
853
826
  resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
@@ -901,26 +874,9 @@ getJasmineRequireObj().Env = function(j$) {
901
874
  return buildExpectationResult(attrs);
902
875
  };
903
876
 
904
- // TODO: fix this naming, and here's where the value comes in
905
- this.catchExceptions = function(value) {
906
- catchExceptions = !!value;
907
- if (!catchExceptions) {
908
- this.deprecated('The catchExceptions option is deprecated and will be replaced with stopOnSpecFailure in Jasmine 3.0');
909
- }
910
- return catchExceptions;
911
- };
912
-
913
- this.catchingExceptions = function() {
914
- return catchExceptions;
915
- };
916
-
917
877
  var maximumSpecCallbackDepth = 20;
918
878
  var currentSpecCallbackDepth = 0;
919
879
 
920
- var catchException = function(e) {
921
- return j$.Spec.isPendingSpecException(e) || catchExceptions;
922
- };
923
-
924
880
  this.throwOnExpectationFailure = function(value) {
925
881
  throwOnExpectationFailure = !!value;
926
882
  };
@@ -929,6 +885,14 @@ getJasmineRequireObj().Env = function(j$) {
929
885
  return throwOnExpectationFailure;
930
886
  };
931
887
 
888
+ this.stopOnSpecFailure = function(value) {
889
+ stopOnSpecFailure = !!value;
890
+ };
891
+
892
+ this.stoppingOnSpecFailure = function() {
893
+ return stopOnSpecFailure;
894
+ };
895
+
932
896
  this.randomizeTests = function(value) {
933
897
  random = !!value;
934
898
  };
@@ -944,6 +908,13 @@ getJasmineRequireObj().Env = function(j$) {
944
908
  return seed;
945
909
  };
946
910
 
911
+ this.suppressLoadErrors = function() {
912
+ if (handlingLoadErrors) {
913
+ globalErrors.popListener();
914
+ }
915
+ handlingLoadErrors = false;
916
+ };
917
+
947
918
  this.deprecated = function(msg) {
948
919
  var runnable = currentRunnable() || topSuite;
949
920
  runnable.addDeprecationWarning(msg);
@@ -952,16 +923,24 @@ getJasmineRequireObj().Env = function(j$) {
952
923
  }
953
924
  };
954
925
 
955
- var queueRunnerFactory = function(options) {
956
- options.catchException = catchException;
926
+ var queueRunnerFactory = function(options, args) {
927
+ var failFast = false;
928
+ if (options.isLeaf) {
929
+ failFast = throwOnExpectationFailure;
930
+ } else if (!options.isReporter) {
931
+ failFast = stopOnSpecFailure;
932
+ }
957
933
  options.clearStack = options.clearStack || clearStack;
958
934
  options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
959
935
  options.fail = self.fail;
960
936
  options.globalErrors = globalErrors;
961
- options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
937
+ options.completeOnFirstError = failFast;
938
+ options.onException = options.onException || function(e) {
939
+ (currentRunnable() || topSuite).onException(e);
940
+ };
962
941
  options.deprecated = self.deprecated;
963
942
 
964
- new j$.QueueRunner(options).execute();
943
+ new j$.QueueRunner(options).execute(args);
965
944
  };
966
945
 
967
946
  var topSuite = new j$.Suite({
@@ -978,12 +957,62 @@ getJasmineRequireObj().Env = function(j$) {
978
957
  return topSuite;
979
958
  };
980
959
 
981
- this.execute = function(runnablesToRun) {
982
- if (hasExecuted) {
983
- this.deprecated('Executing the same Jasmine multiple times will no longer work in Jasmine 3.0');
984
- }
960
+ /**
961
+ * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
962
+ * @interface Reporter
963
+ */
964
+ var reporter = new j$.ReportDispatcher([
965
+ /**
966
+ * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
967
+ * @function
968
+ * @name Reporter#jasmineStarted
969
+ * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
970
+ */
971
+ 'jasmineStarted',
972
+ /**
973
+ * When the entire suite has finished execution `jasmineDone` is called
974
+ * @function
975
+ * @name Reporter#jasmineDone
976
+ * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
977
+ */
978
+ 'jasmineDone',
979
+ /**
980
+ * `suiteStarted` is invoked when a `describe` starts to run
981
+ * @function
982
+ * @name Reporter#suiteStarted
983
+ * @param {SuiteResult} result Information about the individual {@link describe} being run
984
+ */
985
+ 'suiteStarted',
986
+ /**
987
+ * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
988
+ *
989
+ * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
990
+ * @function
991
+ * @name Reporter#suiteDone
992
+ * @param {SuiteResult} result
993
+ */
994
+ 'suiteDone',
995
+ /**
996
+ * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
997
+ * @function
998
+ * @name Reporter#specStarted
999
+ * @param {SpecResult} result Information about the individual {@link it} being run
1000
+ */
1001
+ 'specStarted',
1002
+ /**
1003
+ * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
1004
+ *
1005
+ * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
1006
+ * @function
1007
+ * @name Reporter#specDone
1008
+ * @param {SpecResult} result
1009
+ */
1010
+ 'specDone'
1011
+ ], queueRunnerFactory);
985
1012
 
986
- hasExecuted = true;
1013
+ this.execute = function(runnablesToRun) {
1014
+ var self = this;
1015
+ this.suppressLoadErrors();
987
1016
 
988
1017
  if(!runnablesToRun) {
989
1018
  if (focusedRunnables.length) {
@@ -1002,24 +1031,30 @@ getJasmineRequireObj().Env = function(j$) {
1002
1031
  tree: topSuite,
1003
1032
  runnableIds: runnablesToRun,
1004
1033
  queueRunnerFactory: queueRunnerFactory,
1005
- nodeStart: function(suite) {
1034
+ nodeStart: function(suite, next) {
1006
1035
  currentlyExecutingSuites.push(suite);
1007
1036
  defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
1008
- reporter.suiteStarted(suite.result);
1037
+ reporter.suiteStarted(suite.result, next);
1009
1038
  },
1010
- nodeComplete: function(suite, result) {
1039
+ nodeComplete: function(suite, result, next) {
1011
1040
  if (suite !== currentSuite()) {
1012
1041
  throw new Error('Tried to complete the wrong suite');
1013
1042
  }
1014
1043
 
1015
- if (!suite.markedPending) {
1016
- clearResourcesForRunnable(suite.id);
1017
- }
1044
+ clearResourcesForRunnable(suite.id);
1018
1045
  currentlyExecutingSuites.pop();
1019
- reporter.suiteDone(result);
1046
+
1047
+ if (result.status === 'failed') {
1048
+ hasFailures = true;
1049
+ }
1050
+
1051
+ reporter.suiteDone(result, next);
1020
1052
  },
1021
1053
  orderChildren: function(node) {
1022
1054
  return order.sort(node.children);
1055
+ },
1056
+ excludeNode: function(spec) {
1057
+ return !self.specFilter(spec);
1023
1058
  }
1024
1059
  });
1025
1060
 
@@ -1036,27 +1071,42 @@ getJasmineRequireObj().Env = function(j$) {
1036
1071
  reporter.jasmineStarted({
1037
1072
  totalSpecsDefined: totalSpecsDefined,
1038
1073
  order: order
1039
- });
1074
+ }, function() {
1075
+ currentlyExecutingSuites.push(topSuite);
1040
1076
 
1041
- currentlyExecutingSuites.push(topSuite);
1042
-
1043
- globalErrors.install();
1044
- processor.execute(function() {
1045
- clearResourcesForRunnable(topSuite.id);
1046
- currentlyExecutingSuites.pop();
1047
- globalErrors.uninstall();
1077
+ processor.execute(function () {
1078
+ clearResourcesForRunnable(topSuite.id);
1079
+ currentlyExecutingSuites.pop();
1080
+ var overallStatus, incompleteReason;
1081
+
1082
+ if (hasFailures || topSuite.result.failedExpectations.length > 0) {
1083
+ overallStatus = 'failed';
1084
+ } else if (focusedRunnables.length > 0) {
1085
+ overallStatus = 'incomplete';
1086
+ incompleteReason = 'fit() or fdescribe() was found';
1087
+ } else if (totalSpecsDefined === 0) {
1088
+ overallStatus = 'incomplete';
1089
+ incompleteReason = 'No specs found';
1090
+ } else {
1091
+ overallStatus = 'passed';
1092
+ }
1048
1093
 
1049
- /**
1050
- * Information passed to the {@link Reporter#jasmineDone} event.
1051
- * @typedef JasmineDoneInfo
1052
- * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1053
- * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
1054
- * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
1055
- */
1056
- reporter.jasmineDone({
1057
- order: order,
1058
- failedExpectations: topSuite.result.failedExpectations,
1059
- deprecationWarnings: topSuite.result.deprecationWarnings
1094
+ /**
1095
+ * Information passed to the {@link Reporter#jasmineDone} event.
1096
+ * @typedef JasmineDoneInfo
1097
+ * @property {OverallStatus} - The overall result of the sute: 'passed', 'failed', or 'incomplete'.
1098
+ * @property {IncompleteReason} - Explanation of why the suite was incimplete.
1099
+ * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1100
+ * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
1101
+ * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
1102
+ */
1103
+ reporter.jasmineDone({
1104
+ overallStatus: overallStatus,
1105
+ incompleteReason: incompleteReason,
1106
+ order: order,
1107
+ failedExpectations: topSuite.result.failedExpectations,
1108
+ deprecationWarnings: topSuite.result.deprecationWarnings
1109
+ }, function() {});
1060
1110
  });
1061
1111
  });
1062
1112
  };
@@ -1080,12 +1130,27 @@ getJasmineRequireObj().Env = function(j$) {
1080
1130
  reporter.clearReporters();
1081
1131
  };
1082
1132
 
1083
- var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
1084
- if(!currentRunnable()) {
1085
- throw new Error('Spies must be created in a before function or a spec');
1133
+ var spyFactory = new j$.SpyFactory(function() {
1134
+ var runnable = currentRunnable();
1135
+
1136
+ if (runnable) {
1137
+ return runnableResources[runnable.id].customSpyStrategies;
1138
+ }
1139
+
1140
+ return {};
1141
+ });
1142
+
1143
+ var spyRegistry = new j$.SpyRegistry({
1144
+ currentSpies: function() {
1145
+ if(!currentRunnable()) {
1146
+ throw new Error('Spies must be created in a before function or a spec');
1147
+ }
1148
+ return runnableResources[currentRunnable().id].spies;
1149
+ },
1150
+ createSpy: function(name, originalFn) {
1151
+ return self.createSpy(name, originalFn);
1086
1152
  }
1087
- return runnableResources[currentRunnable().id].spies;
1088
- }});
1153
+ });
1089
1154
 
1090
1155
  this.allowRespy = function(allow){
1091
1156
  spyRegistry.allowRespy(allow);
@@ -1099,6 +1164,14 @@ getJasmineRequireObj().Env = function(j$) {
1099
1164
  return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
1100
1165
  };
1101
1166
 
1167
+ this.createSpy = function(name, originalFn) {
1168
+ return spyFactory.createSpy(name, originalFn);
1169
+ };
1170
+
1171
+ this.createSpyObj = function(baseName, methodNames) {
1172
+ return spyFactory.createSpyObj(baseName, methodNames);
1173
+ };
1174
+
1102
1175
  var ensureIsFunction = function(fn, caller) {
1103
1176
  if (!j$.isFunction_(fn)) {
1104
1177
  throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
@@ -1158,7 +1231,6 @@ getJasmineRequireObj().Env = function(j$) {
1158
1231
  var focusedRunnables = [];
1159
1232
 
1160
1233
  this.fdescribe = function(description, specDefinitions) {
1161
- this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
1162
1234
  ensureIsNotNested('fdescribe');
1163
1235
  ensureIsFunction(specDefinitions, 'fdescribe');
1164
1236
  var suite = suiteFactory(description);
@@ -1184,9 +1256,7 @@ getJasmineRequireObj().Env = function(j$) {
1184
1256
  }
1185
1257
 
1186
1258
  if (declarationError) {
1187
- self.it('encountered a declaration exception', function() {
1188
- throw declarationError;
1189
- });
1259
+ suite.onException(declarationError);
1190
1260
  }
1191
1261
 
1192
1262
  currentDeclarationSuite = parentSuite;
@@ -1237,22 +1307,23 @@ getJasmineRequireObj().Env = function(j$) {
1237
1307
  throwOnExpectationFailure: throwOnExpectationFailure
1238
1308
  });
1239
1309
 
1240
- if (!self.specFilter(spec)) {
1241
- spec.disable();
1242
- }
1243
-
1244
1310
  return spec;
1245
1311
 
1246
- function specResultCallback(result) {
1312
+ function specResultCallback(result, next) {
1247
1313
  clearResourcesForRunnable(spec.id);
1248
1314
  currentSpec = null;
1249
- reporter.specDone(result);
1315
+
1316
+ if (result.status === 'failed') {
1317
+ hasFailures = true;
1318
+ }
1319
+
1320
+ reporter.specDone(result, next);
1250
1321
  }
1251
1322
 
1252
- function specStarted(spec) {
1323
+ function specStarted(spec, next) {
1253
1324
  currentSpec = spec;
1254
1325
  defaultResourcesForRunnable(spec.id, suite.id);
1255
- reporter.specStarted(spec.result);
1326
+ reporter.specStarted(spec.result, next);
1256
1327
  }
1257
1328
  };
1258
1329
 
@@ -1284,7 +1355,6 @@ getJasmineRequireObj().Env = function(j$) {
1284
1355
  };
1285
1356
 
1286
1357
  this.fit = function(description, fn, timeout){
1287
- this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0');
1288
1358
  ensureIsNotNested('fit');
1289
1359
  ensureIsFunctionOrAsync(fn, 'fit');
1290
1360
  var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
@@ -1540,10 +1610,7 @@ getJasmineRequireObj().Any = function(j$) {
1540
1610
  }
1541
1611
 
1542
1612
  if (this.expectedObject == Object) {
1543
- if (other === null) {
1544
- j$.getEnv().deprecated('jasmine.Any(Object) will no longer match null in Jasmine 3.0');
1545
- }
1546
- return typeof other == 'object';
1613
+ return other !== null && typeof other == 'object';
1547
1614
  }
1548
1615
 
1549
1616
  if (this.expectedObject == Boolean) {
@@ -1986,22 +2053,10 @@ getJasmineRequireObj().Clock = function() {
1986
2053
  };
1987
2054
 
1988
2055
  self.setTimeout = function(fn, delay, params) {
1989
- if (legacyIE()) {
1990
- if (arguments.length > 2) {
1991
- throw new Error('IE < 9 cannot support extra params to setTimeout without a polyfill');
1992
- }
1993
- return timer.setTimeout(fn, delay);
1994
- }
1995
2056
  return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
1996
2057
  };
1997
2058
 
1998
2059
  self.setInterval = function(fn, delay, params) {
1999
- if (legacyIE()) {
2000
- if (arguments.length > 2) {
2001
- throw new Error('IE < 9 cannot support extra params to setInterval without a polyfill');
2002
- }
2003
- return timer.setInterval(fn, delay);
2004
- }
2005
2060
  return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
2006
2061
  };
2007
2062
 
@@ -2036,11 +2091,6 @@ getJasmineRequireObj().Clock = function() {
2036
2091
  global.clearInterval === realTimingFunctions.clearInterval;
2037
2092
  }
2038
2093
 
2039
- function legacyIE() {
2040
- //if these methods are polyfilled, apply will be present
2041
- return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
2042
- }
2043
-
2044
2094
  function replace(dest, source) {
2045
2095
  for (var prop in source) {
2046
2096
  dest[prop] = source[prop];
@@ -2249,6 +2299,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
2249
2299
  }
2250
2300
  funcToRun.funcToCall.apply(null, funcToRun.params || []);
2251
2301
  });
2302
+ deletedKeys = [];
2252
2303
  } while (scheduledLookup.length > 0 &&
2253
2304
  // checking first if we're out of time prevents setTimeout(0)
2254
2305
  // scheduled in a funcToRun from forcing an extra iteration
@@ -2275,8 +2326,10 @@ getJasmineRequireObj().errors = function() {
2275
2326
  ExpectationFailed: ExpectationFailed
2276
2327
  };
2277
2328
  };
2278
- getJasmineRequireObj().ExceptionFormatter = function() {
2279
- function ExceptionFormatter() {
2329
+ getJasmineRequireObj().ExceptionFormatter = function(j$) {
2330
+
2331
+ function ExceptionFormatter(options) {
2332
+ var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
2280
2333
  this.message = function(error) {
2281
2334
  var message = '';
2282
2335
 
@@ -2298,8 +2351,34 @@ getJasmineRequireObj().ExceptionFormatter = function() {
2298
2351
  };
2299
2352
 
2300
2353
  this.stack = function(error) {
2301
- return error ? error.stack : null;
2302
- };
2354
+ if (!error || !error.stack) {
2355
+ return null;
2356
+ }
2357
+
2358
+ var stackTrace = new j$.StackTrace(error.stack);
2359
+ var lines = filterJasmine(stackTrace);
2360
+
2361
+ if (stackTrace.message) {
2362
+ lines.unshift(stackTrace.message);
2363
+ }
2364
+
2365
+ return lines.join('\n');
2366
+ };
2367
+
2368
+ function filterJasmine(stackTrace) {
2369
+ var result = [],
2370
+ jasmineMarker = stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
2371
+
2372
+ stackTrace.frames.forEach(function(frame) {
2373
+ if (frame.file && frame.file !== jasmineFile) {
2374
+ result.push(frame.raw);
2375
+ } else if (result[result.length - 1] !== jasmineMarker) {
2376
+ result.push(jasmineMarker);
2377
+ }
2378
+ });
2379
+
2380
+ return result;
2381
+ }
2303
2382
  }
2304
2383
 
2305
2384
  return ExceptionFormatter;
@@ -2491,8 +2570,6 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
2491
2570
  }
2492
2571
  };
2493
2572
 
2494
- this.uninstall = function noop() {};
2495
-
2496
2573
  this.install = function install() {
2497
2574
  if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
2498
2575
  var originalHandlers = global.process.listeners('uncaughtException');
@@ -2745,28 +2822,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
2745
2822
  var bIsDomNode = j$.isDomNode(b);
2746
2823
  if (aIsDomNode && bIsDomNode) {
2747
2824
  // At first try to use DOM3 method isEqualNode
2748
- if (a.isEqualNode) {
2749
- result = a.isEqualNode(b);
2750
- if (!result) {
2751
- diffBuilder.record(a, b);
2752
- }
2753
- return result;
2754
- }
2755
- // IE8 doesn't support isEqualNode, try to use outerHTML && innerText
2756
- var aIsElement = a instanceof Element;
2757
- var bIsElement = b instanceof Element;
2758
- if (aIsElement && bIsElement) {
2759
- result = a.outerHTML == b.outerHTML;
2760
- if (!result) {
2761
- diffBuilder.record(a, b);
2762
- }
2763
- return result;
2764
- }
2765
- if (aIsElement || bIsElement) {
2766
- diffBuilder.record(a, b);
2767
- return false;
2768
- }
2769
- result = a.innerText == b.innerText && a.textContent == b.textContent;
2825
+ result = a.isEqualNode(b);
2770
2826
  if (!result) {
2771
2827
  diffBuilder.record(a, b);
2772
2828
  }
@@ -3553,8 +3609,8 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
3553
3609
  result.pass = actual.calls.any();
3554
3610
 
3555
3611
  result.message = result.pass ?
3556
- 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
3557
- 'Expected spy ' + actual.and.identity() + ' to have been called.';
3612
+ 'Expected spy ' + actual.and.identity + ' not to have been called.' :
3613
+ 'Expected spy ' + actual.and.identity + ' to have been called.';
3558
3614
 
3559
3615
  return result;
3560
3616
  }
@@ -3589,11 +3645,11 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
3589
3645
  var result = { pass: false };
3590
3646
 
3591
3647
  if (!firstSpy.calls.count()) {
3592
- result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called.';
3648
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.';
3593
3649
  return result;
3594
3650
  }
3595
3651
  if (!latterSpy.calls.count()) {
3596
- result.message = 'Expected spy ' + latterSpy.and.identity() + ' to have been called.';
3652
+ result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.';
3597
3653
  return result;
3598
3654
  }
3599
3655
 
@@ -3603,17 +3659,17 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
3603
3659
  result.pass = latest1stSpyCall < first2ndSpyCall;
3604
3660
 
3605
3661
  if (result.pass) {
3606
- result.message = 'Expected spy ' + firstSpy.and.identity() + ' to not have been called before spy ' + latterSpy.and.identity() + ', but it was';
3662
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was';
3607
3663
  } else {
3608
3664
  var first1stSpyCall = firstSpy.calls.first().invocationOrder;
3609
3665
  var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
3610
3666
 
3611
3667
  if(first1stSpyCall < first2ndSpyCall) {
3612
- result.message = 'Expected latest call to spy ' + firstSpy.and.identity() + ' to have been called before first call to spy ' + latterSpy.and.identity() + ' (no interleaved calls)';
3668
+ result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)';
3613
3669
  } else if (latest2ndSpyCall > latest1stSpyCall) {
3614
- result.message = 'Expected first call to spy ' + latterSpy.and.identity() + ' to have been called after latest call to spy ' + firstSpy.and.identity() + ' (no interleaved calls)';
3670
+ result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)';
3615
3671
  } else {
3616
- result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called before spy ' + latterSpy.and.identity();
3672
+ result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity;
3617
3673
  }
3618
3674
  }
3619
3675
 
@@ -3656,8 +3712,8 @@ getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
3656
3712
  var timesMessage = expected === 1 ? 'once' : expected + ' times';
3657
3713
  result.pass = calls === expected;
3658
3714
  result.message = result.pass ?
3659
- 'Expected spy ' + actual.and.identity() + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
3660
- 'Expected spy ' + actual.and.identity() + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
3715
+ 'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
3716
+ 'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
3661
3717
  return result;
3662
3718
  }
3663
3719
  };
@@ -3691,15 +3747,15 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
3691
3747
  }
3692
3748
 
3693
3749
  if (!actual.calls.any()) {
3694
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
3750
+ result.message = function() { return 'Expected spy ' + actual.and.identity + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
3695
3751
  return result;
3696
3752
  }
3697
3753
 
3698
3754
  if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
3699
3755
  result.pass = true;
3700
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
3756
+ result.message = function() { return 'Expected spy ' + actual.and.identity + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
3701
3757
  } else {
3702
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but actual calls were ' + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + '.'; };
3758
+ result.message = function() { return 'Expected spy ' + actual.and.identity + ' to have been called with ' + j$.pp(expectedArgs) + ' but actual calls were ' + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + '.'; };
3703
3759
  }
3704
3760
 
3705
3761
  return result;
@@ -3820,73 +3876,61 @@ getJasmineRequireObj().toThrowError = function(j$) {
3820
3876
  function toThrowError () {
3821
3877
  return {
3822
3878
  compare: function(actual) {
3823
- var threw = false,
3824
- pass = {pass: true},
3825
- fail = {pass: false},
3879
+ var errorMatcher = getMatcher.apply(null, arguments),
3826
3880
  thrown;
3827
3881
 
3828
3882
  if (typeof actual != 'function') {
3829
3883
  throw new Error(getErrorMsg('Actual is not a Function'));
3830
3884
  }
3831
3885
 
3832
- var errorMatcher = getMatcher.apply(null, arguments);
3833
-
3834
3886
  try {
3835
3887
  actual();
3888
+ return fail('Expected function to throw an Error.');
3836
3889
  } catch (e) {
3837
- threw = true;
3838
3890
  thrown = e;
3839
3891
  }
3840
3892
 
3841
- if (!threw) {
3842
- fail.message = 'Expected function to throw an Error.';
3843
- return fail;
3844
- }
3845
-
3846
- // Get Error constructor of thrown
3847
- if (!isErrorObject(thrown)) {
3848
- fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
3849
- return fail;
3893
+ if (!j$.isError_(thrown)) {
3894
+ return fail(function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; });
3850
3895
  }
3851
3896
 
3852
- if (errorMatcher.hasNoSpecifics()) {
3853
- pass.message = 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(thrown) + '.';
3854
- return pass;
3855
- }
3856
-
3857
- if (errorMatcher.matches(thrown)) {
3858
- pass.message = function() {
3859
- return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
3860
- };
3861
- return pass;
3862
- } else {
3863
- fail.message = function() {
3864
- return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
3865
- ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
3866
- };
3867
- return fail;
3868
- }
3897
+ return errorMatcher.match(thrown);
3869
3898
  }
3870
3899
  };
3871
3900
 
3872
3901
  function getMatcher() {
3873
- var expected = null,
3874
- errorType = null;
3902
+ var expected, errorType;
3875
3903
 
3876
- if (arguments.length == 2) {
3877
- expected = arguments[1];
3878
- if (isAnErrorType(expected)) {
3879
- errorType = expected;
3880
- expected = null;
3881
- }
3882
- } else if (arguments.length > 2) {
3904
+ if (arguments[2]) {
3883
3905
  errorType = arguments[1];
3884
3906
  expected = arguments[2];
3885
3907
  if (!isAnErrorType(errorType)) {
3886
3908
  throw new Error(getErrorMsg('Expected error type is not an Error.'));
3887
3909
  }
3910
+
3911
+ return exactMatcher(expected, errorType);
3912
+ } else if (arguments[1]) {
3913
+ expected = arguments[1];
3914
+
3915
+ if (isAnErrorType(arguments[1])) {
3916
+ return exactMatcher(null, arguments[1]);
3917
+ } else {
3918
+ return exactMatcher(arguments[1], null);
3919
+ }
3920
+ } else {
3921
+ return anyMatcher();
3888
3922
  }
3923
+ }
3889
3924
 
3925
+ function anyMatcher() {
3926
+ return {
3927
+ match: function(error) {
3928
+ return pass('Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.');
3929
+ }
3930
+ };
3931
+ }
3932
+
3933
+ function exactMatcher(expected, errorType) {
3890
3934
  if (expected && !isStringOrRegExp(expected)) {
3891
3935
  if (errorType) {
3892
3936
  throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
@@ -3903,33 +3947,46 @@ getJasmineRequireObj().toThrowError = function(j$) {
3903
3947
  }
3904
3948
  }
3905
3949
 
3906
- return {
3907
- errorTypeDescription: errorType ? j$.fnNameFor(errorType) : 'an exception',
3908
- thrownDescription: function(thrown) {
3909
- var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
3910
- thrownMessage = '';
3950
+ var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception';
3911
3951
 
3912
- if (expected) {
3913
- thrownMessage = ' with message ' + j$.pp(thrown.message);
3914
- }
3952
+ function thrownDescription(thrown) {
3953
+ var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
3954
+ thrownMessage = '';
3915
3955
 
3916
- return thrownName + thrownMessage;
3917
- },
3918
- messageDescription: function() {
3919
- if (expected === null) {
3920
- return '';
3921
- } else if (expected instanceof RegExp) {
3922
- return ' with a message matching ' + j$.pp(expected);
3956
+ if (expected) {
3957
+ thrownMessage = ' with message ' + j$.pp(thrown.message);
3958
+ }
3959
+
3960
+ return thrownName + thrownMessage;
3961
+ }
3962
+
3963
+ function messageDescription() {
3964
+ if (expected === null) {
3965
+ return '';
3966
+ } else if (expected instanceof RegExp) {
3967
+ return ' with a message matching ' + j$.pp(expected);
3968
+ } else {
3969
+ return ' with message ' + j$.pp(expected);
3970
+ }
3971
+ }
3972
+
3973
+ function matches(error) {
3974
+ return (errorType === null || error instanceof errorType) &&
3975
+ (expected === null || messageMatch(error.message));
3976
+ }
3977
+
3978
+ return {
3979
+ match: function(thrown) {
3980
+ if (matches(thrown)) {
3981
+ return pass(function() {
3982
+ return 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.';
3983
+ });
3923
3984
  } else {
3924
- return ' with message ' + j$.pp(expected);
3985
+ return fail(function() {
3986
+ return 'Expected function to throw ' + errorTypeDescription + messageDescription() +
3987
+ ', but it threw ' + thrownDescription(thrown) + '.';
3988
+ });
3925
3989
  }
3926
- },
3927
- hasNoSpecifics: function() {
3928
- return expected === null && errorType === null;
3929
- },
3930
- matches: function(error) {
3931
- return (errorType === null || error instanceof errorType) &&
3932
- (expected === null || messageMatch(error.message));
3933
3990
  }
3934
3991
  };
3935
3992
  }
@@ -3945,22 +4002,94 @@ getJasmineRequireObj().toThrowError = function(j$) {
3945
4002
 
3946
4003
  var Surrogate = function() {};
3947
4004
  Surrogate.prototype = type.prototype;
3948
- return isErrorObject(new Surrogate());
4005
+ return j$.isError_(new Surrogate());
3949
4006
  }
4007
+ }
3950
4008
 
3951
- function isErrorObject(thrown) {
3952
- if (thrown instanceof Error) {
3953
- return true;
3954
- }
3955
- if (thrown && thrown.constructor && thrown.constructor.constructor &&
3956
- (thrown instanceof (thrown.constructor.constructor('return this')()).Error)) {
3957
- return true;
4009
+ function pass(message) {
4010
+ return {
4011
+ pass: true,
4012
+ message: message
4013
+ };
4014
+ }
4015
+
4016
+ function fail(message) {
4017
+ return {
4018
+ pass: false,
4019
+ message: message
4020
+ };
4021
+ }
4022
+
4023
+ return toThrowError;
4024
+ };
4025
+
4026
+ getJasmineRequireObj().toThrowMatching = function(j$) {
4027
+ var usageError = j$.formatErrorMsg('<toThrowMatching>', 'expect(function() {<expectation>}).toThrowMatching(<Predicate>)');
4028
+
4029
+ /**
4030
+ * {@link expect} a function to `throw` something matching a predicate.
4031
+ * @function
4032
+ * @name matchers#toThrowMatching
4033
+ * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches.
4034
+ * @example
4035
+ * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
4036
+ */
4037
+ function toThrowMatching() {
4038
+ return {
4039
+ compare: function(actual, predicate) {
4040
+ var thrown;
4041
+
4042
+ if (typeof actual !== 'function') {
4043
+ throw new Error(usageError('Actual is not a Function'));
4044
+ }
4045
+
4046
+ if (typeof predicate !== 'function') {
4047
+ throw new Error(usageError('Predicate is not a Function'));
4048
+ }
4049
+
4050
+ try {
4051
+ actual();
4052
+ return fail('Expected function to throw an exception.');
4053
+ } catch (e) {
4054
+ thrown = e;
4055
+ }
4056
+
4057
+ if (predicate(thrown)) {
4058
+ return pass('Expected function not to throw an exception matching a predicate.');
4059
+ } else {
4060
+ return fail(function() {
4061
+ return 'Expected function to throw an exception matching a predicate, ' +
4062
+ 'but it threw ' + thrownDescription(thrown) + '.';
4063
+ });
4064
+ }
3958
4065
  }
3959
- return false;
4066
+ };
4067
+ }
4068
+
4069
+ function thrownDescription(thrown) {
4070
+ if (thrown && thrown.constructor) {
4071
+ return j$.fnNameFor(thrown.constructor) + ' with message ' +
4072
+ j$.pp(thrown.message);
4073
+ } else {
4074
+ return j$.pp(thrown);
3960
4075
  }
3961
4076
  }
3962
4077
 
3963
- return toThrowError;
4078
+ function pass(message) {
4079
+ return {
4080
+ pass: true,
4081
+ message: message
4082
+ };
4083
+ }
4084
+
4085
+ function fail(message) {
4086
+ return {
4087
+ pass: false,
4088
+ message: message
4089
+ };
4090
+ }
4091
+
4092
+ return toThrowMatching;
3964
4093
  };
3965
4094
 
3966
4095
  getJasmineRequireObj().MockDate = function() {
@@ -4077,11 +4206,13 @@ getJasmineRequireObj().pp = function(j$) {
4077
4206
  } else if (typeof value === 'string') {
4078
4207
  this.emitString(value);
4079
4208
  } else if (j$.isSpy(value)) {
4080
- this.emitScalar('spy on ' + value.and.identity());
4209
+ this.emitScalar('spy on ' + value.and.identity);
4081
4210
  } else if (value instanceof RegExp) {
4082
4211
  this.emitScalar(value.toString());
4083
4212
  } else if (typeof value === 'function') {
4084
4213
  this.emitScalar('Function');
4214
+ } else if (value.nodeType === 1) {
4215
+ this.emitDomElement(value);
4085
4216
  } else if (typeof value.nodeType === 'number') {
4086
4217
  this.emitScalar('HTMLNode');
4087
4218
  } else if (value instanceof Date) {
@@ -4273,6 +4404,18 @@ getJasmineRequireObj().pp = function(j$) {
4273
4404
  this.append(constructorName + ' [ ' + itemsString + ' ]');
4274
4405
  };
4275
4406
 
4407
+ PrettyPrinter.prototype.emitDomElement = function(el) {
4408
+ var closingTag = '</' + el.tagName.toLowerCase() + '>';
4409
+
4410
+ if (el.innerHTML === '') {
4411
+ this.append(el.outerHTML.replace(closingTag, ''));
4412
+ } else {
4413
+ var tagEnd = el.outerHTML.indexOf(el.innerHTML);
4414
+ this.append(el.outerHTML.substring(0, tagEnd));
4415
+ this.append('...' + closingTag);
4416
+ }
4417
+ };
4418
+
4276
4419
  PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
4277
4420
  this.append(property);
4278
4421
  this.append(': ');
@@ -4347,6 +4490,9 @@ getJasmineRequireObj().pp = function(j$) {
4347
4490
  };
4348
4491
 
4349
4492
  getJasmineRequireObj().QueueRunner = function(j$) {
4493
+ function StopExecutionError() {}
4494
+ StopExecutionError.prototype = new Error();
4495
+ j$.StopExecutionError = StopExecutionError;
4350
4496
 
4351
4497
  function once(fn) {
4352
4498
  var called = false;
@@ -4366,12 +4512,16 @@ getJasmineRequireObj().QueueRunner = function(j$) {
4366
4512
  this.onComplete = attrs.onComplete || function() {};
4367
4513
  this.clearStack = attrs.clearStack || function(fn) {fn();};
4368
4514
  this.onException = attrs.onException || function() {};
4369
- this.catchException = attrs.catchException || function() { return true; };
4370
4515
  this.userContext = attrs.userContext || new j$.UserContext();
4371
4516
  this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
4372
4517
  this.fail = attrs.fail || function() {};
4373
4518
  this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
4374
4519
  this.completeOnFirstError = !!attrs.completeOnFirstError;
4520
+ this.errored = false;
4521
+
4522
+ if (typeof(this.onComplete) !== 'function') {
4523
+ throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
4524
+ }
4375
4525
  this.deprecated = attrs.deprecated;
4376
4526
  }
4377
4527
 
@@ -4392,135 +4542,134 @@ getJasmineRequireObj().QueueRunner = function(j$) {
4392
4542
  }
4393
4543
  };
4394
4544
 
4395
- QueueRunner.prototype.run = function(recursiveIndex) {
4396
- var length = this.queueableFns.length,
4397
- self = this,
4398
- iterativeIndex;
4399
-
4400
-
4401
- for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
4402
- var result = attempt(iterativeIndex);
4403
-
4404
- if (!result.completedSynchronously) {
4405
- return;
4406
- }
4407
-
4408
- if (this.completeOnFirstError && result.errored) {
4409
- this.skipToCleanup(iterativeIndex);
4410
- return;
4411
- }
4412
- }
4545
+ QueueRunner.prototype.clearTimeout = function(timeoutId) {
4546
+ Function.prototype.apply.apply(this.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
4547
+ };
4413
4548
 
4414
- this.clearStack(function() {
4415
- self.globalErrors.popListener(self.handleFinalError);
4416
- self.onComplete();
4417
- });
4549
+ QueueRunner.prototype.setTimeout = function(fn, timeout) {
4550
+ return Function.prototype.apply.apply(this.timeout.setTimeout, [j$.getGlobal(), [fn, timeout]]);
4551
+ };
4418
4552
 
4419
- function attempt() {
4420
- var clearTimeout = function () {
4421
- Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
4422
- },
4423
- setTimeout = function(delayedFn, delay) {
4424
- return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
4425
- },
4426
- completedSynchronously = true,
4427
- handleError = function(error) {
4428
- onException(error);
4429
- next();
4430
- },
4431
- cleanup = once(function() {
4432
- clearTimeout(timeoutId);
4433
- self.globalErrors.popListener(handleError);
4434
- }),
4435
- next = once(function (err) {
4436
- cleanup();
4437
-
4438
- if (err instanceof Error) {
4439
- self.deprecated('done callback received an Error object. Jasmine 3.0 will treat this as a failure');
4440
- }
4553
+ QueueRunner.prototype.attempt = function attempt(iterativeIndex) {
4554
+ var self = this, completedSynchronously = true,
4555
+ handleError = function handleError(error) {
4556
+ onException(error);
4557
+ next(error);
4558
+ },
4559
+ cleanup = once(function cleanup() {
4560
+ self.clearTimeout(timeoutId);
4561
+ self.globalErrors.popListener(handleError);
4562
+ }),
4563
+ next = once(function next(err) {
4564
+ cleanup();
4441
4565
 
4442
- function runNext() {
4443
- if (self.completeOnFirstError && errored) {
4444
- self.skipToCleanup(iterativeIndex);
4445
- } else {
4446
- self.run(iterativeIndex + 1);
4447
- }
4566
+ if (j$.isError_(err)) {
4567
+ if (!(err instanceof StopExecutionError)) {
4568
+ self.fail(err);
4448
4569
  }
4570
+ self.errored = errored = true;
4571
+ }
4449
4572
 
4450
- if (completedSynchronously) {
4451
- setTimeout(runNext);
4573
+ function runNext() {
4574
+ if (self.completeOnFirstError && errored) {
4575
+ self.skipToCleanup(iterativeIndex);
4452
4576
  } else {
4453
- runNext();
4577
+ self.run(iterativeIndex + 1);
4454
4578
  }
4455
- }),
4456
- errored = false,
4457
- queueableFn = self.queueableFns[iterativeIndex],
4458
- timeoutId;
4459
-
4460
- next.fail = function() {
4461
- self.fail.apply(null, arguments);
4462
- errored = true;
4463
- next();
4464
- };
4579
+ }
4465
4580
 
4466
- self.globalErrors.pushListener(handleError);
4581
+ if (completedSynchronously) {
4582
+ self.setTimeout(runNext);
4583
+ } else {
4584
+ runNext();
4585
+ }
4586
+ }),
4587
+ errored = false,
4588
+ queueableFn = self.queueableFns[iterativeIndex],
4589
+ timeoutId;
4467
4590
 
4468
- if (queueableFn.timeout) {
4469
- timeoutId = setTimeout(function() {
4470
- var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
4471
- onException(error);
4472
- next();
4473
- }, queueableFn.timeout());
4474
- }
4591
+ next.fail = function nextFail() {
4592
+ self.fail.apply(null, arguments);
4593
+ self.errored = errored = true;
4594
+ next();
4595
+ };
4475
4596
 
4476
- try {
4477
- if (queueableFn.fn.length === 0) {
4478
- var maybeThenable = queueableFn.fn.call(self.userContext);
4597
+ self.globalErrors.pushListener(handleError);
4479
4598
 
4480
- if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
4481
- maybeThenable.then(next, onPromiseRejection);
4482
- completedSynchronously = false;
4483
- return { completedSynchronously: false };
4484
- }
4485
- } else {
4486
- queueableFn.fn.call(self.userContext, next);
4599
+ if (queueableFn.timeout) {
4600
+ timeoutId = self.setTimeout(function() {
4601
+ var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
4602
+ onException(error);
4603
+ next();
4604
+ }, queueableFn.timeout());
4605
+ }
4606
+
4607
+ try {
4608
+ if (queueableFn.fn.length === 0) {
4609
+ var maybeThenable = queueableFn.fn.call(self.userContext);
4610
+
4611
+ if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
4612
+ maybeThenable.then(next, onPromiseRejection);
4487
4613
  completedSynchronously = false;
4488
4614
  return { completedSynchronously: false };
4489
4615
  }
4490
- } catch (e) {
4491
- handleException(e, queueableFn);
4492
- errored = true;
4616
+ } else {
4617
+ queueableFn.fn.call(self.userContext, next);
4618
+ completedSynchronously = false;
4619
+ return { completedSynchronously: false };
4493
4620
  }
4621
+ } catch (e) {
4622
+ onException(e);
4623
+ self.errored = errored = true;
4624
+ }
4494
4625
 
4495
- cleanup();
4496
- return { completedSynchronously: true, errored: errored };
4626
+ cleanup();
4627
+ return { completedSynchronously: true, errored: errored };
4497
4628
 
4498
- function onException(e) {
4499
- self.onException(e);
4500
- errored = true;
4501
- }
4629
+ function onException(e) {
4630
+ self.onException(e);
4631
+ self.errored = errored = true;
4632
+ }
4502
4633
 
4503
- function onPromiseRejection(e) {
4504
- onException(e);
4505
- next();
4634
+ function onPromiseRejection(e) {
4635
+ onException(e);
4636
+ next();
4637
+ }
4638
+ };
4639
+
4640
+ QueueRunner.prototype.run = function(recursiveIndex) {
4641
+ var length = this.queueableFns.length,
4642
+ self = this,
4643
+ iterativeIndex;
4644
+
4645
+
4646
+ for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
4647
+ var result = this.attempt(iterativeIndex);
4648
+
4649
+ if (!result.completedSynchronously) {
4650
+ return;
4506
4651
  }
4507
4652
 
4508
- function handleException(e, queueableFn) {
4509
- onException(e);
4510
- if (!self.catchException(e)) {
4511
- //TODO: set a var when we catch an exception and
4512
- //use a finally block to close the loop in a nice way..
4513
- throw e;
4514
- }
4653
+ self.errored = result.errored;
4654
+
4655
+ if (this.completeOnFirstError && result.errored) {
4656
+ this.skipToCleanup(iterativeIndex);
4657
+ return;
4515
4658
  }
4516
4659
  }
4660
+
4661
+ this.clearStack(function() {
4662
+ self.globalErrors.popListener(self.handleFinalError);
4663
+ self.onComplete(self.errored && new StopExecutionError());
4664
+ });
4665
+
4517
4666
  };
4518
4667
 
4519
4668
  return QueueRunner;
4520
4669
  };
4521
4670
 
4522
4671
  getJasmineRequireObj().ReportDispatcher = function(j$) {
4523
- function ReportDispatcher(methods) {
4672
+ function ReportDispatcher(methods, queueRunnerFactory) {
4524
4673
 
4525
4674
  var dispatchedMethods = methods || [];
4526
4675
 
@@ -4554,11 +4703,40 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
4554
4703
  if (reporters.length === 0 && fallbackReporter !== null) {
4555
4704
  reporters.push(fallbackReporter);
4556
4705
  }
4706
+ var onComplete = args[args.length - 1];
4707
+ args = j$.util.argsToArray(args).splice(0, args.length - 1);
4708
+ var fns = [];
4557
4709
  for (var i = 0; i < reporters.length; i++) {
4558
4710
  var reporter = reporters[i];
4559
- if (reporter[method]) {
4560
- reporter[method].apply(reporter, j$.util.cloneArgs(args));
4561
- }
4711
+ addFn(fns, reporter, method, args);
4712
+ }
4713
+
4714
+ queueRunnerFactory({
4715
+ queueableFns: fns,
4716
+ onComplete: onComplete,
4717
+ isReporter: true
4718
+ });
4719
+ }
4720
+
4721
+ function addFn(fns, reporter, method, args) {
4722
+ var fn = reporter[method];
4723
+ if (!fn) {
4724
+ return;
4725
+ }
4726
+
4727
+ var thisArgs = j$.util.cloneArgs(args);
4728
+ if (fn.length <= 1) {
4729
+ fns.push({
4730
+ fn: function () {
4731
+ return fn.apply(reporter, thisArgs);
4732
+ }
4733
+ });
4734
+ } else {
4735
+ fns.push({
4736
+ fn: function (done) {
4737
+ return fn.apply(reporter, thisArgs.concat([done]));
4738
+ }
4739
+ });
4562
4740
  }
4563
4741
  }
4564
4742
  }
@@ -4825,6 +5003,43 @@ getJasmineRequireObj().interface = function(jasmine, env) {
4825
5003
  return env.clock;
4826
5004
  };
4827
5005
 
5006
+ /**
5007
+ * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
5008
+ * @name jasmine.createSpy
5009
+ * @function
5010
+ * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
5011
+ * @param {Function} [originalFn] - Function to act as the real implementation.
5012
+ * @return {Spy}
5013
+ */
5014
+ jasmine.createSpy = function(name, originalFn) {
5015
+ return env.createSpy(name, originalFn);
5016
+ };
5017
+
5018
+ /**
5019
+ * Create an object with multiple {@link Spy}s as its members.
5020
+ * @name jasmine.createSpyObj
5021
+ * @function
5022
+ * @param {String} [baseName] - Base name for the spies in the object.
5023
+ * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
5024
+ * @return {Object}
5025
+ */
5026
+ jasmine.createSpyObj = function(baseName, methodNames) {
5027
+ return env.createSpyObj(baseName, methodNames);
5028
+ };
5029
+
5030
+ /**
5031
+ * Add a custom spy strategy for the current scope of specs.
5032
+ *
5033
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
5034
+ * @name jasmine.addSpyStrategy
5035
+ * @function
5036
+ * @param {String} name - The name of the strategy (i.e. what you call from `and`)
5037
+ * @param {Function} factory - Factory function that returns the plan to be executed.
5038
+ */
5039
+ jasmine.addSpyStrategy = function(name, factory) {
5040
+ return env.addSpyStrategy(name, factory);
5041
+ };
5042
+
4828
5043
  return jasmineInterface;
4829
5044
  };
4830
5045
 
@@ -4843,17 +5058,18 @@ getJasmineRequireObj().Spy = function (j$) {
4843
5058
  * @constructor
4844
5059
  * @name Spy
4845
5060
  */
4846
- function Spy(name, originalFn) {
5061
+ function Spy(name, originalFn, customStrategies) {
4847
5062
  var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
4848
5063
  wrapper = makeFunc(numArgs, function () {
4849
5064
  return spy.apply(this, Array.prototype.slice.call(arguments));
4850
5065
  }),
4851
- spyStrategy = new j$.SpyStrategy({
5066
+ strategyDispatcher = new SpyStrategyDispatcher({
4852
5067
  name: name,
4853
5068
  fn: originalFn,
4854
5069
  getSpy: function () {
4855
5070
  return wrapper;
4856
- }
5071
+ },
5072
+ customStrategies: customStrategies
4857
5073
  }),
4858
5074
  callTracker = new j$.CallTracker(),
4859
5075
  spy = function () {
@@ -4870,7 +5086,7 @@ getJasmineRequireObj().Spy = function (j$) {
4870
5086
  };
4871
5087
 
4872
5088
  callTracker.track(callData);
4873
- var returnValue = spyStrategy.exec.apply(this, arguments);
5089
+ var returnValue = strategyDispatcher.exec(this, arguments);
4874
5090
  callData.returnValue = returnValue;
4875
5091
 
4876
5092
  return returnValue;
@@ -4899,15 +5115,144 @@ getJasmineRequireObj().Spy = function (j$) {
4899
5115
  wrapper[prop] = originalFn[prop];
4900
5116
  }
4901
5117
 
4902
- wrapper.and = spyStrategy;
5118
+ /**
5119
+ * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used
5120
+ * whenever the spy is called with arguments that don't match any strategy
5121
+ * created with {@link Spy#withArgs}.
5122
+ * @name Spy#and
5123
+ * @example
5124
+ * spyOn(someObj, 'func').and.returnValue(42);
5125
+ */
5126
+ wrapper.and = strategyDispatcher.and;
5127
+ /**
5128
+ * Specifies a strategy to be used for calls to the spy that have the
5129
+ * specified arguments.
5130
+ * @name Spy#withArgs
5131
+ * @function
5132
+ * @param {...*} args - The arguments to match
5133
+ * @type {SpyStrategy}
5134
+ * @example
5135
+ * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42);
5136
+ * someObj.func(1, 2, 3); // returns 42
5137
+ */
5138
+ wrapper.withArgs = function() {
5139
+ return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments);
5140
+ };
4903
5141
  wrapper.calls = callTracker;
4904
5142
 
4905
5143
  return wrapper;
4906
5144
  }
4907
5145
 
5146
+
5147
+ function SpyStrategyDispatcher(strategyArgs) {
5148
+ var baseStrategy = new j$.SpyStrategy(strategyArgs);
5149
+ var argsStrategies = new StrategyDict(function() {
5150
+ return new j$.SpyStrategy(strategyArgs);
5151
+ });
5152
+
5153
+ this.and = baseStrategy;
5154
+
5155
+ this.exec = function(spy, args) {
5156
+ var strategy = argsStrategies.get(args);
5157
+
5158
+ if (!strategy) {
5159
+ if (argsStrategies.any() && !baseStrategy.isConfigured()) {
5160
+ throw new Error('Spy \'' + strategyArgs.name + '\' receieved a call with arguments ' + j$.pp(Array.prototype.slice.call(args)) + ' but all configured strategies specify other arguments.');
5161
+ } else {
5162
+ strategy = baseStrategy;
5163
+ }
5164
+ }
5165
+
5166
+ return strategy.exec(spy, args);
5167
+ };
5168
+
5169
+ this.withArgs = function() {
5170
+ return { and: argsStrategies.getOrCreate(arguments) };
5171
+ };
5172
+ }
5173
+
5174
+ function StrategyDict(strategyFactory) {
5175
+ this.strategies = [];
5176
+ this.strategyFactory = strategyFactory;
5177
+ }
5178
+
5179
+ StrategyDict.prototype.any = function() {
5180
+ return this.strategies.length > 0;
5181
+ };
5182
+
5183
+ StrategyDict.prototype.getOrCreate = function(args) {
5184
+ var strategy = this.get(args);
5185
+
5186
+ if (!strategy) {
5187
+ strategy = this.strategyFactory();
5188
+ this.strategies.push({
5189
+ args: args,
5190
+ strategy: strategy
5191
+ });
5192
+ }
5193
+
5194
+ return strategy;
5195
+ };
5196
+
5197
+ StrategyDict.prototype.get = function(args) {
5198
+ var i;
5199
+
5200
+ for (i = 0; i < this.strategies.length; i++) {
5201
+ if (j$.matchersUtil.equals(args, this.strategies[i].args)) {
5202
+ return this.strategies[i].strategy;
5203
+ }
5204
+ }
5205
+ };
5206
+
4908
5207
  return Spy;
4909
5208
  };
4910
5209
 
5210
+ getJasmineRequireObj().SpyFactory = function(j$) {
5211
+
5212
+ function SpyFactory(getCustomStrategies) {
5213
+ var self = this;
5214
+
5215
+ this.createSpy = function(name, originalFn) {
5216
+ return j$.Spy(name, originalFn, getCustomStrategies());
5217
+ };
5218
+
5219
+ this.createSpyObj = function(baseName, methodNames) {
5220
+ var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
5221
+
5222
+ if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
5223
+ methodNames = baseName;
5224
+ baseName = 'unknown';
5225
+ }
5226
+
5227
+ var obj = {};
5228
+ var spiesWereSet = false;
5229
+
5230
+ if (j$.isArray_(methodNames)) {
5231
+ for (var i = 0; i < methodNames.length; i++) {
5232
+ obj[methodNames[i]] = self.createSpy(baseName + '.' + methodNames[i]);
5233
+ spiesWereSet = true;
5234
+ }
5235
+ } else if (j$.isObject_(methodNames)) {
5236
+ for (var key in methodNames) {
5237
+ if (methodNames.hasOwnProperty(key)) {
5238
+ obj[key] = self.createSpy(baseName + '.' + key);
5239
+ obj[key].and.returnValue(methodNames[key]);
5240
+ spiesWereSet = true;
5241
+ }
5242
+ }
5243
+ }
5244
+
5245
+ if (!spiesWereSet) {
5246
+ throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
5247
+ }
5248
+
5249
+ return obj;
5250
+ };
5251
+ }
5252
+
5253
+ return SpyFactory;
5254
+ };
5255
+
4911
5256
  getJasmineRequireObj().SpyRegistry = function(j$) {
4912
5257
 
4913
5258
  var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
@@ -4915,6 +5260,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
4915
5260
  function SpyRegistry(options) {
4916
5261
  options = options || {};
4917
5262
  var global = options.global || j$.getGlobal();
5263
+ var createSpy = options.createSpy;
4918
5264
  var currentSpies = options.currentSpies || function() { return []; };
4919
5265
 
4920
5266
  this.allowRespy = function(allow){
@@ -4943,19 +5289,14 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
4943
5289
  }
4944
5290
  }
4945
5291
 
4946
- var descriptor;
4947
- try {
4948
- descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
4949
- } catch(e) {
4950
- // IE 8 doesn't support `definePropery` on non-DOM nodes
4951
- }
5292
+ var descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
4952
5293
 
4953
5294
  if (descriptor && !(descriptor.writable || descriptor.set)) {
4954
5295
  throw new Error(getErrorMsg(methodName + ' is not declared writable or has no setter'));
4955
5296
  }
4956
5297
 
4957
5298
  var originalMethod = obj[methodName],
4958
- spiedMethod = j$.createSpy(methodName, originalMethod),
5299
+ spiedMethod = createSpy(methodName, originalMethod),
4959
5300
  restoreStrategy;
4960
5301
 
4961
5302
  if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
@@ -4990,12 +5331,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
4990
5331
  throw new Error('No property name supplied');
4991
5332
  }
4992
5333
 
4993
- var descriptor;
4994
- try {
4995
- descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
4996
- } catch(e) {
4997
- // IE 8 doesn't support `definePropery` on non-DOM nodes
4998
- }
5334
+ var descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
4999
5335
 
5000
5336
  if (!descriptor) {
5001
5337
  throw new Error(propertyName + ' property does not exist');
@@ -5015,7 +5351,7 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
5015
5351
  }
5016
5352
 
5017
5353
  var originalDescriptor = j$.util.clone(descriptor),
5018
- spy = j$.createSpy(propertyName, descriptor[accessType]),
5354
+ spy = createSpy(propertyName, descriptor[accessType]),
5019
5355
  restoreStrategy;
5020
5356
 
5021
5357
  if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
@@ -5054,112 +5390,213 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
5054
5390
  getJasmineRequireObj().SpyStrategy = function(j$) {
5055
5391
 
5056
5392
  /**
5057
- * @namespace Spy#and
5393
+ * @interface SpyStrategy
5058
5394
  */
5059
5395
  function SpyStrategy(options) {
5060
5396
  options = options || {};
5061
5397
 
5062
- var identity = options.name || 'unknown',
5063
- originalFn = options.fn || function() {},
5064
- getSpy = options.getSpy || function() {},
5065
- plan = function() {};
5066
-
5067
5398
  /**
5068
- * Return the identifying information for the spy.
5069
- * @name Spy#and#identity
5070
- * @function
5071
- * @returns {String}
5399
+ * Get the identifying information for the spy.
5400
+ * @name SpyStrategy#identity
5401
+ * @member
5402
+ * @type {String}
5072
5403
  */
5073
- this.identity = function() {
5074
- return identity;
5075
- };
5404
+ this.identity = options.name || 'unknown';
5405
+ this.originalFn = options.fn || function() {};
5406
+ this.getSpy = options.getSpy || function() {};
5407
+ this.plan = this._defaultPlan = function() {};
5076
5408
 
5077
- /**
5078
- * Execute the current spy strategy.
5079
- * @name Spy#and#exec
5080
- * @function
5081
- */
5082
- this.exec = function() {
5083
- return plan.apply(this, arguments);
5084
- };
5409
+ var k, cs = options.customStrategies || {};
5410
+ for (k in cs) {
5411
+ if (j$.util.has(cs, k) && !this[k]) {
5412
+ this[k] = createCustomPlan(cs[k]);
5413
+ }
5414
+ }
5415
+ }
5085
5416
 
5086
- /**
5087
- * Tell the spy to call through to the real implementation when invoked.
5088
- * @name Spy#and#callThrough
5089
- * @function
5090
- */
5091
- this.callThrough = function() {
5092
- plan = originalFn;
5093
- return getSpy();
5094
- };
5417
+ function createCustomPlan(factory) {
5418
+ return function() {
5419
+ var plan = factory.apply(null, arguments);
5095
5420
 
5096
- /**
5097
- * Tell the spy to return the value when invoked.
5098
- * @name Spy#and#returnValue
5099
- * @function
5100
- * @param {*} value The value to return.
5101
- */
5102
- this.returnValue = function(value) {
5103
- plan = function() {
5104
- return value;
5105
- };
5106
- return getSpy();
5421
+ if (!j$.isFunction_(plan)) {
5422
+ throw new Error('Spy strategy must return a function');
5423
+ }
5424
+
5425
+ this.plan = plan;
5426
+ return this.getSpy();
5107
5427
  };
5428
+ }
5108
5429
 
5109
- /**
5110
- * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
5111
- * @name Spy#and#returnValues
5112
- * @function
5113
- * @param {...*} values - Values to be returned on subsequent calls to the spy.
5114
- */
5115
- this.returnValues = function() {
5116
- var values = Array.prototype.slice.call(arguments);
5117
- plan = function () {
5118
- return values.shift();
5119
- };
5120
- return getSpy();
5430
+ /**
5431
+ * Execute the current spy strategy.
5432
+ * @name SpyStrategy#exec
5433
+ * @function
5434
+ */
5435
+ SpyStrategy.prototype.exec = function(context, args) {
5436
+ return this.plan.apply(context, args);
5437
+ };
5438
+
5439
+ /**
5440
+ * Tell the spy to call through to the real implementation when invoked.
5441
+ * @name SpyStrategy#callThrough
5442
+ * @function
5443
+ */
5444
+ SpyStrategy.prototype.callThrough = function() {
5445
+ this.plan = this.originalFn;
5446
+ return this.getSpy();
5447
+ };
5448
+
5449
+ /**
5450
+ * Tell the spy to return the value when invoked.
5451
+ * @name SpyStrategy#returnValue
5452
+ * @function
5453
+ * @param {*} value The value to return.
5454
+ */
5455
+ SpyStrategy.prototype.returnValue = function(value) {
5456
+ this.plan = function() {
5457
+ return value;
5121
5458
  };
5459
+ return this.getSpy();
5460
+ };
5122
5461
 
5123
- /**
5124
- * Tell the spy to throw an error when invoked.
5125
- * @name Spy#and#throwError
5126
- * @function
5127
- * @param {Error|String} something Thing to throw
5128
- */
5129
- this.throwError = function(something) {
5130
- var error = (something instanceof Error) ? something : new Error(something);
5131
- plan = function() {
5132
- throw error;
5133
- };
5134
- return getSpy();
5462
+ /**
5463
+ * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
5464
+ * @name SpyStrategy#returnValues
5465
+ * @function
5466
+ * @param {...*} values - Values to be returned on subsequent calls to the spy.
5467
+ */
5468
+ SpyStrategy.prototype.returnValues = function() {
5469
+ var values = Array.prototype.slice.call(arguments);
5470
+ this.plan = function () {
5471
+ return values.shift();
5135
5472
  };
5473
+ return this.getSpy();
5474
+ };
5136
5475
 
5137
- /**
5138
- * Tell the spy to call a fake implementation when invoked.
5139
- * @name Spy#and#callFake
5140
- * @function
5141
- * @param {Function} fn The function to invoke with the passed parameters.
5142
- */
5143
- this.callFake = function(fn) {
5144
- if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
5145
- throw new Error('Argument passed to callFake should be a function, got ' + fn);
5146
- }
5147
- plan = fn;
5148
- return getSpy();
5476
+ /**
5477
+ * Tell the spy to throw an error when invoked.
5478
+ * @name SpyStrategy#throwError
5479
+ * @function
5480
+ * @param {Error|String} something Thing to throw
5481
+ */
5482
+ SpyStrategy.prototype.throwError = function(something) {
5483
+ var error = (something instanceof Error) ? something : new Error(something);
5484
+ this.plan = function() {
5485
+ throw error;
5149
5486
  };
5487
+ return this.getSpy();
5488
+ };
5150
5489
 
5151
- /**
5152
- * Tell the spy to do nothing when invoked. This is the default.
5153
- * @name Spy#and#stub
5154
- * @function
5155
- */
5156
- this.stub = function(fn) {
5157
- plan = function() {};
5158
- return getSpy();
5490
+ /**
5491
+ * Tell the spy to call a fake implementation when invoked.
5492
+ * @name SpyStrategy#callFake
5493
+ * @function
5494
+ * @param {Function} fn The function to invoke with the passed parameters.
5495
+ */
5496
+ SpyStrategy.prototype.callFake = function(fn) {
5497
+ if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
5498
+ throw new Error('Argument passed to callFake should be a function, got ' + fn);
5499
+ }
5500
+ this.plan = fn;
5501
+ return this.getSpy();
5502
+ };
5503
+
5504
+ /**
5505
+ * Tell the spy to do nothing when invoked. This is the default.
5506
+ * @name SpyStrategy#stub
5507
+ * @function
5508
+ */
5509
+ SpyStrategy.prototype.stub = function(fn) {
5510
+ this.plan = function() {};
5511
+ return this.getSpy();
5512
+ };
5513
+
5514
+ SpyStrategy.prototype.isConfigured = function() {
5515
+ return this.plan !== this._defaultPlan;
5516
+ };
5517
+
5518
+ return SpyStrategy;
5519
+ };
5520
+
5521
+ getJasmineRequireObj().StackTrace = function(j$) {
5522
+ function StackTrace(rawTrace) {
5523
+ var lines = rawTrace
5524
+ .split('\n')
5525
+ .filter(function(line) { return line !== ''; });
5526
+
5527
+ if (lines[0].match(/^Error/)) {
5528
+ this.message = lines.shift();
5529
+ } else {
5530
+ this.message = undefined;
5531
+ }
5532
+
5533
+ var parseResult = tryParseFrames(lines);
5534
+ this.frames = parseResult.frames;
5535
+ this.style = parseResult.style;
5536
+ }
5537
+
5538
+ var framePatterns = [
5539
+ // PhantomJS on Linux, Node, Chrome, IE, Edge
5540
+ // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)"
5541
+ // Note that the "function name" can include a surprisingly large set of
5542
+ // characters, including angle brackets and square brackets.
5543
+ { re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, fnIx: 1, fileLineColIx: 2, style: 'v8' },
5544
+
5545
+ // NodeJS alternate form, often mixed in with the Chrome style
5546
+ // e.g. " at /some/path:4320:20
5547
+ { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' },
5548
+
5549
+ // PhantomJS on OS X, Safari, Firefox
5550
+ // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
5551
+ // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
5552
+ { re: /^(([^@\s]+)@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' }
5553
+ ];
5554
+
5555
+ // regexes should capture the function name (if any) as group 1
5556
+ // and the file, line, and column as group 2.
5557
+ function tryParseFrames(lines) {
5558
+ var style = null;
5559
+ var frames = lines.map(function(line) {
5560
+ var convertedLine = first(framePatterns, function(pattern) {
5561
+ var overallMatch = line.match(pattern.re),
5562
+ fileLineColMatch;
5563
+ if (!overallMatch) { return null; }
5564
+
5565
+ fileLineColMatch = overallMatch[pattern.fileLineColIx].match(
5566
+ /^(.*):(\d+):\d+$/);
5567
+ if (!fileLineColMatch) { return null; }
5568
+
5569
+ style = style || pattern.style;
5570
+ return {
5571
+ raw: line,
5572
+ file: fileLineColMatch[1],
5573
+ line: parseInt(fileLineColMatch[2], 10),
5574
+ func: overallMatch[pattern.fnIx]
5575
+ };
5576
+ });
5577
+
5578
+ return convertedLine || { raw: line };
5579
+ });
5580
+
5581
+ return {
5582
+ style: style,
5583
+ frames: frames
5159
5584
  };
5160
5585
  }
5161
5586
 
5162
- return SpyStrategy;
5587
+ function first(items, fn) {
5588
+ var i, result;
5589
+
5590
+ for (i = 0; i < items.length; i++) {
5591
+ result = fn(items[i]);
5592
+
5593
+ if (result) {
5594
+ return result;
5595
+ }
5596
+ }
5597
+ }
5598
+
5599
+ return StackTrace;
5163
5600
  };
5164
5601
 
5165
5602
  getJasmineRequireObj().Suite = function(j$) {
@@ -5231,6 +5668,19 @@ getJasmineRequireObj().Suite = function(j$) {
5231
5668
  this.afterAllFns.unshift(fn);
5232
5669
  };
5233
5670
 
5671
+ function removeFns(queueableFns) {
5672
+ for(var i = 0; i < queueableFns.length; i++) {
5673
+ queueableFns[i].fn = null;
5674
+ }
5675
+ }
5676
+
5677
+ Suite.prototype.cleanupBeforeAfter = function() {
5678
+ removeFns(this.beforeAllFns);
5679
+ removeFns(this.afterAllFns);
5680
+ removeFns(this.beforeFns);
5681
+ removeFns(this.afterFns);
5682
+ };
5683
+
5234
5684
  Suite.prototype.addChild = function(child) {
5235
5685
  this.children.push(child);
5236
5686
  };
@@ -5243,14 +5693,10 @@ getJasmineRequireObj().Suite = function(j$) {
5243
5693
  if (this.result.failedExpectations.length > 0) {
5244
5694
  return 'failed';
5245
5695
  } else {
5246
- return 'finished';
5696
+ return 'passed';
5247
5697
  }
5248
5698
  };
5249
5699
 
5250
- Suite.prototype.isExecutable = function() {
5251
- return !this.markedPending;
5252
- };
5253
-
5254
5700
  Suite.prototype.canBeReentered = function() {
5255
5701
  return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
5256
5702
  };
@@ -5277,39 +5723,29 @@ getJasmineRequireObj().Suite = function(j$) {
5277
5723
  return;
5278
5724
  }
5279
5725
 
5280
- if(isAfterAll(this.children)) {
5281
- var data = {
5282
- matcherName: '',
5283
- passed: false,
5284
- expected: '',
5285
- actual: '',
5286
- error: arguments[0]
5287
- };
5288
- this.result.failedExpectations.push(this.expectationResultFactory(data));
5289
- } else {
5290
- for (var i = 0; i < this.children.length; i++) {
5291
- var child = this.children[i];
5292
- child.onException.apply(child, arguments);
5293
- }
5726
+ var data = {
5727
+ matcherName: '',
5728
+ passed: false,
5729
+ expected: '',
5730
+ actual: '',
5731
+ error: arguments[0]
5732
+ };
5733
+ var failedExpectation = this.expectationResultFactory(data);
5734
+
5735
+ if (!this.parentSuite) {
5736
+ failedExpectation.globalErrorType = 'afterAll';
5294
5737
  }
5738
+
5739
+ this.result.failedExpectations.push(failedExpectation);
5295
5740
  };
5296
5741
 
5297
5742
  Suite.prototype.addExpectationResult = function () {
5298
- if(isAfterAll(this.children) && isFailure(arguments)){
5743
+ if(isFailure(arguments)) {
5299
5744
  var data = arguments[1];
5300
5745
  this.result.failedExpectations.push(this.expectationResultFactory(data));
5301
5746
  if(this.throwOnExpectationFailure) {
5302
5747
  throw new j$.errors.ExpectationFailed();
5303
5748
  }
5304
- } else {
5305
- for (var i = 0; i < this.children.length; i++) {
5306
- var child = this.children[i];
5307
- try {
5308
- child.addExpectationResult.apply(child, arguments);
5309
- } catch(e) {
5310
- // keep going
5311
- }
5312
- }
5313
5749
  }
5314
5750
  };
5315
5751
 
@@ -5317,10 +5753,6 @@ getJasmineRequireObj().Suite = function(j$) {
5317
5753
  this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg }));
5318
5754
  };
5319
5755
 
5320
- function isAfterAll(children) {
5321
- return children && children[0].result.status;
5322
- }
5323
-
5324
5756
  function isFailure(args) {
5325
5757
  return !args[0];
5326
5758
  }
@@ -5363,13 +5795,14 @@ getJasmineRequireObj().TreeProcessor = function() {
5363
5795
  nodeStart = attrs.nodeStart || function() {},
5364
5796
  nodeComplete = attrs.nodeComplete || function() {},
5365
5797
  orderChildren = attrs.orderChildren || function(node) { return node.children; },
5798
+ excludeNode = attrs.excludeNode || function(node) { return false; },
5366
5799
  stats = { valid: true },
5367
5800
  processed = false,
5368
5801
  defaultMin = Infinity,
5369
5802
  defaultMax = 1 - Infinity;
5370
5803
 
5371
5804
  this.processTree = function() {
5372
- processNode(tree, false);
5805
+ processNode(tree, true);
5373
5806
  processed = true;
5374
5807
  return stats;
5375
5808
  };
@@ -5403,18 +5836,18 @@ getJasmineRequireObj().TreeProcessor = function() {
5403
5836
  }
5404
5837
  }
5405
5838
 
5406
- function processNode(node, parentEnabled) {
5839
+ function processNode(node, parentExcluded) {
5407
5840
  var executableIndex = runnableIndex(node.id);
5408
5841
 
5409
5842
  if (executableIndex !== undefined) {
5410
- parentEnabled = true;
5843
+ parentExcluded = false;
5411
5844
  }
5412
5845
 
5413
- parentEnabled = parentEnabled && node.isExecutable();
5414
-
5415
5846
  if (!node.children) {
5847
+ var excluded = parentExcluded || excludeNode(node);
5416
5848
  stats[node.id] = {
5417
- executable: parentEnabled && node.isExecutable(),
5849
+ excluded: excluded,
5850
+ willExecute: !excluded && !node.markedPending,
5418
5851
  segments: [{
5419
5852
  index: 0,
5420
5853
  owner: node,
@@ -5431,7 +5864,7 @@ getJasmineRequireObj().TreeProcessor = function() {
5431
5864
  for (var i = 0; i < orderedChildren.length; i++) {
5432
5865
  var child = orderedChildren[i];
5433
5866
 
5434
- processNode(child, parentEnabled);
5867
+ processNode(child, parentExcluded);
5435
5868
 
5436
5869
  if (!stats.valid) {
5437
5870
  return;
@@ -5439,11 +5872,12 @@ getJasmineRequireObj().TreeProcessor = function() {
5439
5872
 
5440
5873
  var childStats = stats[child.id];
5441
5874
 
5442
- hasExecutableChild = hasExecutableChild || childStats.executable;
5875
+ hasExecutableChild = hasExecutableChild || childStats.willExecute;
5443
5876
  }
5444
5877
 
5445
5878
  stats[node.id] = {
5446
- executable: hasExecutableChild
5879
+ excluded: parentExcluded,
5880
+ willExecute: hasExecutableChild
5447
5881
  };
5448
5882
 
5449
5883
  segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
@@ -5521,16 +5955,20 @@ getJasmineRequireObj().TreeProcessor = function() {
5521
5955
  if (node.children) {
5522
5956
  return {
5523
5957
  fn: function(done) {
5524
- nodeStart(node);
5958
+ var onStart = {
5959
+ fn: function(next) {
5960
+ nodeStart(node, next);
5961
+ }
5962
+ };
5525
5963
 
5526
5964
  queueRunnerFactory({
5527
- onComplete: function() {
5528
- nodeComplete(node, node.getResult());
5529
- done();
5965
+ onComplete: function () {
5966
+ node.cleanupBeforeAfter();
5967
+ nodeComplete(node, node.getResult(), done);
5530
5968
  },
5531
- queueableFns: wrapChildren(node, segmentNumber),
5969
+ queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
5532
5970
  userContext: node.sharedUserContext(),
5533
- onException: function() {
5971
+ onException: function () {
5534
5972
  node.onException.apply(node, arguments);
5535
5973
  }
5536
5974
  });
@@ -5538,7 +5976,7 @@ getJasmineRequireObj().TreeProcessor = function() {
5538
5976
  };
5539
5977
  } else {
5540
5978
  return {
5541
- fn: function(done) { node.execute(done, stats[node.id].executable); }
5979
+ fn: function(done) { node.execute(done, stats[node.id].excluded); }
5542
5980
  };
5543
5981
  }
5544
5982
  }
@@ -5551,7 +5989,7 @@ getJasmineRequireObj().TreeProcessor = function() {
5551
5989
  result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
5552
5990
  }
5553
5991
 
5554
- if (!stats[node.id].executable) {
5992
+ if (!stats[node.id].willExecute) {
5555
5993
  return result;
5556
5994
  }
5557
5995
 
@@ -5582,5 +6020,5 @@ getJasmineRequireObj().UserContext = function(j$) {
5582
6020
  };
5583
6021
 
5584
6022
  getJasmineRequireObj().version = function() {
5585
- return '2.99.0';
6023
+ return '3.0.0';
5586
6024
  };