jasmine-core 2.99.2 → 3.0.0

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