jasmine-core 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/lib/console/console.js +54 -24
  3. data/lib/jasmine-core/__init__.py +1 -0
  4. data/lib/jasmine-core/boot/boot.js +2 -63
  5. data/lib/jasmine-core/boot/node_boot.js +19 -0
  6. data/lib/jasmine-core/boot.js +3 -64
  7. data/lib/jasmine-core/core.py +60 -0
  8. data/lib/jasmine-core/example/node_example/spec/PlayerSpec.js +60 -0
  9. data/lib/jasmine-core/example/node_example/spec/SpecHelper.js +15 -0
  10. data/lib/jasmine-core/example/node_example/src/Player.js +24 -0
  11. data/lib/jasmine-core/example/node_example/src/Song.js +9 -0
  12. data/lib/jasmine-core/jasmine-html.js +119 -74
  13. data/lib/jasmine-core/jasmine.css +61 -54
  14. data/lib/jasmine-core/jasmine.js +964 -456
  15. data/lib/jasmine-core/json2.js +73 -62
  16. data/lib/jasmine-core/node_boot.js +41 -0
  17. data/lib/jasmine-core/spec/console/ConsoleReporterSpec.js +52 -8
  18. data/lib/jasmine-core/spec/core/AnySpec.js +1 -0
  19. data/lib/jasmine-core/spec/core/ClockSpec.js +122 -18
  20. data/lib/jasmine-core/spec/core/DelayedFunctionSchedulerSpec.js +14 -1
  21. data/lib/jasmine-core/spec/core/EnvSpec.js +0 -63
  22. data/lib/jasmine-core/spec/core/ExceptionFormatterSpec.js +7 -0
  23. data/lib/jasmine-core/spec/core/ExceptionsSpec.js +2 -2
  24. data/lib/jasmine-core/spec/core/ExpectationSpec.js +46 -50
  25. data/lib/jasmine-core/spec/core/JsApiReporterSpec.js +37 -0
  26. data/lib/jasmine-core/spec/core/MockDateSpec.js +200 -0
  27. data/lib/jasmine-core/spec/core/ObjectContainingSpec.js +6 -0
  28. data/lib/jasmine-core/spec/core/PrettyPrintSpec.js +49 -12
  29. data/lib/jasmine-core/spec/core/QueueRunnerSpec.js +184 -60
  30. data/lib/jasmine-core/spec/core/SpecSpec.js +46 -108
  31. data/lib/jasmine-core/spec/core/SpyRegistrySpec.js +55 -0
  32. data/lib/jasmine-core/spec/core/SpySpec.js +10 -0
  33. data/lib/jasmine-core/spec/core/SpyStrategySpec.js +13 -0
  34. data/lib/jasmine-core/spec/core/SuiteSpec.js +143 -11
  35. data/lib/jasmine-core/spec/core/TimerSpec.js +18 -0
  36. data/lib/jasmine-core/spec/core/integration/CustomMatchersSpec.js +34 -32
  37. data/lib/jasmine-core/spec/core/integration/EnvSpec.js +998 -50
  38. data/lib/jasmine-core/spec/core/integration/SpecRunningSpec.js +279 -3
  39. data/lib/jasmine-core/spec/core/matchers/matchersUtilSpec.js +18 -1
  40. data/lib/jasmine-core/spec/core/matchers/toBeGreaterThanSpec.js +2 -1
  41. data/lib/jasmine-core/spec/core/matchers/toBeNaNSpec.js +3 -2
  42. data/lib/jasmine-core/spec/core/matchers/toBeUndefinedSpec.js +2 -1
  43. data/lib/jasmine-core/spec/core/matchers/toContainSpec.js +4 -2
  44. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledSpec.js +2 -1
  45. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledWithSpec.js +17 -3
  46. data/lib/jasmine-core/spec/core/matchers/toThrowErrorSpec.js +14 -14
  47. data/lib/jasmine-core/spec/core/matchers/toThrowSpec.js +5 -5
  48. data/lib/jasmine-core/spec/helpers/defineJasmineUnderTest.js +7 -0
  49. data/lib/jasmine-core/spec/helpers/nodeDefineJasmineUnderTest.js +33 -0
  50. data/lib/jasmine-core/spec/html/HtmlReporterSpec.js +183 -35
  51. data/lib/jasmine-core/spec/html/PrettyPrintHtmlSpec.js +1 -1
  52. data/lib/jasmine-core/spec/node_suite.js +9 -1
  53. data/lib/jasmine-core/spec/npmPackage/npmPackageSpec.js +104 -0
  54. data/lib/jasmine-core/spec/performance/large_object_test.js +36 -0
  55. data/lib/jasmine-core/version.rb +1 -1
  56. data/lib/jasmine-core.js +37 -0
  57. data/lib/jasmine-core.rb +6 -2
  58. metadata +23 -9
  59. data/lib/jasmine-core/spec/support/dev_boot.js +0 -124
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (c) 2008-2013 Pivotal Labs
2
+ Copyright (c) 2008-2014 Pivotal Labs
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
@@ -20,64 +20,74 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
20
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
- function getJasmineRequireObj() {
24
- if (typeof module !== "undefined" && module.exports) {
25
- return exports;
23
+ getJasmineRequireObj = (function (jasmineGlobal) {
24
+ var jasmineRequire;
25
+
26
+ if (typeof module !== 'undefined' && module.exports) {
27
+ jasmineGlobal = global;
28
+ jasmineRequire = exports;
26
29
  } else {
27
- window.jasmineRequire = window.jasmineRequire || {};
28
- return window.jasmineRequire;
30
+ jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {};
29
31
  }
30
- }
31
32
 
32
- getJasmineRequireObj().core = function(jRequire) {
33
- var j$ = {};
34
-
35
- jRequire.base(j$);
36
- j$.util = jRequire.util();
37
- j$.Any = jRequire.Any();
38
- j$.CallTracker = jRequire.CallTracker();
39
- j$.Clock = jRequire.Clock();
40
- j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
41
- j$.Env = jRequire.Env(j$);
42
- j$.ExceptionFormatter = jRequire.ExceptionFormatter();
43
- j$.Expectation = jRequire.Expectation();
44
- j$.buildExpectationResult = jRequire.buildExpectationResult();
45
- j$.JsApiReporter = jRequire.JsApiReporter();
46
- j$.matchersUtil = jRequire.matchersUtil(j$);
47
- j$.ObjectContaining = jRequire.ObjectContaining(j$);
48
- j$.pp = jRequire.pp(j$);
49
- j$.QueueRunner = jRequire.QueueRunner();
50
- j$.ReportDispatcher = jRequire.ReportDispatcher();
51
- j$.Spec = jRequire.Spec(j$);
52
- j$.SpyStrategy = jRequire.SpyStrategy();
53
- j$.Suite = jRequire.Suite();
54
- j$.Timer = jRequire.Timer();
55
- j$.version = jRequire.version();
56
-
57
- j$.matchers = jRequire.requireMatchers(jRequire, j$);
58
-
59
- return j$;
60
- };
33
+ function getJasmineRequire() {
34
+ return jasmineRequire;
35
+ }
36
+
37
+ getJasmineRequire().core = function(jRequire) {
38
+ var j$ = {};
39
+
40
+ jRequire.base(j$, jasmineGlobal);
41
+ j$.util = jRequire.util();
42
+ j$.Any = jRequire.Any();
43
+ j$.CallTracker = jRequire.CallTracker();
44
+ j$.MockDate = jRequire.MockDate();
45
+ j$.Clock = jRequire.Clock();
46
+ j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
47
+ j$.Env = jRequire.Env(j$);
48
+ j$.ExceptionFormatter = jRequire.ExceptionFormatter();
49
+ j$.Expectation = jRequire.Expectation();
50
+ j$.buildExpectationResult = jRequire.buildExpectationResult();
51
+ j$.JsApiReporter = jRequire.JsApiReporter();
52
+ j$.matchersUtil = jRequire.matchersUtil(j$);
53
+ j$.ObjectContaining = jRequire.ObjectContaining(j$);
54
+ j$.pp = jRequire.pp(j$);
55
+ j$.QueueRunner = jRequire.QueueRunner(j$);
56
+ j$.ReportDispatcher = jRequire.ReportDispatcher();
57
+ j$.Spec = jRequire.Spec(j$);
58
+ j$.SpyRegistry = jRequire.SpyRegistry(j$);
59
+ j$.SpyStrategy = jRequire.SpyStrategy();
60
+ j$.Suite = jRequire.Suite();
61
+ j$.Timer = jRequire.Timer();
62
+ j$.version = jRequire.version();
63
+
64
+ j$.matchers = jRequire.requireMatchers(jRequire, j$);
65
+
66
+ return j$;
67
+ };
68
+
69
+ return getJasmineRequire;
70
+ })(this);
61
71
 
62
72
  getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
63
73
  var availableMatchers = [
64
- "toBe",
65
- "toBeCloseTo",
66
- "toBeDefined",
67
- "toBeFalsy",
68
- "toBeGreaterThan",
69
- "toBeLessThan",
70
- "toBeNaN",
71
- "toBeNull",
72
- "toBeTruthy",
73
- "toBeUndefined",
74
- "toContain",
75
- "toEqual",
76
- "toHaveBeenCalled",
77
- "toHaveBeenCalledWith",
78
- "toMatch",
79
- "toThrow",
80
- "toThrowError"
74
+ 'toBe',
75
+ 'toBeCloseTo',
76
+ 'toBeDefined',
77
+ 'toBeFalsy',
78
+ 'toBeGreaterThan',
79
+ 'toBeLessThan',
80
+ 'toBeNaN',
81
+ 'toBeNull',
82
+ 'toBeTruthy',
83
+ 'toBeUndefined',
84
+ 'toContain',
85
+ 'toEqual',
86
+ 'toHaveBeenCalled',
87
+ 'toHaveBeenCalledWith',
88
+ 'toMatch',
89
+ 'toThrow',
90
+ 'toThrowError'
81
91
  ],
82
92
  matchers = {};
83
93
 
@@ -89,20 +99,18 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
89
99
  return matchers;
90
100
  };
91
101
 
92
- getJasmineRequireObj().base = function(j$) {
102
+ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
93
103
  j$.unimplementedMethod_ = function() {
94
- throw new Error("unimplemented method");
104
+ throw new Error('unimplemented method');
95
105
  };
96
106
 
97
107
  j$.MAX_PRETTY_PRINT_DEPTH = 40;
108
+ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
98
109
  j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
99
110
 
100
- j$.getGlobal = (function() {
101
- var jasmineGlobal = eval.call(null, "this");
102
- return function() {
103
- return jasmineGlobal;
104
- };
105
- })();
111
+ j$.getGlobal = function() {
112
+ return jasmineGlobal;
113
+ };
106
114
 
107
115
  j$.getEnv = function(options) {
108
116
  var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
@@ -111,15 +119,15 @@ getJasmineRequireObj().base = function(j$) {
111
119
  };
112
120
 
113
121
  j$.isArray_ = function(value) {
114
- return j$.isA_("Array", value);
122
+ return j$.isA_('Array', value);
115
123
  };
116
124
 
117
125
  j$.isString_ = function(value) {
118
- return j$.isA_("String", value);
126
+ return j$.isA_('String', value);
119
127
  };
120
128
 
121
129
  j$.isNumber_ = function(value) {
122
- return j$.isA_("Number", value);
130
+ return j$.isA_('Number', value);
123
131
  };
124
132
 
125
133
  j$.isA_ = function(typeName, value) {
@@ -147,16 +155,21 @@ getJasmineRequireObj().base = function(j$) {
147
155
  }),
148
156
  callTracker = new j$.CallTracker(),
149
157
  spy = function() {
150
- callTracker.track({
158
+ var callData = {
151
159
  object: this,
152
160
  args: Array.prototype.slice.apply(arguments)
153
- });
154
- return spyStrategy.exec.apply(this, arguments);
161
+ };
162
+
163
+ callTracker.track(callData);
164
+ var returnValue = spyStrategy.exec.apply(this, arguments);
165
+ callData.returnValue = returnValue;
166
+
167
+ return returnValue;
155
168
  };
156
169
 
157
170
  for (var prop in originalFn) {
158
171
  if (prop === 'and' || prop === 'calls') {
159
- throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
172
+ throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
160
173
  }
161
174
 
162
175
  spy[prop] = originalFn[prop];
@@ -178,7 +191,7 @@ getJasmineRequireObj().base = function(j$) {
178
191
 
179
192
  j$.createSpyObj = function(baseName, methodNames) {
180
193
  if (!j$.isArray_(methodNames) || methodNames.length === 0) {
181
- throw "createSpyObj requires a non-empty array of method names to create spies for";
194
+ throw 'createSpyObj requires a non-empty array of method names to create spies for';
182
195
  }
183
196
  var obj = {};
184
197
  for (var i = 0; i < methodNames.length; i++) {
@@ -220,6 +233,31 @@ getJasmineRequireObj().util = function() {
220
233
  return obj === void 0;
221
234
  };
222
235
 
236
+ util.arrayContains = function(array, search) {
237
+ var i = array.length;
238
+ while (i--) {
239
+ if (array[i] === search) {
240
+ return true;
241
+ }
242
+ }
243
+ return false;
244
+ };
245
+
246
+ util.clone = function(obj) {
247
+ if (Object.prototype.toString.apply(obj) === '[object Array]') {
248
+ return obj.slice();
249
+ }
250
+
251
+ var cloned = {};
252
+ for (var prop in obj) {
253
+ if (obj.hasOwnProperty(prop)) {
254
+ cloned[prop] = obj[prop];
255
+ }
256
+ }
257
+
258
+ return cloned;
259
+ };
260
+
223
261
  return util;
224
262
  };
225
263
 
@@ -229,19 +267,16 @@ getJasmineRequireObj().Spec = function(j$) {
229
267
  this.resultCallback = attrs.resultCallback || function() {};
230
268
  this.id = attrs.id;
231
269
  this.description = attrs.description || '';
232
- this.fn = attrs.fn;
233
- this.beforeFns = attrs.beforeFns || function() { return []; };
234
- this.afterFns = attrs.afterFns || function() { return []; };
270
+ this.queueableFn = attrs.queueableFn;
271
+ this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
272
+ this.userContext = attrs.userContext || function() { return {}; };
235
273
  this.onStart = attrs.onStart || function() {};
236
- this.exceptionFormatter = attrs.exceptionFormatter || function() {};
237
274
  this.getSpecName = attrs.getSpecName || function() { return ''; };
238
275
  this.expectationResultFactory = attrs.expectationResultFactory || function() { };
239
276
  this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
240
277
  this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
241
278
 
242
- this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
243
-
244
- if (!this.fn) {
279
+ if (!this.queueableFn.fn) {
245
280
  this.pend();
246
281
  }
247
282
 
@@ -249,15 +284,18 @@ getJasmineRequireObj().Spec = function(j$) {
249
284
  id: this.id,
250
285
  description: this.description,
251
286
  fullName: this.getFullName(),
252
- failedExpectations: []
287
+ failedExpectations: [],
288
+ passedExpectations: []
253
289
  };
254
290
  }
255
291
 
256
292
  Spec.prototype.addExpectationResult = function(passed, data) {
293
+ var expectationResult = this.expectationResultFactory(data);
257
294
  if (passed) {
258
- return;
295
+ this.result.passedExpectations.push(expectationResult);
296
+ } else {
297
+ this.result.failedExpectations.push(expectationResult);
259
298
  }
260
- this.result.failedExpectations.push(this.expectationResultFactory(data));
261
299
  };
262
300
 
263
301
  Spec.prototype.expect = function(actual) {
@@ -265,8 +303,7 @@ getJasmineRequireObj().Spec = function(j$) {
265
303
  };
266
304
 
267
305
  Spec.prototype.execute = function(onComplete) {
268
- var self = this,
269
- timeout;
306
+ var self = this;
270
307
 
271
308
  this.onStart(this);
272
309
 
@@ -275,56 +312,16 @@ getJasmineRequireObj().Spec = function(j$) {
275
312
  return;
276
313
  }
277
314
 
278
- function timeoutable(fn) {
279
- return function(done) {
280
- timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
281
- onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
282
- done();
283
- }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
284
-
285
- var callDone = function() {
286
- clearTimeoutable();
287
- done();
288
- };
289
-
290
- fn.call(this, callDone); //TODO: do we care about more than 1 arg?
291
- };
292
- }
293
-
294
- function clearTimeoutable() {
295
- Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
296
- timeout = void 0;
297
- }
298
-
299
- var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()),
300
- allTimeoutableFns = [];
301
- for (var i = 0; i < allFns.length; i++) {
302
- var fn = allFns[i];
303
- allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn);
304
- }
315
+ var fns = this.beforeAndAfterFns();
316
+ var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
305
317
 
306
318
  this.queueRunnerFactory({
307
- fns: allTimeoutableFns,
308
- onException: onException,
309
- onComplete: complete
319
+ queueableFns: allFns,
320
+ onException: function() { self.onException.apply(self, arguments); },
321
+ onComplete: complete,
322
+ userContext: this.userContext()
310
323
  });
311
324
 
312
- function onException(e) {
313
- clearTimeoutable();
314
- if (Spec.isPendingSpecException(e)) {
315
- self.pend();
316
- return;
317
- }
318
-
319
- self.addExpectationResult(false, {
320
- matcherName: "",
321
- passed: false,
322
- expected: "",
323
- actual: "",
324
- error: e
325
- });
326
- }
327
-
328
325
  function complete() {
329
326
  self.result.status = self.status();
330
327
  self.resultCallback(self.result);
@@ -335,6 +332,21 @@ getJasmineRequireObj().Spec = function(j$) {
335
332
  }
336
333
  };
337
334
 
335
+ Spec.prototype.onException = function onException(e) {
336
+ if (Spec.isPendingSpecException(e)) {
337
+ this.pend();
338
+ return;
339
+ }
340
+
341
+ this.addExpectationResult(false, {
342
+ matcherName: '',
343
+ passed: false,
344
+ expected: '',
345
+ actual: '',
346
+ error: e
347
+ });
348
+ };
349
+
338
350
  Spec.prototype.disable = function() {
339
351
  this.disabled = true;
340
352
  };
@@ -359,20 +371,24 @@ getJasmineRequireObj().Spec = function(j$) {
359
371
  }
360
372
  };
361
373
 
374
+ Spec.prototype.isExecutable = function() {
375
+ return !this.disabled && !this.markedPending;
376
+ };
377
+
362
378
  Spec.prototype.getFullName = function() {
363
379
  return this.getSpecName(this);
364
380
  };
365
381
 
366
- Spec.pendingSpecExceptionMessage = "=> marked Pending";
382
+ Spec.pendingSpecExceptionMessage = '=> marked Pending';
367
383
 
368
384
  Spec.isPendingSpecException = function(e) {
369
- return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1;
385
+ return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1);
370
386
  };
371
387
 
372
388
  return Spec;
373
389
  };
374
390
 
375
- if (typeof window == void 0 && typeof exports == "object") {
391
+ if (typeof window == void 0 && typeof exports == 'object') {
376
392
  exports.Spec = jasmineRequire.Spec;
377
393
  }
378
394
 
@@ -389,33 +405,51 @@ getJasmineRequireObj().Env = function(j$) {
389
405
 
390
406
  var realSetTimeout = j$.getGlobal().setTimeout;
391
407
  var realClearTimeout = j$.getGlobal().clearTimeout;
392
- this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
408
+ this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
393
409
 
394
410
  var runnableLookupTable = {};
395
-
396
- var spies = [];
411
+ var runnableResources = {};
397
412
 
398
413
  var currentSpec = null;
399
- var currentSuite = null;
414
+ var currentlyExecutingSuites = [];
415
+ var currentDeclarationSuite = null;
416
+
417
+ var currentSuite = function() {
418
+ return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
419
+ };
420
+
421
+ var currentRunnable = function() {
422
+ return currentSpec || currentSuite();
423
+ };
400
424
 
401
425
  var reporter = new j$.ReportDispatcher([
402
- "jasmineStarted",
403
- "jasmineDone",
404
- "suiteStarted",
405
- "suiteDone",
406
- "specStarted",
407
- "specDone"
426
+ 'jasmineStarted',
427
+ 'jasmineDone',
428
+ 'suiteStarted',
429
+ 'suiteDone',
430
+ 'specStarted',
431
+ 'specDone'
408
432
  ]);
409
433
 
410
434
  this.specFilter = function() {
411
435
  return true;
412
436
  };
413
437
 
414
- var equalityTesters = [];
415
-
416
- var customEqualityTesters = [];
417
438
  this.addCustomEqualityTester = function(tester) {
418
- customEqualityTesters.push(tester);
439
+ if(!currentRunnable()) {
440
+ throw new Error('Custom Equalities must be added in a before function or a spec');
441
+ }
442
+ runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
443
+ };
444
+
445
+ this.addMatchers = function(matchersToAdd) {
446
+ if(!currentRunnable()) {
447
+ throw new Error('Matchers must be added in a before function or a spec');
448
+ }
449
+ var customMatchers = runnableResources[currentRunnable().id].customMatchers;
450
+ for (var matcherName in matchersToAdd) {
451
+ customMatchers[matcherName] = matchersToAdd[matcherName];
452
+ }
419
453
  };
420
454
 
421
455
  j$.Expectation.addCoreMatchers(j$.matchers);
@@ -433,7 +467,8 @@ getJasmineRequireObj().Env = function(j$) {
433
467
  var expectationFactory = function(actual, spec) {
434
468
  return j$.Expectation.Factory({
435
469
  util: j$.matchersUtil,
436
- customEqualityTesters: customEqualityTesters,
470
+ customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
471
+ customMatchers: runnableResources[spec.id].customMatchers,
437
472
  actual: actual,
438
473
  addExpectationResult: addExpectationResult
439
474
  });
@@ -443,30 +478,44 @@ getJasmineRequireObj().Env = function(j$) {
443
478
  }
444
479
  };
445
480
 
446
- var specStarted = function(spec) {
447
- currentSpec = spec;
448
- reporter.specStarted(spec.result);
481
+ var defaultResourcesForRunnable = function(id, parentRunnableId) {
482
+ var resources = {spies: [], customEqualityTesters: [], customMatchers: {}};
483
+
484
+ if(runnableResources[parentRunnableId]){
485
+ resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
486
+ resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
487
+ }
488
+
489
+ runnableResources[id] = resources;
449
490
  };
450
491
 
451
- var beforeFns = function(suite) {
452
- return function() {
453
- var befores = [];
454
- while(suite) {
455
- befores = befores.concat(suite.beforeFns);
456
- suite = suite.parentSuite;
457
- }
458
- return befores.reverse();
459
- };
492
+ var clearResourcesForRunnable = function(id) {
493
+ spyRegistry.clearSpies();
494
+ delete runnableResources[id];
460
495
  };
461
496
 
462
- var afterFns = function(suite) {
497
+ var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
463
498
  return function() {
464
- var afters = [];
499
+ var befores = [],
500
+ afters = [],
501
+ beforeAlls = [],
502
+ afterAlls = [];
503
+
465
504
  while(suite) {
505
+ befores = befores.concat(suite.beforeFns);
466
506
  afters = afters.concat(suite.afterFns);
507
+
508
+ if (runnablesExplictlySet()) {
509
+ beforeAlls = beforeAlls.concat(suite.beforeAllFns);
510
+ afterAlls = afterAlls.concat(suite.afterAllFns);
511
+ }
512
+
467
513
  suite = suite.parentSuite;
468
514
  }
469
- return afters;
515
+ return {
516
+ befores: beforeAlls.reverse().concat(befores.reverse()),
517
+ afters: afters.concat(afterAlls)
518
+ };
470
519
  };
471
520
  };
472
521
 
@@ -514,6 +563,8 @@ getJasmineRequireObj().Env = function(j$) {
514
563
  var queueRunnerFactory = function(options) {
515
564
  options.catchException = catchException;
516
565
  options.clearStack = options.clearStack || clearStack;
566
+ options.timer = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
567
+ options.fail = self.fail;
517
568
 
518
569
  new j$.QueueRunner(options).execute();
519
570
  };
@@ -523,65 +574,57 @@ getJasmineRequireObj().Env = function(j$) {
523
574
  id: getNextSuiteId(),
524
575
  description: 'Jasmine__TopLevel__Suite',
525
576
  queueRunner: queueRunnerFactory,
526
- resultCallback: function() {} // TODO - hook this up
577
+ onStart: function(suite) {
578
+ reporter.suiteStarted(suite.result);
579
+ },
580
+ resultCallback: function(attrs) {
581
+ reporter.suiteDone(attrs);
582
+ }
527
583
  });
528
584
  runnableLookupTable[topSuite.id] = topSuite;
529
- currentSuite = topSuite;
585
+ defaultResourcesForRunnable(topSuite.id);
586
+ currentDeclarationSuite = topSuite;
530
587
 
531
588
  this.topSuite = function() {
532
589
  return topSuite;
533
590
  };
534
591
 
535
592
  this.execute = function(runnablesToRun) {
536
- runnablesToRun = runnablesToRun || [topSuite.id];
593
+ if(runnablesToRun) {
594
+ runnablesExplictlySet = true;
595
+ } else if (focusedRunnables.length) {
596
+ runnablesExplictlySet = true;
597
+ runnablesToRun = focusedRunnables;
598
+ } else {
599
+ runnablesToRun = [topSuite.id];
600
+ }
537
601
 
538
602
  var allFns = [];
539
603
  for(var i = 0; i < runnablesToRun.length; i++) {
540
604
  var runnable = runnableLookupTable[runnablesToRun[i]];
541
- allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
605
+ allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
542
606
  }
543
607
 
544
608
  reporter.jasmineStarted({
545
609
  totalSpecsDefined: totalSpecsDefined
546
610
  });
547
611
 
548
- queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
612
+ queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
549
613
  };
550
614
 
551
615
  this.addReporter = function(reporterToAdd) {
552
616
  reporter.addReporter(reporterToAdd);
553
617
  };
554
618
 
555
- this.addMatchers = function(matchersToAdd) {
556
- j$.Expectation.addMatchers(matchersToAdd);
557
- };
558
-
559
- this.spyOn = function(obj, methodName) {
560
- if (j$.util.isUndefined(obj)) {
561
- throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
619
+ var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
620
+ if(!currentRunnable()) {
621
+ throw new Error('Spies must be created in a before function or a spec');
562
622
  }
623
+ return runnableResources[currentRunnable().id].spies;
624
+ }});
563
625
 
564
- if (j$.util.isUndefined(obj[methodName])) {
565
- throw new Error(methodName + '() method does not exist');
566
- }
567
-
568
- if (obj[methodName] && j$.isSpy(obj[methodName])) {
569
- //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
570
- throw new Error(methodName + ' has already been spied upon');
571
- }
572
-
573
- var spy = j$.createSpy(methodName, obj[methodName]);
574
-
575
- spies.push({
576
- spy: spy,
577
- baseObj: obj,
578
- methodName: methodName,
579
- originalValue: obj[methodName]
580
- });
581
-
582
- obj[methodName] = spy;
583
-
584
- return spy;
626
+ this.spyOn = function() {
627
+ return spyRegistry.spyOn.apply(spyRegistry, arguments);
585
628
  };
586
629
 
587
630
  var suiteFactory = function(description) {
@@ -589,24 +632,59 @@ getJasmineRequireObj().Env = function(j$) {
589
632
  env: self,
590
633
  id: getNextSuiteId(),
591
634
  description: description,
592
- parentSuite: currentSuite,
635
+ parentSuite: currentDeclarationSuite,
593
636
  queueRunner: queueRunnerFactory,
594
637
  onStart: suiteStarted,
638
+ expectationFactory: expectationFactory,
639
+ expectationResultFactory: expectationResultFactory,
595
640
  resultCallback: function(attrs) {
641
+ if (!suite.disabled) {
642
+ clearResourcesForRunnable(suite.id);
643
+ currentlyExecutingSuites.pop();
644
+ }
596
645
  reporter.suiteDone(attrs);
597
646
  }
598
647
  });
599
648
 
600
649
  runnableLookupTable[suite.id] = suite;
601
650
  return suite;
651
+
652
+ function suiteStarted(suite) {
653
+ currentlyExecutingSuites.push(suite);
654
+ defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
655
+ reporter.suiteStarted(suite.result);
656
+ }
602
657
  };
603
658
 
604
659
  this.describe = function(description, specDefinitions) {
605
660
  var suite = suiteFactory(description);
661
+ addSpecsToSuite(suite, specDefinitions);
662
+ return suite;
663
+ };
664
+
665
+ this.xdescribe = function(description, specDefinitions) {
666
+ var suite = this.describe(description, specDefinitions);
667
+ suite.disable();
668
+ return suite;
669
+ };
670
+
671
+ var focusedRunnables = [];
672
+
673
+ this.fdescribe = function(description, specDefinitions) {
674
+ var suite = suiteFactory(description);
675
+ suite.isFocused = true;
676
+
677
+ focusedRunnables.push(suite.id);
678
+ unfocusAncestor();
679
+ addSpecsToSuite(suite, specDefinitions);
606
680
 
607
- var parentSuite = currentSuite;
681
+ return suite;
682
+ };
683
+
684
+ function addSpecsToSuite(suite, specDefinitions) {
685
+ var parentSuite = currentDeclarationSuite;
608
686
  parentSuite.addChild(suite);
609
- currentSuite = suite;
687
+ currentDeclarationSuite = suite;
610
688
 
611
689
  var declarationError = null;
612
690
  try {
@@ -616,31 +694,49 @@ getJasmineRequireObj().Env = function(j$) {
616
694
  }
617
695
 
618
696
  if (declarationError) {
619
- this.it("encountered a declaration exception", function() {
697
+ self.it('encountered a declaration exception', function() {
620
698
  throw declarationError;
621
699
  });
622
700
  }
623
701
 
624
- currentSuite = parentSuite;
702
+ currentDeclarationSuite = parentSuite;
703
+ }
625
704
 
626
- return suite;
627
- };
705
+ function findFocusedAncestor(suite) {
706
+ while (suite) {
707
+ if (suite.isFocused) {
708
+ return suite.id;
709
+ }
710
+ suite = suite.parentSuite;
711
+ }
628
712
 
629
- this.xdescribe = function(description, specDefinitions) {
630
- var suite = this.describe(description, specDefinitions);
631
- suite.disable();
632
- return suite;
713
+ return null;
714
+ }
715
+
716
+ function unfocusAncestor() {
717
+ var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
718
+ if (focusedAncestor) {
719
+ for (var i = 0; i < focusedRunnables.length; i++) {
720
+ if (focusedRunnables[i] === focusedAncestor) {
721
+ focusedRunnables.splice(i, 1);
722
+ break;
723
+ }
724
+ }
725
+ }
726
+ }
727
+
728
+ var runnablesExplictlySet = false;
729
+
730
+ var runnablesExplictlySetGetter = function(){
731
+ return runnablesExplictlySet;
633
732
  };
634
733
 
635
- var specFactory = function(description, fn, suite) {
734
+ var specFactory = function(description, fn, suite, timeout) {
636
735
  totalSpecsDefined++;
637
-
638
736
  var spec = new j$.Spec({
639
737
  id: getNextSpecId(),
640
- beforeFns: beforeFns(suite),
641
- afterFns: afterFns(suite),
738
+ beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
642
739
  expectationFactory: expectationFactory,
643
- exceptionFormatter: exceptionFormatter,
644
740
  resultCallback: specResultCallback,
645
741
  getSpecName: function(spec) {
646
742
  return getSpecName(spec, suite);
@@ -649,8 +745,11 @@ getJasmineRequireObj().Env = function(j$) {
649
745
  description: description,
650
746
  expectationResultFactory: expectationResultFactory,
651
747
  queueRunnerFactory: queueRunnerFactory,
652
- fn: fn,
653
- timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
748
+ userContext: function() { return suite.clonedSharedUserContext(); },
749
+ queueableFn: {
750
+ fn: fn,
751
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
752
+ }
654
753
  });
655
754
 
656
755
  runnableLookupTable[spec.id] = spec;
@@ -661,54 +760,94 @@ getJasmineRequireObj().Env = function(j$) {
661
760
 
662
761
  return spec;
663
762
 
664
- function removeAllSpies() {
665
- for (var i = 0; i < spies.length; i++) {
666
- var spyEntry = spies[i];
667
- spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
668
- }
669
- spies = [];
670
- }
671
-
672
763
  function specResultCallback(result) {
673
- removeAllSpies();
674
- j$.Expectation.resetMatchers();
675
- customEqualityTesters = [];
764
+ clearResourcesForRunnable(spec.id);
676
765
  currentSpec = null;
677
766
  reporter.specDone(result);
678
767
  }
679
- };
680
768
 
681
- var suiteStarted = function(suite) {
682
- reporter.suiteStarted(suite.result);
769
+ function specStarted(spec) {
770
+ currentSpec = spec;
771
+ defaultResourcesForRunnable(spec.id, suite.id);
772
+ reporter.specStarted(spec.result);
773
+ }
683
774
  };
684
775
 
685
- this.it = function(description, fn) {
686
- var spec = specFactory(description, fn, currentSuite);
687
- currentSuite.addChild(spec);
776
+ this.it = function(description, fn, timeout) {
777
+ var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
778
+ currentDeclarationSuite.addChild(spec);
688
779
  return spec;
689
780
  };
690
781
 
691
- this.xit = function(description, fn) {
692
- var spec = this.it(description, fn);
782
+ this.xit = function() {
783
+ var spec = this.it.apply(this, arguments);
693
784
  spec.pend();
694
785
  return spec;
695
786
  };
696
787
 
788
+ this.fit = function(){
789
+ var spec = this.it.apply(this, arguments);
790
+
791
+ focusedRunnables.push(spec.id);
792
+ unfocusAncestor();
793
+ return spec;
794
+ };
795
+
697
796
  this.expect = function(actual) {
698
- return currentSpec.expect(actual);
797
+ if (!currentRunnable()) {
798
+ throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
799
+ }
800
+
801
+ return currentRunnable().expect(actual);
699
802
  };
700
803
 
701
- this.beforeEach = function(beforeEachFunction) {
702
- currentSuite.beforeEach(beforeEachFunction);
804
+ this.beforeEach = function(beforeEachFunction, timeout) {
805
+ currentDeclarationSuite.beforeEach({
806
+ fn: beforeEachFunction,
807
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
808
+ });
703
809
  };
704
810
 
705
- this.afterEach = function(afterEachFunction) {
706
- currentSuite.afterEach(afterEachFunction);
811
+ this.beforeAll = function(beforeAllFunction, timeout) {
812
+ currentDeclarationSuite.beforeAll({
813
+ fn: beforeAllFunction,
814
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
815
+ });
816
+ };
817
+
818
+ this.afterEach = function(afterEachFunction, timeout) {
819
+ currentDeclarationSuite.afterEach({
820
+ fn: afterEachFunction,
821
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
822
+ });
823
+ };
824
+
825
+ this.afterAll = function(afterAllFunction, timeout) {
826
+ currentDeclarationSuite.afterAll({
827
+ fn: afterAllFunction,
828
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
829
+ });
707
830
  };
708
831
 
709
832
  this.pending = function() {
710
833
  throw j$.Spec.pendingSpecExceptionMessage;
711
834
  };
835
+
836
+ this.fail = function(error) {
837
+ var message = 'Failed';
838
+ if (error) {
839
+ message += ': ';
840
+ message += error.message || error;
841
+ }
842
+
843
+ currentRunnable().addExpectationResult(false, {
844
+ matcherName: '',
845
+ passed: false,
846
+ expected: '',
847
+ actual: '',
848
+ message: message
849
+ });
850
+ };
712
851
  }
713
852
 
714
853
  return Env;
@@ -723,7 +862,7 @@ getJasmineRequireObj().JsApiReporter = function() {
723
862
 
724
863
  function JsApiReporter(options) {
725
864
  var timer = options.timer || noopTimer,
726
- status = "loaded";
865
+ status = 'loaded';
727
866
 
728
867
  this.started = false;
729
868
  this.finished = false;
@@ -746,26 +885,31 @@ getJasmineRequireObj().JsApiReporter = function() {
746
885
  return status;
747
886
  };
748
887
 
749
- var suites = {};
888
+ var suites = [],
889
+ suites_hash = {};
750
890
 
751
891
  this.suiteStarted = function(result) {
752
- storeSuite(result);
892
+ suites_hash[result.id] = result;
753
893
  };
754
894
 
755
895
  this.suiteDone = function(result) {
756
896
  storeSuite(result);
757
897
  };
758
898
 
899
+ this.suiteResults = function(index, length) {
900
+ return suites.slice(index, index + length);
901
+ };
902
+
759
903
  function storeSuite(result) {
760
- suites[result.id] = result;
904
+ suites.push(result);
905
+ suites_hash[result.id] = result;
761
906
  }
762
907
 
763
908
  this.suites = function() {
764
- return suites;
909
+ return suites_hash;
765
910
  };
766
911
 
767
912
  var specs = [];
768
- this.specStarted = function(result) { };
769
913
 
770
914
  this.specDone = function(result) {
771
915
  specs.push(result);
@@ -819,7 +963,7 @@ getJasmineRequireObj().Any = function() {
819
963
  };
820
964
 
821
965
  Any.prototype.jasmineToString = function() {
822
- return '<jasmine.any(' + this.expectedClass + ')>';
966
+ return '<jasmine.any(' + this.expectedObject + ')>';
823
967
  };
824
968
 
825
969
  return Any;
@@ -877,7 +1021,7 @@ getJasmineRequireObj().CallTracker = function() {
877
1021
  };
878
1022
 
879
1023
  getJasmineRequireObj().Clock = function() {
880
- function Clock(global, delayedFunctionScheduler) {
1024
+ function Clock(global, delayedFunctionScheduler, mockDate) {
881
1025
  var self = this,
882
1026
  realTimingFunctions = {
883
1027
  setTimeout: global.setTimeout,
@@ -894,23 +1038,32 @@ getJasmineRequireObj().Clock = function() {
894
1038
  installed = false,
895
1039
  timer;
896
1040
 
1041
+
897
1042
  self.install = function() {
898
1043
  replace(global, fakeTimingFunctions);
899
1044
  timer = fakeTimingFunctions;
900
1045
  installed = true;
1046
+
1047
+ return self;
901
1048
  };
902
1049
 
903
1050
  self.uninstall = function() {
904
1051
  delayedFunctionScheduler.reset();
1052
+ mockDate.uninstall();
905
1053
  replace(global, realTimingFunctions);
1054
+
906
1055
  timer = realTimingFunctions;
907
1056
  installed = false;
908
1057
  };
909
1058
 
1059
+ self.mockDate = function(initialDate) {
1060
+ mockDate.install(initialDate);
1061
+ };
1062
+
910
1063
  self.setTimeout = function(fn, delay, params) {
911
1064
  if (legacyIE()) {
912
1065
  if (arguments.length > 2) {
913
- throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
1066
+ throw new Error('IE < 9 cannot support extra params to setTimeout without a polyfill');
914
1067
  }
915
1068
  return timer.setTimeout(fn, delay);
916
1069
  }
@@ -920,7 +1073,7 @@ getJasmineRequireObj().Clock = function() {
920
1073
  self.setInterval = function(fn, delay, params) {
921
1074
  if (legacyIE()) {
922
1075
  if (arguments.length > 2) {
923
- throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
1076
+ throw new Error('IE < 9 cannot support extra params to setInterval without a polyfill');
924
1077
  }
925
1078
  return timer.setInterval(fn, delay);
926
1079
  }
@@ -937,9 +1090,10 @@ getJasmineRequireObj().Clock = function() {
937
1090
 
938
1091
  self.tick = function(millis) {
939
1092
  if (installed) {
1093
+ mockDate.tick(millis);
940
1094
  delayedFunctionScheduler.tick(millis);
941
1095
  } else {
942
- throw new Error("Mock clock is not installed, use jasmine.clock().install()");
1096
+ throw new Error('Mock clock is not installed, use jasmine.clock().install()');
943
1097
  }
944
1098
  };
945
1099
 
@@ -973,7 +1127,7 @@ getJasmineRequireObj().Clock = function() {
973
1127
  }
974
1128
 
975
1129
  function argSlice(argsObj, n) {
976
- return Array.prototype.slice.call(argsObj, 2);
1130
+ return Array.prototype.slice.call(argsObj, n);
977
1131
  }
978
1132
  }
979
1133
 
@@ -1109,11 +1263,12 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
1109
1263
 
1110
1264
  for (var i = 0; i < funcsToRun.length; ++i) {
1111
1265
  var funcToRun = funcsToRun[i];
1112
- funcToRun.funcToCall.apply(null, funcToRun.params || []);
1113
1266
 
1114
1267
  if (funcToRun.recurring) {
1115
1268
  reschedule(funcToRun);
1116
1269
  }
1270
+
1271
+ funcToRun.funcToCall.apply(null, funcToRun.params || []);
1117
1272
  }
1118
1273
  } while (scheduledLookup.length > 0 &&
1119
1274
  // checking first if we're out of time prevents setTimeout(0)
@@ -1129,16 +1284,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
1129
1284
  getJasmineRequireObj().ExceptionFormatter = function() {
1130
1285
  function ExceptionFormatter() {
1131
1286
  this.message = function(error) {
1132
- var message = error.name +
1133
- ': ' +
1134
- error.message;
1287
+ var message = '';
1288
+
1289
+ if (error.name && error.message) {
1290
+ message += error.name + ': ' + error.message;
1291
+ } else {
1292
+ message += error.toString() + ' thrown';
1293
+ }
1135
1294
 
1136
1295
  if (error.fileName || error.sourceURL) {
1137
- message += " in " + (error.fileName || error.sourceURL);
1296
+ message += ' in ' + (error.fileName || error.sourceURL);
1138
1297
  }
1139
1298
 
1140
1299
  if (error.line || error.lineNumber) {
1141
- message += " (line " + (error.line || error.lineNumber) + ")";
1300
+ message += ' (line ' + (error.line || error.lineNumber) + ')';
1142
1301
  }
1143
1302
 
1144
1303
  return message;
@@ -1154,8 +1313,6 @@ getJasmineRequireObj().ExceptionFormatter = function() {
1154
1313
 
1155
1314
  getJasmineRequireObj().Expectation = function() {
1156
1315
 
1157
- var matchers = {};
1158
-
1159
1316
  function Expectation(options) {
1160
1317
  this.util = options.util || { buildFailureMessage: function() {} };
1161
1318
  this.customEqualityTesters = options.customEqualityTesters || [];
@@ -1163,8 +1320,9 @@ getJasmineRequireObj().Expectation = function() {
1163
1320
  this.addExpectationResult = options.addExpectationResult || function(){};
1164
1321
  this.isNot = options.isNot;
1165
1322
 
1166
- for (var matcherName in matchers) {
1167
- this[matcherName] = matchers[matcherName];
1323
+ var customMatchers = options.customMatchers || {};
1324
+ for (var matcherName in customMatchers) {
1325
+ this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
1168
1326
  }
1169
1327
  }
1170
1328
 
@@ -1172,7 +1330,7 @@ getJasmineRequireObj().Expectation = function() {
1172
1330
  return function() {
1173
1331
  var args = Array.prototype.slice.call(arguments, 0),
1174
1332
  expected = args.slice(0),
1175
- message = "";
1333
+ message = '';
1176
1334
 
1177
1335
  args.unshift(this.actual);
1178
1336
 
@@ -1197,7 +1355,11 @@ getJasmineRequireObj().Expectation = function() {
1197
1355
  args.unshift(name);
1198
1356
  message = this.util.buildFailureMessage.apply(null, args);
1199
1357
  } else {
1200
- message = result.message;
1358
+ if (Object.prototype.toString.apply(result.message) === '[object Function]') {
1359
+ message = result.message();
1360
+ } else {
1361
+ message = result.message;
1362
+ }
1201
1363
  }
1202
1364
  }
1203
1365
 
@@ -1227,19 +1389,6 @@ getJasmineRequireObj().Expectation = function() {
1227
1389
  }
1228
1390
  };
1229
1391
 
1230
- Expectation.addMatchers = function(matchersToAdd) {
1231
- for (var name in matchersToAdd) {
1232
- var matcher = matchersToAdd[name];
1233
- matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
1234
- }
1235
- };
1236
-
1237
- Expectation.resetMatchers = function() {
1238
- for (var name in matchers) {
1239
- delete matchers[name];
1240
- }
1241
- };
1242
-
1243
1392
  Expectation.Factory = function(options) {
1244
1393
  options = options || {};
1245
1394
 
@@ -1273,18 +1422,18 @@ getJasmineRequireObj().buildExpectationResult = function() {
1273
1422
 
1274
1423
  function message() {
1275
1424
  if (options.passed) {
1276
- return "Passed.";
1425
+ return 'Passed.';
1277
1426
  } else if (options.message) {
1278
1427
  return options.message;
1279
1428
  } else if (options.error) {
1280
1429
  return messageFormatter(options.error);
1281
1430
  }
1282
- return "";
1431
+ return '';
1283
1432
  }
1284
1433
 
1285
1434
  function stack() {
1286
1435
  if (options.passed) {
1287
- return "";
1436
+ return '';
1288
1437
  }
1289
1438
 
1290
1439
  var error = options.error;
@@ -1302,6 +1451,89 @@ getJasmineRequireObj().buildExpectationResult = function() {
1302
1451
  return buildExpectationResult;
1303
1452
  };
1304
1453
 
1454
+ getJasmineRequireObj().MockDate = function() {
1455
+ function MockDate(global) {
1456
+ var self = this;
1457
+ var currentTime = 0;
1458
+
1459
+ if (!global || !global.Date) {
1460
+ self.install = function() {};
1461
+ self.tick = function() {};
1462
+ self.uninstall = function() {};
1463
+ return self;
1464
+ }
1465
+
1466
+ var GlobalDate = global.Date;
1467
+
1468
+ self.install = function(mockDate) {
1469
+ if (mockDate instanceof GlobalDate) {
1470
+ currentTime = mockDate.getTime();
1471
+ } else {
1472
+ currentTime = new GlobalDate().getTime();
1473
+ }
1474
+
1475
+ global.Date = FakeDate;
1476
+ };
1477
+
1478
+ self.tick = function(millis) {
1479
+ millis = millis || 0;
1480
+ currentTime = currentTime + millis;
1481
+ };
1482
+
1483
+ self.uninstall = function() {
1484
+ currentTime = 0;
1485
+ global.Date = GlobalDate;
1486
+ };
1487
+
1488
+ createDateProperties();
1489
+
1490
+ return self;
1491
+
1492
+ function FakeDate() {
1493
+ switch(arguments.length) {
1494
+ case 0:
1495
+ return new GlobalDate(currentTime);
1496
+ case 1:
1497
+ return new GlobalDate(arguments[0]);
1498
+ case 2:
1499
+ return new GlobalDate(arguments[0], arguments[1]);
1500
+ case 3:
1501
+ return new GlobalDate(arguments[0], arguments[1], arguments[2]);
1502
+ case 4:
1503
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
1504
+ case 5:
1505
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1506
+ arguments[4]);
1507
+ case 6:
1508
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1509
+ arguments[4], arguments[5]);
1510
+ case 7:
1511
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1512
+ arguments[4], arguments[5], arguments[6]);
1513
+ }
1514
+ }
1515
+
1516
+ function createDateProperties() {
1517
+ FakeDate.prototype = GlobalDate.prototype;
1518
+
1519
+ FakeDate.now = function() {
1520
+ if (GlobalDate.now) {
1521
+ return currentTime;
1522
+ } else {
1523
+ throw new Error('Browser does not support Date.now()');
1524
+ }
1525
+ };
1526
+
1527
+ FakeDate.toSource = GlobalDate.toSource;
1528
+ FakeDate.toString = GlobalDate.toString;
1529
+ FakeDate.parse = GlobalDate.parse;
1530
+ FakeDate.UTC = GlobalDate.UTC;
1531
+ }
1532
+ }
1533
+
1534
+ return MockDate;
1535
+ };
1536
+
1305
1537
  getJasmineRequireObj().ObjectContaining = function(j$) {
1306
1538
 
1307
1539
  function ObjectContaining(sample) {
@@ -1309,7 +1541,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1309
1541
  }
1310
1542
 
1311
1543
  ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
1312
- if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); }
1544
+ if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
1313
1545
 
1314
1546
  mismatchKeys = mismatchKeys || [];
1315
1547
  mismatchValues = mismatchValues || [];
@@ -1320,10 +1552,10 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1320
1552
 
1321
1553
  for (var property in this.sample) {
1322
1554
  if (!hasKey(other, property) && hasKey(this.sample, property)) {
1323
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1555
+ mismatchKeys.push('expected has key \'' + property + '\', but missing from actual.');
1324
1556
  }
1325
- else if (!j$.matchersUtil.equals(this.sample[property], other[property])) {
1326
- mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected.");
1557
+ else if (!j$.matchersUtil.equals(other[property], this.sample[property])) {
1558
+ mismatchValues.push('\'' + property + '\' was \'' + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + '\' in actual, but was \'' + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + '\' in expected.');
1327
1559
  }
1328
1560
  }
1329
1561
 
@@ -1331,7 +1563,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1331
1563
  };
1332
1564
 
1333
1565
  ObjectContaining.prototype.jasmineToString = function() {
1334
- return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
1566
+ return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
1335
1567
  };
1336
1568
 
1337
1569
  return ObjectContaining;
@@ -1341,6 +1573,7 @@ getJasmineRequireObj().pp = function(j$) {
1341
1573
 
1342
1574
  function PrettyPrinter() {
1343
1575
  this.ppNestLevel_ = 0;
1576
+ this.seen = [];
1344
1577
  }
1345
1578
 
1346
1579
  PrettyPrinter.prototype.format = function(value) {
@@ -1350,6 +1583,8 @@ getJasmineRequireObj().pp = function(j$) {
1350
1583
  this.emitScalar('undefined');
1351
1584
  } else if (value === null) {
1352
1585
  this.emitScalar('null');
1586
+ } else if (value === 0 && 1/value === -Infinity) {
1587
+ this.emitScalar('-0');
1353
1588
  } else if (value === j$.getGlobal()) {
1354
1589
  this.emitScalar('<global>');
1355
1590
  } else if (value.jasmineToString) {
@@ -1357,7 +1592,7 @@ getJasmineRequireObj().pp = function(j$) {
1357
1592
  } else if (typeof value === 'string') {
1358
1593
  this.emitString(value);
1359
1594
  } else if (j$.isSpy(value)) {
1360
- this.emitScalar("spy on " + value.and.identity());
1595
+ this.emitScalar('spy on ' + value.and.identity());
1361
1596
  } else if (value instanceof RegExp) {
1362
1597
  this.emitScalar(value.toString());
1363
1598
  } else if (typeof value === 'function') {
@@ -1366,16 +1601,16 @@ getJasmineRequireObj().pp = function(j$) {
1366
1601
  this.emitScalar('HTMLNode');
1367
1602
  } else if (value instanceof Date) {
1368
1603
  this.emitScalar('Date(' + value + ')');
1369
- } else if (value.__Jasmine_been_here_before__) {
1604
+ } else if (j$.util.arrayContains(this.seen, value)) {
1370
1605
  this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
1371
1606
  } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
1372
- value.__Jasmine_been_here_before__ = true;
1607
+ this.seen.push(value);
1373
1608
  if (j$.isArray_(value)) {
1374
1609
  this.emitArray(value);
1375
1610
  } else {
1376
1611
  this.emitObject(value);
1377
1612
  }
1378
- delete value.__Jasmine_been_here_before__;
1613
+ this.seen.pop();
1379
1614
  } else {
1380
1615
  this.emitScalar(value.toString());
1381
1616
  }
@@ -1386,8 +1621,7 @@ getJasmineRequireObj().pp = function(j$) {
1386
1621
 
1387
1622
  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1388
1623
  for (var property in obj) {
1389
- if (!obj.hasOwnProperty(property)) { continue; }
1390
- if (property == '__Jasmine_been_here_before__') { continue; }
1624
+ if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
1391
1625
  fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
1392
1626
  obj.__lookupGetter__(property) !== null) : false);
1393
1627
  }
@@ -1411,28 +1645,31 @@ getJasmineRequireObj().pp = function(j$) {
1411
1645
  };
1412
1646
 
1413
1647
  StringPrettyPrinter.prototype.emitString = function(value) {
1414
- this.append("'" + value + "'");
1648
+ this.append('\'' + value + '\'');
1415
1649
  };
1416
1650
 
1417
1651
  StringPrettyPrinter.prototype.emitArray = function(array) {
1418
1652
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1419
- this.append("Array");
1653
+ this.append('Array');
1420
1654
  return;
1421
1655
  }
1422
-
1656
+ var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
1423
1657
  this.append('[ ');
1424
- for (var i = 0; i < array.length; i++) {
1658
+ for (var i = 0; i < length; i++) {
1425
1659
  if (i > 0) {
1426
1660
  this.append(', ');
1427
1661
  }
1428
1662
  this.format(array[i]);
1429
1663
  }
1664
+ if(array.length > length){
1665
+ this.append(', ...');
1666
+ }
1430
1667
  this.append(' ]');
1431
1668
  };
1432
1669
 
1433
1670
  StringPrettyPrinter.prototype.emitObject = function(obj) {
1434
1671
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1435
- this.append("Object");
1672
+ this.append('Object');
1436
1673
  return;
1437
1674
  }
1438
1675
 
@@ -1448,7 +1685,7 @@ getJasmineRequireObj().pp = function(j$) {
1448
1685
  }
1449
1686
 
1450
1687
  self.append(property);
1451
- self.append(' : ');
1688
+ self.append(': ');
1452
1689
  if (isGetter) {
1453
1690
  self.append('<getter>');
1454
1691
  } else {
@@ -1470,32 +1707,45 @@ getJasmineRequireObj().pp = function(j$) {
1470
1707
  };
1471
1708
  };
1472
1709
 
1473
- getJasmineRequireObj().QueueRunner = function() {
1710
+ getJasmineRequireObj().QueueRunner = function(j$) {
1711
+
1712
+ function once(fn) {
1713
+ var called = false;
1714
+ return function() {
1715
+ if (!called) {
1716
+ called = true;
1717
+ fn();
1718
+ }
1719
+ };
1720
+ }
1474
1721
 
1475
1722
  function QueueRunner(attrs) {
1476
- this.fns = attrs.fns || [];
1723
+ this.queueableFns = attrs.queueableFns || [];
1477
1724
  this.onComplete = attrs.onComplete || function() {};
1478
1725
  this.clearStack = attrs.clearStack || function(fn) {fn();};
1479
1726
  this.onException = attrs.onException || function() {};
1480
1727
  this.catchException = attrs.catchException || function() { return true; };
1481
- this.userContext = {};
1728
+ this.userContext = attrs.userContext || {};
1729
+ this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
1730
+ this.fail = attrs.fail || function() {};
1482
1731
  }
1483
1732
 
1484
1733
  QueueRunner.prototype.execute = function() {
1485
- this.run(this.fns, 0);
1734
+ this.run(this.queueableFns, 0);
1486
1735
  };
1487
1736
 
1488
- QueueRunner.prototype.run = function(fns, recursiveIndex) {
1489
- var length = fns.length,
1490
- self = this,
1491
- iterativeIndex;
1737
+ QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
1738
+ var length = queueableFns.length,
1739
+ self = this,
1740
+ iterativeIndex;
1741
+
1492
1742
 
1493
1743
  for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
1494
- var fn = fns[iterativeIndex];
1495
- if (fn.length > 0) {
1496
- return attemptAsync(fn);
1744
+ var queueableFn = queueableFns[iterativeIndex];
1745
+ if (queueableFn.fn.length > 0) {
1746
+ return attemptAsync(queueableFn);
1497
1747
  } else {
1498
- attemptSync(fn);
1748
+ attemptSync(queueableFn);
1499
1749
  }
1500
1750
  }
1501
1751
 
@@ -1505,27 +1755,51 @@ getJasmineRequireObj().QueueRunner = function() {
1505
1755
  this.clearStack(this.onComplete);
1506
1756
  }
1507
1757
 
1508
- function attemptSync(fn) {
1758
+ function attemptSync(queueableFn) {
1509
1759
  try {
1510
- fn.call(self.userContext);
1760
+ queueableFn.fn.call(self.userContext);
1511
1761
  } catch (e) {
1512
- handleException(e);
1762
+ handleException(e, queueableFn);
1513
1763
  }
1514
1764
  }
1515
1765
 
1516
- function attemptAsync(fn) {
1517
- var next = function () { self.run(fns, iterativeIndex + 1); };
1766
+ function attemptAsync(queueableFn) {
1767
+ var clearTimeout = function () {
1768
+ Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
1769
+ },
1770
+ next = once(function () {
1771
+ clearTimeout(timeoutId);
1772
+ self.run(queueableFns, iterativeIndex + 1);
1773
+ }),
1774
+ timeoutId;
1775
+
1776
+ next.fail = function() {
1777
+ self.fail.apply(null, arguments);
1778
+ next();
1779
+ };
1780
+
1781
+ if (queueableFn.timeout) {
1782
+ timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
1783
+ var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
1784
+ onException(error, queueableFn);
1785
+ next();
1786
+ }, queueableFn.timeout()]]);
1787
+ }
1518
1788
 
1519
1789
  try {
1520
- fn.call(self.userContext, next);
1790
+ queueableFn.fn.call(self.userContext, next);
1521
1791
  } catch (e) {
1522
- handleException(e);
1792
+ handleException(e, queueableFn);
1523
1793
  next();
1524
1794
  }
1525
1795
  }
1526
1796
 
1527
- function handleException(e) {
1797
+ function onException(e, queueableFn) {
1528
1798
  self.onException(e);
1799
+ }
1800
+
1801
+ function handleException(e, queueableFn) {
1802
+ onException(e, queueableFn);
1529
1803
  if (!self.catchException(e)) {
1530
1804
  //TODO: set a var when we catch an exception and
1531
1805
  //use a finally block to close the loop in a nice way..
@@ -1573,12 +1847,58 @@ getJasmineRequireObj().ReportDispatcher = function() {
1573
1847
  };
1574
1848
 
1575
1849
 
1850
+ getJasmineRequireObj().SpyRegistry = function(j$) {
1851
+
1852
+ function SpyRegistry(options) {
1853
+ options = options || {};
1854
+ var currentSpies = options.currentSpies || function() { return []; };
1855
+
1856
+ this.spyOn = function(obj, methodName) {
1857
+ if (j$.util.isUndefined(obj)) {
1858
+ throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
1859
+ }
1860
+
1861
+ if (j$.util.isUndefined(obj[methodName])) {
1862
+ throw new Error(methodName + '() method does not exist');
1863
+ }
1864
+
1865
+ if (obj[methodName] && j$.isSpy(obj[methodName])) {
1866
+ //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
1867
+ throw new Error(methodName + ' has already been spied upon');
1868
+ }
1869
+
1870
+ var spy = j$.createSpy(methodName, obj[methodName]);
1871
+
1872
+ currentSpies().push({
1873
+ spy: spy,
1874
+ baseObj: obj,
1875
+ methodName: methodName,
1876
+ originalValue: obj[methodName]
1877
+ });
1878
+
1879
+ obj[methodName] = spy;
1880
+
1881
+ return spy;
1882
+ };
1883
+
1884
+ this.clearSpies = function() {
1885
+ var spies = currentSpies();
1886
+ for (var i = 0; i < spies.length; i++) {
1887
+ var spyEntry = spies[i];
1888
+ spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
1889
+ }
1890
+ };
1891
+ }
1892
+
1893
+ return SpyRegistry;
1894
+ };
1895
+
1576
1896
  getJasmineRequireObj().SpyStrategy = function() {
1577
1897
 
1578
1898
  function SpyStrategy(options) {
1579
1899
  options = options || {};
1580
1900
 
1581
- var identity = options.name || "unknown",
1901
+ var identity = options.name || 'unknown',
1582
1902
  originalFn = options.fn || function() {},
1583
1903
  getSpy = options.getSpy || function() {},
1584
1904
  plan = function() {};
@@ -1603,6 +1923,14 @@ getJasmineRequireObj().SpyStrategy = function() {
1603
1923
  return getSpy();
1604
1924
  };
1605
1925
 
1926
+ this.returnValues = function() {
1927
+ var values = Array.prototype.slice.call(arguments);
1928
+ plan = function () {
1929
+ return values.shift();
1930
+ };
1931
+ return getSpy();
1932
+ };
1933
+
1606
1934
  this.throwError = function(something) {
1607
1935
  var error = (something instanceof Error) ? something : new Error(something);
1608
1936
  plan = function() {
@@ -1634,9 +1962,13 @@ getJasmineRequireObj().Suite = function() {
1634
1962
  this.onStart = attrs.onStart || function() {};
1635
1963
  this.resultCallback = attrs.resultCallback || function() {};
1636
1964
  this.clearStack = attrs.clearStack || function(fn) {fn();};
1965
+ this.expectationFactory = attrs.expectationFactory;
1966
+ this.expectationResultFactory = attrs.expectationResultFactory;
1637
1967
 
1638
1968
  this.beforeFns = [];
1639
1969
  this.afterFns = [];
1970
+ this.beforeAllFns = [];
1971
+ this.afterAllFns = [];
1640
1972
  this.queueRunner = attrs.queueRunner || function() {};
1641
1973
  this.disabled = false;
1642
1974
 
@@ -1644,12 +1976,16 @@ getJasmineRequireObj().Suite = function() {
1644
1976
 
1645
1977
  this.result = {
1646
1978
  id: this.id,
1647
- status: this.disabled ? 'disabled' : '',
1648
1979
  description: this.description,
1649
- fullName: this.getFullName()
1980
+ fullName: this.getFullName(),
1981
+ failedExpectations: []
1650
1982
  };
1651
1983
  }
1652
1984
 
1985
+ Suite.prototype.expect = function(actual) {
1986
+ return this.expectationFactory(actual, this);
1987
+ };
1988
+
1653
1989
  Suite.prototype.getFullName = function() {
1654
1990
  var fullName = this.description;
1655
1991
  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -1668,16 +2004,39 @@ getJasmineRequireObj().Suite = function() {
1668
2004
  this.beforeFns.unshift(fn);
1669
2005
  };
1670
2006
 
2007
+ Suite.prototype.beforeAll = function(fn) {
2008
+ this.beforeAllFns.push(fn);
2009
+ };
2010
+
1671
2011
  Suite.prototype.afterEach = function(fn) {
1672
2012
  this.afterFns.unshift(fn);
1673
2013
  };
1674
2014
 
2015
+ Suite.prototype.afterAll = function(fn) {
2016
+ this.afterAllFns.push(fn);
2017
+ };
2018
+
1675
2019
  Suite.prototype.addChild = function(child) {
1676
2020
  this.children.push(child);
1677
2021
  };
1678
2022
 
2023
+ Suite.prototype.status = function() {
2024
+ if (this.disabled) {
2025
+ return 'disabled';
2026
+ }
2027
+
2028
+ if (this.result.failedExpectations.length > 0) {
2029
+ return 'failed';
2030
+ } else {
2031
+ return 'finished';
2032
+ }
2033
+ };
2034
+
1679
2035
  Suite.prototype.execute = function(onComplete) {
1680
2036
  var self = this;
2037
+
2038
+ this.onStart(this);
2039
+
1681
2040
  if (this.disabled) {
1682
2041
  complete();
1683
2042
  return;
@@ -1685,18 +2044,25 @@ getJasmineRequireObj().Suite = function() {
1685
2044
 
1686
2045
  var allFns = [];
1687
2046
 
1688
- for (var i = 0; i < this.children.length; i++) {
1689
- allFns.push(wrapChildAsAsync(this.children[i]));
1690
- }
2047
+ if (this.isExecutable()) {
2048
+ allFns = allFns.concat(this.beforeAllFns);
1691
2049
 
1692
- this.onStart(this);
2050
+ for (var i = 0; i < this.children.length; i++) {
2051
+ allFns.push(wrapChildAsAsync(this.children[i]));
2052
+ }
2053
+
2054
+ allFns = allFns.concat(this.afterAllFns);
2055
+ }
1693
2056
 
1694
2057
  this.queueRunner({
1695
- fns: allFns,
1696
- onComplete: complete
2058
+ queueableFns: allFns,
2059
+ onComplete: complete,
2060
+ userContext: this.sharedUserContext(),
2061
+ onException: function() { self.onException.apply(self, arguments); }
1697
2062
  });
1698
2063
 
1699
2064
  function complete() {
2065
+ self.result.status = self.status();
1700
2066
  self.resultCallback(self.result);
1701
2067
 
1702
2068
  if (onComplete) {
@@ -1705,23 +2071,99 @@ getJasmineRequireObj().Suite = function() {
1705
2071
  }
1706
2072
 
1707
2073
  function wrapChildAsAsync(child) {
1708
- return function(done) { child.execute(done); };
2074
+ return { fn: function(done) { child.execute(done); } };
2075
+ }
2076
+ };
2077
+
2078
+ Suite.prototype.isExecutable = function() {
2079
+ var foundActive = false;
2080
+ for(var i = 0; i < this.children.length; i++) {
2081
+ if(this.children[i].isExecutable()) {
2082
+ foundActive = true;
2083
+ break;
2084
+ }
2085
+ }
2086
+ return foundActive;
2087
+ };
2088
+
2089
+ Suite.prototype.sharedUserContext = function() {
2090
+ if (!this.sharedContext) {
2091
+ this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
2092
+ }
2093
+
2094
+ return this.sharedContext;
2095
+ };
2096
+
2097
+ Suite.prototype.clonedSharedUserContext = function() {
2098
+ return clone(this.sharedUserContext());
2099
+ };
2100
+
2101
+ Suite.prototype.onException = function() {
2102
+ if(isAfterAll(this.children)) {
2103
+ var data = {
2104
+ matcherName: '',
2105
+ passed: false,
2106
+ expected: '',
2107
+ actual: '',
2108
+ error: arguments[0]
2109
+ };
2110
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
2111
+ } else {
2112
+ for (var i = 0; i < this.children.length; i++) {
2113
+ var child = this.children[i];
2114
+ child.onException.apply(child, arguments);
2115
+ }
2116
+ }
2117
+ };
2118
+
2119
+ Suite.prototype.addExpectationResult = function () {
2120
+ if(isAfterAll(this.children) && isFailure(arguments)){
2121
+ var data = arguments[1];
2122
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
2123
+ } else {
2124
+ for (var i = 0; i < this.children.length; i++) {
2125
+ var child = this.children[i];
2126
+ child.addExpectationResult.apply(child, arguments);
2127
+ }
1709
2128
  }
1710
2129
  };
1711
2130
 
2131
+ function isAfterAll(children) {
2132
+ return children && children[0].result.status;
2133
+ }
2134
+
2135
+ function isFailure(args) {
2136
+ return !args[0];
2137
+ }
2138
+
2139
+ function clone(obj) {
2140
+ var clonedObj = {};
2141
+ for (var prop in obj) {
2142
+ if (obj.hasOwnProperty(prop)) {
2143
+ clonedObj[prop] = obj[prop];
2144
+ }
2145
+ }
2146
+
2147
+ return clonedObj;
2148
+ }
2149
+
1712
2150
  return Suite;
1713
2151
  };
1714
2152
 
1715
- if (typeof window == void 0 && typeof exports == "object") {
2153
+ if (typeof window == void 0 && typeof exports == 'object') {
1716
2154
  exports.Suite = jasmineRequire.Suite;
1717
2155
  }
1718
2156
 
1719
2157
  getJasmineRequireObj().Timer = function() {
2158
+ var defaultNow = (function(Date) {
2159
+ return function() { return new Date().getTime(); };
2160
+ })(Date);
2161
+
1720
2162
  function Timer(options) {
1721
2163
  options = options || {};
1722
2164
 
1723
- var now = options.now || function() { return new Date().getTime(); },
1724
- startTime;
2165
+ var now = options.now || defaultNow,
2166
+ startTime;
1725
2167
 
1726
2168
  this.start = function() {
1727
2169
  startTime = now();
@@ -1748,7 +2190,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1748
2190
  contains: function(haystack, needle, customTesters) {
1749
2191
  customTesters = customTesters || [];
1750
2192
 
1751
- if (Object.prototype.toString.apply(haystack) === "[object Array]") {
2193
+ if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
2194
+ (!!haystack && !haystack.indexOf))
2195
+ {
1752
2196
  for (var i = 0; i < haystack.length; i++) {
1753
2197
  if (eq(haystack[i], needle, [], [], customTesters)) {
1754
2198
  return true;
@@ -1756,7 +2200,8 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1756
2200
  }
1757
2201
  return false;
1758
2202
  }
1759
- return haystack.indexOf(needle) >= 0;
2203
+
2204
+ return !!haystack && haystack.indexOf(needle) >= 0;
1760
2205
  },
1761
2206
 
1762
2207
  buildFailureMessage: function() {
@@ -1767,21 +2212,21 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1767
2212
  expected = args.slice(3),
1768
2213
  englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1769
2214
 
1770
- var message = "Expected " +
2215
+ var message = 'Expected ' +
1771
2216
  j$.pp(actual) +
1772
- (isNot ? " not " : " ") +
2217
+ (isNot ? ' not ' : ' ') +
1773
2218
  englishyPredicate;
1774
2219
 
1775
2220
  if (expected.length > 0) {
1776
2221
  for (var i = 0; i < expected.length; i++) {
1777
2222
  if (i > 0) {
1778
- message += ",";
2223
+ message += ',';
1779
2224
  }
1780
- message += " " + j$.pp(expected[i]);
2225
+ message += ' ' + j$.pp(expected[i]);
1781
2226
  }
1782
2227
  }
1783
2228
 
1784
- return message + ".";
2229
+ return message + '.';
1785
2230
  }
1786
2231
  };
1787
2232
 
@@ -2018,9 +2463,9 @@ getJasmineRequireObj().toBeNaN = function(j$) {
2018
2463
  };
2019
2464
 
2020
2465
  if (result.pass) {
2021
- result.message = "Expected actual not to be NaN.";
2466
+ result.message = 'Expected actual not to be NaN.';
2022
2467
  } else {
2023
- result.message = "Expected " + j$.pp(actual) + " to be NaN.";
2468
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
2024
2469
  }
2025
2470
 
2026
2471
  return result;
@@ -2132,8 +2577,8 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2132
2577
  result.pass = actual.calls.any();
2133
2578
 
2134
2579
  result.message = result.pass ?
2135
- "Expected spy " + actual.and.identity() + " not to have been called." :
2136
- "Expected spy " + actual.and.identity() + " to have been called.";
2580
+ 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
2581
+ 'Expected spy ' + actual.and.identity() + ' to have been called.';
2137
2582
 
2138
2583
  return result;
2139
2584
  }
@@ -2145,7 +2590,7 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2145
2590
 
2146
2591
  getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2147
2592
 
2148
- function toHaveBeenCalledWith(util) {
2593
+ function toHaveBeenCalledWith(util, customEqualityTesters) {
2149
2594
  return {
2150
2595
  compare: function() {
2151
2596
  var args = Array.prototype.slice.call(arguments, 0),
@@ -2158,15 +2603,15 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2158
2603
  }
2159
2604
 
2160
2605
  if (!actual.calls.any()) {
2161
- result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
2606
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
2162
2607
  return result;
2163
2608
  }
2164
2609
 
2165
- if (util.contains(actual.calls.allArgs(), expectedArgs)) {
2610
+ if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
2166
2611
  result.pass = true;
2167
- result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
2612
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
2168
2613
  } else {
2169
- result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";
2614
+ 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, '') + '.'; };
2170
2615
  }
2171
2616
 
2172
2617
  return result;
@@ -2203,8 +2648,8 @@ getJasmineRequireObj().toThrow = function(j$) {
2203
2648
  threw = false,
2204
2649
  thrown;
2205
2650
 
2206
- if (typeof actual != "function") {
2207
- throw new Error("Actual is not a Function");
2651
+ if (typeof actual != 'function') {
2652
+ throw new Error('Actual is not a Function');
2208
2653
  }
2209
2654
 
2210
2655
  try {
@@ -2215,22 +2660,22 @@ getJasmineRequireObj().toThrow = function(j$) {
2215
2660
  }
2216
2661
 
2217
2662
  if (!threw) {
2218
- result.message = "Expected function to throw an exception.";
2663
+ result.message = 'Expected function to throw an exception.';
2219
2664
  return result;
2220
2665
  }
2221
2666
 
2222
2667
  if (arguments.length == 1) {
2223
2668
  result.pass = true;
2224
- result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
2669
+ result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
2225
2670
 
2226
2671
  return result;
2227
2672
  }
2228
2673
 
2229
2674
  if (util.equals(thrown, expected)) {
2230
2675
  result.pass = true;
2231
- result.message = "Expected function not to throw " + j$.pp(expected) + ".";
2676
+ result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
2232
2677
  } else {
2233
- result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";
2678
+ result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
2234
2679
  }
2235
2680
 
2236
2681
  return result;
@@ -2246,18 +2691,15 @@ getJasmineRequireObj().toThrowError = function(j$) {
2246
2691
  return {
2247
2692
  compare: function(actual) {
2248
2693
  var threw = false,
2249
- thrown,
2250
- errorType,
2251
- message,
2252
- regexp,
2253
- name,
2254
- constructorName;
2255
-
2256
- if (typeof actual != "function") {
2257
- throw new Error("Actual is not a Function");
2694
+ pass = {pass: true},
2695
+ fail = {pass: false},
2696
+ thrown;
2697
+
2698
+ if (typeof actual != 'function') {
2699
+ throw new Error('Actual is not a Function');
2258
2700
  }
2259
2701
 
2260
- extractExpectedParams.apply(null, arguments);
2702
+ var errorMatcher = getMatcher.apply(null, arguments);
2261
2703
 
2262
2704
  try {
2263
2705
  actual();
@@ -2267,136 +2709,202 @@ getJasmineRequireObj().toThrowError = function(j$) {
2267
2709
  }
2268
2710
 
2269
2711
  if (!threw) {
2270
- return fail("Expected function to throw an Error.");
2712
+ fail.message = 'Expected function to throw an Error.';
2713
+ return fail;
2271
2714
  }
2272
2715
 
2273
2716
  if (!(thrown instanceof Error)) {
2274
- return fail("Expected function to throw an Error, but it threw " + thrown + ".");
2717
+ fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
2718
+ return fail;
2275
2719
  }
2276
2720
 
2277
- if (arguments.length == 1) {
2278
- return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
2721
+ if (errorMatcher.hasNoSpecifics()) {
2722
+ pass.message = 'Expected function not to throw an Error, but it threw ' + fnNameFor(thrown) + '.';
2723
+ return pass;
2279
2724
  }
2280
2725
 
2281
- if (errorType) {
2282
- name = fnNameFor(errorType);
2283
- constructorName = fnNameFor(thrown.constructor);
2726
+ if (errorMatcher.matches(thrown)) {
2727
+ pass.message = function() {
2728
+ return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
2729
+ };
2730
+ return pass;
2731
+ } else {
2732
+ fail.message = function() {
2733
+ return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
2734
+ ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
2735
+ };
2736
+ return fail;
2284
2737
  }
2738
+ }
2739
+ };
2285
2740
 
2286
- if (errorType && message) {
2287
- if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
2288
- return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
2289
- } else {
2290
- return fail("Expected function to throw " + name + " with message \"" + message +
2291
- "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2292
- }
2293
- }
2741
+ function getMatcher() {
2742
+ var expected = null,
2743
+ errorType = null;
2294
2744
 
2295
- if (errorType && regexp) {
2296
- if (thrown.constructor == errorType && regexp.test(thrown.message)) {
2297
- return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
2298
- } else {
2299
- return fail("Expected function to throw " + name + " with message matching " + regexp +
2300
- ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2301
- }
2745
+ if (arguments.length == 2) {
2746
+ expected = arguments[1];
2747
+ if (isAnErrorType(expected)) {
2748
+ errorType = expected;
2749
+ expected = null;
2302
2750
  }
2751
+ } else if (arguments.length > 2) {
2752
+ errorType = arguments[1];
2753
+ expected = arguments[2];
2754
+ if (!isAnErrorType(errorType)) {
2755
+ throw new Error('Expected error type is not an Error.');
2756
+ }
2757
+ }
2303
2758
 
2759
+ if (expected && !isStringOrRegExp(expected)) {
2304
2760
  if (errorType) {
2305
- if (thrown.constructor == errorType) {
2306
- return pass("Expected function not to throw " + name + ".");
2307
- } else {
2308
- return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
2309
- }
2761
+ throw new Error('Expected error message is not a string or RegExp.');
2762
+ } else {
2763
+ throw new Error('Expected is not an Error, string, or RegExp.');
2310
2764
  }
2765
+ }
2311
2766
 
2312
- if (message) {
2313
- if (thrown.message == message) {
2314
- return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
2315
- } else {
2316
- return fail("Expected function to throw an exception with message " + j$.pp(message) +
2317
- ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2318
- }
2767
+ function messageMatch(message) {
2768
+ if (typeof expected == 'string') {
2769
+ return expected == message;
2770
+ } else {
2771
+ return expected.test(message);
2319
2772
  }
2773
+ }
2774
+
2775
+ return {
2776
+ errorTypeDescription: errorType ? fnNameFor(errorType) : 'an exception',
2777
+ thrownDescription: function(thrown) {
2778
+ var thrownName = errorType ? fnNameFor(thrown.constructor) : 'an exception',
2779
+ thrownMessage = '';
2320
2780
 
2321
- if (regexp) {
2322
- if (regexp.test(thrown.message)) {
2323
- return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
2781
+ if (expected) {
2782
+ thrownMessage = ' with message ' + j$.pp(thrown.message);
2783
+ }
2784
+
2785
+ return thrownName + thrownMessage;
2786
+ },
2787
+ messageDescription: function() {
2788
+ if (expected === null) {
2789
+ return '';
2790
+ } else if (expected instanceof RegExp) {
2791
+ return ' with a message matching ' + j$.pp(expected);
2324
2792
  } else {
2325
- return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
2326
- ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2793
+ return ' with message ' + j$.pp(expected);
2327
2794
  }
2795
+ },
2796
+ hasNoSpecifics: function() {
2797
+ return expected === null && errorType === null;
2798
+ },
2799
+ matches: function(error) {
2800
+ return (errorType === null || error.constructor === errorType) &&
2801
+ (expected === null || messageMatch(error.message));
2328
2802
  }
2803
+ };
2804
+ }
2329
2805
 
2330
- function fnNameFor(func) {
2331
- return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2332
- }
2806
+ function fnNameFor(func) {
2807
+ return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2808
+ }
2333
2809
 
2334
- function pass(notMessage) {
2335
- return {
2336
- pass: true,
2337
- message: notMessage
2338
- };
2339
- }
2810
+ function isStringOrRegExp(potential) {
2811
+ return potential instanceof RegExp || (typeof potential == 'string');
2812
+ }
2340
2813
 
2341
- function fail(message) {
2342
- return {
2343
- pass: false,
2344
- message: message
2345
- };
2346
- }
2814
+ function isAnErrorType(type) {
2815
+ if (typeof type !== 'function') {
2816
+ return false;
2817
+ }
2347
2818
 
2348
- function extractExpectedParams() {
2349
- if (arguments.length == 1) {
2350
- return;
2351
- }
2819
+ var Surrogate = function() {};
2820
+ Surrogate.prototype = type.prototype;
2821
+ return (new Surrogate()) instanceof Error;
2822
+ }
2823
+ }
2352
2824
 
2353
- if (arguments.length == 2) {
2354
- var expected = arguments[1];
2825
+ return toThrowError;
2826
+ };
2355
2827
 
2356
- if (expected instanceof RegExp) {
2357
- regexp = expected;
2358
- } else if (typeof expected == "string") {
2359
- message = expected;
2360
- } else if (checkForAnErrorType(expected)) {
2361
- errorType = expected;
2362
- }
2828
+ getJasmineRequireObj().interface = function(jasmine, env) {
2829
+ var jasmineInterface = {
2830
+ describe: function(description, specDefinitions) {
2831
+ return env.describe(description, specDefinitions);
2832
+ },
2363
2833
 
2364
- if (!(errorType || message || regexp)) {
2365
- throw new Error("Expected is not an Error, string, or RegExp.");
2366
- }
2367
- } else {
2368
- if (checkForAnErrorType(arguments[1])) {
2369
- errorType = arguments[1];
2370
- } else {
2371
- throw new Error("Expected error type is not an Error.");
2372
- }
2373
-
2374
- if (arguments[2] instanceof RegExp) {
2375
- regexp = arguments[2];
2376
- } else if (typeof arguments[2] == "string") {
2377
- message = arguments[2];
2378
- } else {
2379
- throw new Error("Expected error message is not a string or RegExp.");
2380
- }
2381
- }
2382
- }
2834
+ xdescribe: function(description, specDefinitions) {
2835
+ return env.xdescribe(description, specDefinitions);
2836
+ },
2383
2837
 
2384
- function checkForAnErrorType(type) {
2385
- if (typeof type !== "function") {
2386
- return false;
2387
- }
2838
+ fdescribe: function(description, specDefinitions) {
2839
+ return env.fdescribe(description, specDefinitions);
2840
+ },
2388
2841
 
2389
- var Surrogate = function() {};
2390
- Surrogate.prototype = type.prototype;
2391
- return (new Surrogate()) instanceof Error;
2392
- }
2393
- }
2394
- };
2395
- }
2842
+ it: function(desc, func) {
2843
+ return env.it(desc, func);
2844
+ },
2396
2845
 
2397
- return toThrowError;
2846
+ xit: function(desc, func) {
2847
+ return env.xit(desc, func);
2848
+ },
2849
+
2850
+ fit: function(desc, func) {
2851
+ return env.fit(desc, func);
2852
+ },
2853
+
2854
+ beforeEach: function(beforeEachFunction) {
2855
+ return env.beforeEach(beforeEachFunction);
2856
+ },
2857
+
2858
+ afterEach: function(afterEachFunction) {
2859
+ return env.afterEach(afterEachFunction);
2860
+ },
2861
+
2862
+ beforeAll: function(beforeAllFunction) {
2863
+ return env.beforeAll(beforeAllFunction);
2864
+ },
2865
+
2866
+ afterAll: function(afterAllFunction) {
2867
+ return env.afterAll(afterAllFunction);
2868
+ },
2869
+
2870
+ expect: function(actual) {
2871
+ return env.expect(actual);
2872
+ },
2873
+
2874
+ pending: function() {
2875
+ return env.pending();
2876
+ },
2877
+
2878
+ fail: function() {
2879
+ return env.fail.apply(env, arguments);
2880
+ },
2881
+
2882
+ spyOn: function(obj, methodName) {
2883
+ return env.spyOn(obj, methodName);
2884
+ },
2885
+
2886
+ jsApiReporter: new jasmine.JsApiReporter({
2887
+ timer: new jasmine.Timer()
2888
+ }),
2889
+
2890
+ jasmine: jasmine
2891
+ };
2892
+
2893
+ jasmine.addCustomEqualityTester = function(tester) {
2894
+ env.addCustomEqualityTester(tester);
2895
+ };
2896
+
2897
+ jasmine.addMatchers = function(matchers) {
2898
+ return env.addMatchers(matchers);
2899
+ };
2900
+
2901
+ jasmine.clock = function() {
2902
+ return env.clock;
2903
+ };
2904
+
2905
+ return jasmineInterface;
2398
2906
  };
2399
2907
 
2400
2908
  getJasmineRequireObj().version = function() {
2401
- return "2.0.0";
2909
+ return '2.1.1';
2402
2910
  };