jasmine-core 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +961 -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 +969 -36
  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,54 @@ 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
+ resultCallback: function(attrs) {
578
+ reporter.suiteDone(attrs);
579
+ }
527
580
  });
528
581
  runnableLookupTable[topSuite.id] = topSuite;
529
- currentSuite = topSuite;
582
+ defaultResourcesForRunnable(topSuite.id);
583
+ currentDeclarationSuite = topSuite;
530
584
 
531
585
  this.topSuite = function() {
532
586
  return topSuite;
533
587
  };
534
588
 
535
589
  this.execute = function(runnablesToRun) {
536
- runnablesToRun = runnablesToRun || [topSuite.id];
590
+ if(runnablesToRun) {
591
+ runnablesExplictlySet = true;
592
+ } else if (focusedRunnables.length) {
593
+ runnablesExplictlySet = true;
594
+ runnablesToRun = focusedRunnables;
595
+ } else {
596
+ runnablesToRun = [topSuite.id];
597
+ }
537
598
 
538
599
  var allFns = [];
539
600
  for(var i = 0; i < runnablesToRun.length; i++) {
540
601
  var runnable = runnableLookupTable[runnablesToRun[i]];
541
- allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
602
+ allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
542
603
  }
543
604
 
544
605
  reporter.jasmineStarted({
545
606
  totalSpecsDefined: totalSpecsDefined
546
607
  });
547
608
 
548
- queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
609
+ queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
549
610
  };
550
611
 
551
612
  this.addReporter = function(reporterToAdd) {
552
613
  reporter.addReporter(reporterToAdd);
553
614
  };
554
615
 
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 + "()");
616
+ var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
617
+ if(!currentRunnable()) {
618
+ throw new Error('Spies must be created in a before function or a spec');
562
619
  }
620
+ return runnableResources[currentRunnable().id].spies;
621
+ }});
563
622
 
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;
623
+ this.spyOn = function() {
624
+ return spyRegistry.spyOn.apply(spyRegistry, arguments);
585
625
  };
586
626
 
587
627
  var suiteFactory = function(description) {
@@ -589,24 +629,59 @@ getJasmineRequireObj().Env = function(j$) {
589
629
  env: self,
590
630
  id: getNextSuiteId(),
591
631
  description: description,
592
- parentSuite: currentSuite,
632
+ parentSuite: currentDeclarationSuite,
593
633
  queueRunner: queueRunnerFactory,
594
634
  onStart: suiteStarted,
635
+ expectationFactory: expectationFactory,
636
+ expectationResultFactory: expectationResultFactory,
595
637
  resultCallback: function(attrs) {
638
+ if (!suite.disabled) {
639
+ clearResourcesForRunnable(suite.id);
640
+ currentlyExecutingSuites.pop();
641
+ }
596
642
  reporter.suiteDone(attrs);
597
643
  }
598
644
  });
599
645
 
600
646
  runnableLookupTable[suite.id] = suite;
601
647
  return suite;
648
+
649
+ function suiteStarted(suite) {
650
+ currentlyExecutingSuites.push(suite);
651
+ defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
652
+ reporter.suiteStarted(suite.result);
653
+ }
602
654
  };
603
655
 
604
656
  this.describe = function(description, specDefinitions) {
605
657
  var suite = suiteFactory(description);
658
+ addSpecsToSuite(suite, specDefinitions);
659
+ return suite;
660
+ };
661
+
662
+ this.xdescribe = function(description, specDefinitions) {
663
+ var suite = this.describe(description, specDefinitions);
664
+ suite.disable();
665
+ return suite;
666
+ };
667
+
668
+ var focusedRunnables = [];
669
+
670
+ this.fdescribe = function(description, specDefinitions) {
671
+ var suite = suiteFactory(description);
672
+ suite.isFocused = true;
673
+
674
+ focusedRunnables.push(suite.id);
675
+ unfocusAncestor();
676
+ addSpecsToSuite(suite, specDefinitions);
606
677
 
607
- var parentSuite = currentSuite;
678
+ return suite;
679
+ };
680
+
681
+ function addSpecsToSuite(suite, specDefinitions) {
682
+ var parentSuite = currentDeclarationSuite;
608
683
  parentSuite.addChild(suite);
609
- currentSuite = suite;
684
+ currentDeclarationSuite = suite;
610
685
 
611
686
  var declarationError = null;
612
687
  try {
@@ -616,31 +691,49 @@ getJasmineRequireObj().Env = function(j$) {
616
691
  }
617
692
 
618
693
  if (declarationError) {
619
- this.it("encountered a declaration exception", function() {
694
+ self.it('encountered a declaration exception', function() {
620
695
  throw declarationError;
621
696
  });
622
697
  }
623
698
 
624
- currentSuite = parentSuite;
699
+ currentDeclarationSuite = parentSuite;
700
+ }
625
701
 
626
- return suite;
627
- };
702
+ function findFocusedAncestor(suite) {
703
+ while (suite) {
704
+ if (suite.isFocused) {
705
+ return suite.id;
706
+ }
707
+ suite = suite.parentSuite;
708
+ }
628
709
 
629
- this.xdescribe = function(description, specDefinitions) {
630
- var suite = this.describe(description, specDefinitions);
631
- suite.disable();
632
- return suite;
710
+ return null;
711
+ }
712
+
713
+ function unfocusAncestor() {
714
+ var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
715
+ if (focusedAncestor) {
716
+ for (var i = 0; i < focusedRunnables.length; i++) {
717
+ if (focusedRunnables[i] === focusedAncestor) {
718
+ focusedRunnables.splice(i, 1);
719
+ break;
720
+ }
721
+ }
722
+ }
723
+ }
724
+
725
+ var runnablesExplictlySet = false;
726
+
727
+ var runnablesExplictlySetGetter = function(){
728
+ return runnablesExplictlySet;
633
729
  };
634
730
 
635
- var specFactory = function(description, fn, suite) {
731
+ var specFactory = function(description, fn, suite, timeout) {
636
732
  totalSpecsDefined++;
637
-
638
733
  var spec = new j$.Spec({
639
734
  id: getNextSpecId(),
640
- beforeFns: beforeFns(suite),
641
- afterFns: afterFns(suite),
735
+ beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
642
736
  expectationFactory: expectationFactory,
643
- exceptionFormatter: exceptionFormatter,
644
737
  resultCallback: specResultCallback,
645
738
  getSpecName: function(spec) {
646
739
  return getSpecName(spec, suite);
@@ -649,8 +742,11 @@ getJasmineRequireObj().Env = function(j$) {
649
742
  description: description,
650
743
  expectationResultFactory: expectationResultFactory,
651
744
  queueRunnerFactory: queueRunnerFactory,
652
- fn: fn,
653
- timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
745
+ userContext: function() { return suite.clonedSharedUserContext(); },
746
+ queueableFn: {
747
+ fn: fn,
748
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
749
+ }
654
750
  });
655
751
 
656
752
  runnableLookupTable[spec.id] = spec;
@@ -661,54 +757,94 @@ getJasmineRequireObj().Env = function(j$) {
661
757
 
662
758
  return spec;
663
759
 
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
760
  function specResultCallback(result) {
673
- removeAllSpies();
674
- j$.Expectation.resetMatchers();
675
- customEqualityTesters = [];
761
+ clearResourcesForRunnable(spec.id);
676
762
  currentSpec = null;
677
763
  reporter.specDone(result);
678
764
  }
679
- };
680
765
 
681
- var suiteStarted = function(suite) {
682
- reporter.suiteStarted(suite.result);
766
+ function specStarted(spec) {
767
+ currentSpec = spec;
768
+ defaultResourcesForRunnable(spec.id, suite.id);
769
+ reporter.specStarted(spec.result);
770
+ }
683
771
  };
684
772
 
685
- this.it = function(description, fn) {
686
- var spec = specFactory(description, fn, currentSuite);
687
- currentSuite.addChild(spec);
773
+ this.it = function(description, fn, timeout) {
774
+ var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
775
+ currentDeclarationSuite.addChild(spec);
688
776
  return spec;
689
777
  };
690
778
 
691
- this.xit = function(description, fn) {
692
- var spec = this.it(description, fn);
779
+ this.xit = function() {
780
+ var spec = this.it.apply(this, arguments);
693
781
  spec.pend();
694
782
  return spec;
695
783
  };
696
784
 
785
+ this.fit = function(){
786
+ var spec = this.it.apply(this, arguments);
787
+
788
+ focusedRunnables.push(spec.id);
789
+ unfocusAncestor();
790
+ return spec;
791
+ };
792
+
697
793
  this.expect = function(actual) {
698
- return currentSpec.expect(actual);
794
+ if (!currentRunnable()) {
795
+ throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
796
+ }
797
+
798
+ return currentRunnable().expect(actual);
699
799
  };
700
800
 
701
- this.beforeEach = function(beforeEachFunction) {
702
- currentSuite.beforeEach(beforeEachFunction);
801
+ this.beforeEach = function(beforeEachFunction, timeout) {
802
+ currentDeclarationSuite.beforeEach({
803
+ fn: beforeEachFunction,
804
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
805
+ });
703
806
  };
704
807
 
705
- this.afterEach = function(afterEachFunction) {
706
- currentSuite.afterEach(afterEachFunction);
808
+ this.beforeAll = function(beforeAllFunction, timeout) {
809
+ currentDeclarationSuite.beforeAll({
810
+ fn: beforeAllFunction,
811
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
812
+ });
813
+ };
814
+
815
+ this.afterEach = function(afterEachFunction, timeout) {
816
+ currentDeclarationSuite.afterEach({
817
+ fn: afterEachFunction,
818
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
819
+ });
820
+ };
821
+
822
+ this.afterAll = function(afterAllFunction, timeout) {
823
+ currentDeclarationSuite.afterAll({
824
+ fn: afterAllFunction,
825
+ timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
826
+ });
707
827
  };
708
828
 
709
829
  this.pending = function() {
710
830
  throw j$.Spec.pendingSpecExceptionMessage;
711
831
  };
832
+
833
+ this.fail = function(error) {
834
+ var message = 'Failed';
835
+ if (error) {
836
+ message += ': ';
837
+ message += error.message || error;
838
+ }
839
+
840
+ currentRunnable().addExpectationResult(false, {
841
+ matcherName: '',
842
+ passed: false,
843
+ expected: '',
844
+ actual: '',
845
+ message: message
846
+ });
847
+ };
712
848
  }
713
849
 
714
850
  return Env;
@@ -723,7 +859,7 @@ getJasmineRequireObj().JsApiReporter = function() {
723
859
 
724
860
  function JsApiReporter(options) {
725
861
  var timer = options.timer || noopTimer,
726
- status = "loaded";
862
+ status = 'loaded';
727
863
 
728
864
  this.started = false;
729
865
  this.finished = false;
@@ -746,26 +882,31 @@ getJasmineRequireObj().JsApiReporter = function() {
746
882
  return status;
747
883
  };
748
884
 
749
- var suites = {};
885
+ var suites = [],
886
+ suites_hash = {};
750
887
 
751
888
  this.suiteStarted = function(result) {
752
- storeSuite(result);
889
+ suites_hash[result.id] = result;
753
890
  };
754
891
 
755
892
  this.suiteDone = function(result) {
756
893
  storeSuite(result);
757
894
  };
758
895
 
896
+ this.suiteResults = function(index, length) {
897
+ return suites.slice(index, index + length);
898
+ };
899
+
759
900
  function storeSuite(result) {
760
- suites[result.id] = result;
901
+ suites.push(result);
902
+ suites_hash[result.id] = result;
761
903
  }
762
904
 
763
905
  this.suites = function() {
764
- return suites;
906
+ return suites_hash;
765
907
  };
766
908
 
767
909
  var specs = [];
768
- this.specStarted = function(result) { };
769
910
 
770
911
  this.specDone = function(result) {
771
912
  specs.push(result);
@@ -819,7 +960,7 @@ getJasmineRequireObj().Any = function() {
819
960
  };
820
961
 
821
962
  Any.prototype.jasmineToString = function() {
822
- return '<jasmine.any(' + this.expectedClass + ')>';
963
+ return '<jasmine.any(' + this.expectedObject + ')>';
823
964
  };
824
965
 
825
966
  return Any;
@@ -877,7 +1018,7 @@ getJasmineRequireObj().CallTracker = function() {
877
1018
  };
878
1019
 
879
1020
  getJasmineRequireObj().Clock = function() {
880
- function Clock(global, delayedFunctionScheduler) {
1021
+ function Clock(global, delayedFunctionScheduler, mockDate) {
881
1022
  var self = this,
882
1023
  realTimingFunctions = {
883
1024
  setTimeout: global.setTimeout,
@@ -894,23 +1035,32 @@ getJasmineRequireObj().Clock = function() {
894
1035
  installed = false,
895
1036
  timer;
896
1037
 
1038
+
897
1039
  self.install = function() {
898
1040
  replace(global, fakeTimingFunctions);
899
1041
  timer = fakeTimingFunctions;
900
1042
  installed = true;
1043
+
1044
+ return self;
901
1045
  };
902
1046
 
903
1047
  self.uninstall = function() {
904
1048
  delayedFunctionScheduler.reset();
1049
+ mockDate.uninstall();
905
1050
  replace(global, realTimingFunctions);
1051
+
906
1052
  timer = realTimingFunctions;
907
1053
  installed = false;
908
1054
  };
909
1055
 
1056
+ self.mockDate = function(initialDate) {
1057
+ mockDate.install(initialDate);
1058
+ };
1059
+
910
1060
  self.setTimeout = function(fn, delay, params) {
911
1061
  if (legacyIE()) {
912
1062
  if (arguments.length > 2) {
913
- throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
1063
+ throw new Error('IE < 9 cannot support extra params to setTimeout without a polyfill');
914
1064
  }
915
1065
  return timer.setTimeout(fn, delay);
916
1066
  }
@@ -920,7 +1070,7 @@ getJasmineRequireObj().Clock = function() {
920
1070
  self.setInterval = function(fn, delay, params) {
921
1071
  if (legacyIE()) {
922
1072
  if (arguments.length > 2) {
923
- throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
1073
+ throw new Error('IE < 9 cannot support extra params to setInterval without a polyfill');
924
1074
  }
925
1075
  return timer.setInterval(fn, delay);
926
1076
  }
@@ -937,9 +1087,10 @@ getJasmineRequireObj().Clock = function() {
937
1087
 
938
1088
  self.tick = function(millis) {
939
1089
  if (installed) {
1090
+ mockDate.tick(millis);
940
1091
  delayedFunctionScheduler.tick(millis);
941
1092
  } else {
942
- throw new Error("Mock clock is not installed, use jasmine.clock().install()");
1093
+ throw new Error('Mock clock is not installed, use jasmine.clock().install()');
943
1094
  }
944
1095
  };
945
1096
 
@@ -973,7 +1124,7 @@ getJasmineRequireObj().Clock = function() {
973
1124
  }
974
1125
 
975
1126
  function argSlice(argsObj, n) {
976
- return Array.prototype.slice.call(argsObj, 2);
1127
+ return Array.prototype.slice.call(argsObj, n);
977
1128
  }
978
1129
  }
979
1130
 
@@ -1109,11 +1260,12 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
1109
1260
 
1110
1261
  for (var i = 0; i < funcsToRun.length; ++i) {
1111
1262
  var funcToRun = funcsToRun[i];
1112
- funcToRun.funcToCall.apply(null, funcToRun.params || []);
1113
1263
 
1114
1264
  if (funcToRun.recurring) {
1115
1265
  reschedule(funcToRun);
1116
1266
  }
1267
+
1268
+ funcToRun.funcToCall.apply(null, funcToRun.params || []);
1117
1269
  }
1118
1270
  } while (scheduledLookup.length > 0 &&
1119
1271
  // checking first if we're out of time prevents setTimeout(0)
@@ -1129,16 +1281,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
1129
1281
  getJasmineRequireObj().ExceptionFormatter = function() {
1130
1282
  function ExceptionFormatter() {
1131
1283
  this.message = function(error) {
1132
- var message = error.name +
1133
- ': ' +
1134
- error.message;
1284
+ var message = '';
1285
+
1286
+ if (error.name && error.message) {
1287
+ message += error.name + ': ' + error.message;
1288
+ } else {
1289
+ message += error.toString() + ' thrown';
1290
+ }
1135
1291
 
1136
1292
  if (error.fileName || error.sourceURL) {
1137
- message += " in " + (error.fileName || error.sourceURL);
1293
+ message += ' in ' + (error.fileName || error.sourceURL);
1138
1294
  }
1139
1295
 
1140
1296
  if (error.line || error.lineNumber) {
1141
- message += " (line " + (error.line || error.lineNumber) + ")";
1297
+ message += ' (line ' + (error.line || error.lineNumber) + ')';
1142
1298
  }
1143
1299
 
1144
1300
  return message;
@@ -1154,8 +1310,6 @@ getJasmineRequireObj().ExceptionFormatter = function() {
1154
1310
 
1155
1311
  getJasmineRequireObj().Expectation = function() {
1156
1312
 
1157
- var matchers = {};
1158
-
1159
1313
  function Expectation(options) {
1160
1314
  this.util = options.util || { buildFailureMessage: function() {} };
1161
1315
  this.customEqualityTesters = options.customEqualityTesters || [];
@@ -1163,8 +1317,9 @@ getJasmineRequireObj().Expectation = function() {
1163
1317
  this.addExpectationResult = options.addExpectationResult || function(){};
1164
1318
  this.isNot = options.isNot;
1165
1319
 
1166
- for (var matcherName in matchers) {
1167
- this[matcherName] = matchers[matcherName];
1320
+ var customMatchers = options.customMatchers || {};
1321
+ for (var matcherName in customMatchers) {
1322
+ this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
1168
1323
  }
1169
1324
  }
1170
1325
 
@@ -1172,7 +1327,7 @@ getJasmineRequireObj().Expectation = function() {
1172
1327
  return function() {
1173
1328
  var args = Array.prototype.slice.call(arguments, 0),
1174
1329
  expected = args.slice(0),
1175
- message = "";
1330
+ message = '';
1176
1331
 
1177
1332
  args.unshift(this.actual);
1178
1333
 
@@ -1197,7 +1352,11 @@ getJasmineRequireObj().Expectation = function() {
1197
1352
  args.unshift(name);
1198
1353
  message = this.util.buildFailureMessage.apply(null, args);
1199
1354
  } else {
1200
- message = result.message;
1355
+ if (Object.prototype.toString.apply(result.message) === '[object Function]') {
1356
+ message = result.message();
1357
+ } else {
1358
+ message = result.message;
1359
+ }
1201
1360
  }
1202
1361
  }
1203
1362
 
@@ -1227,19 +1386,6 @@ getJasmineRequireObj().Expectation = function() {
1227
1386
  }
1228
1387
  };
1229
1388
 
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
1389
  Expectation.Factory = function(options) {
1244
1390
  options = options || {};
1245
1391
 
@@ -1273,18 +1419,18 @@ getJasmineRequireObj().buildExpectationResult = function() {
1273
1419
 
1274
1420
  function message() {
1275
1421
  if (options.passed) {
1276
- return "Passed.";
1422
+ return 'Passed.';
1277
1423
  } else if (options.message) {
1278
1424
  return options.message;
1279
1425
  } else if (options.error) {
1280
1426
  return messageFormatter(options.error);
1281
1427
  }
1282
- return "";
1428
+ return '';
1283
1429
  }
1284
1430
 
1285
1431
  function stack() {
1286
1432
  if (options.passed) {
1287
- return "";
1433
+ return '';
1288
1434
  }
1289
1435
 
1290
1436
  var error = options.error;
@@ -1302,6 +1448,89 @@ getJasmineRequireObj().buildExpectationResult = function() {
1302
1448
  return buildExpectationResult;
1303
1449
  };
1304
1450
 
1451
+ getJasmineRequireObj().MockDate = function() {
1452
+ function MockDate(global) {
1453
+ var self = this;
1454
+ var currentTime = 0;
1455
+
1456
+ if (!global || !global.Date) {
1457
+ self.install = function() {};
1458
+ self.tick = function() {};
1459
+ self.uninstall = function() {};
1460
+ return self;
1461
+ }
1462
+
1463
+ var GlobalDate = global.Date;
1464
+
1465
+ self.install = function(mockDate) {
1466
+ if (mockDate instanceof GlobalDate) {
1467
+ currentTime = mockDate.getTime();
1468
+ } else {
1469
+ currentTime = new GlobalDate().getTime();
1470
+ }
1471
+
1472
+ global.Date = FakeDate;
1473
+ };
1474
+
1475
+ self.tick = function(millis) {
1476
+ millis = millis || 0;
1477
+ currentTime = currentTime + millis;
1478
+ };
1479
+
1480
+ self.uninstall = function() {
1481
+ currentTime = 0;
1482
+ global.Date = GlobalDate;
1483
+ };
1484
+
1485
+ createDateProperties();
1486
+
1487
+ return self;
1488
+
1489
+ function FakeDate() {
1490
+ switch(arguments.length) {
1491
+ case 0:
1492
+ return new GlobalDate(currentTime);
1493
+ case 1:
1494
+ return new GlobalDate(arguments[0]);
1495
+ case 2:
1496
+ return new GlobalDate(arguments[0], arguments[1]);
1497
+ case 3:
1498
+ return new GlobalDate(arguments[0], arguments[1], arguments[2]);
1499
+ case 4:
1500
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
1501
+ case 5:
1502
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1503
+ arguments[4]);
1504
+ case 6:
1505
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1506
+ arguments[4], arguments[5]);
1507
+ case 7:
1508
+ return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
1509
+ arguments[4], arguments[5], arguments[6]);
1510
+ }
1511
+ }
1512
+
1513
+ function createDateProperties() {
1514
+ FakeDate.prototype = GlobalDate.prototype;
1515
+
1516
+ FakeDate.now = function() {
1517
+ if (GlobalDate.now) {
1518
+ return currentTime;
1519
+ } else {
1520
+ throw new Error('Browser does not support Date.now()');
1521
+ }
1522
+ };
1523
+
1524
+ FakeDate.toSource = GlobalDate.toSource;
1525
+ FakeDate.toString = GlobalDate.toString;
1526
+ FakeDate.parse = GlobalDate.parse;
1527
+ FakeDate.UTC = GlobalDate.UTC;
1528
+ }
1529
+ }
1530
+
1531
+ return MockDate;
1532
+ };
1533
+
1305
1534
  getJasmineRequireObj().ObjectContaining = function(j$) {
1306
1535
 
1307
1536
  function ObjectContaining(sample) {
@@ -1309,7 +1538,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1309
1538
  }
1310
1539
 
1311
1540
  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+"'."); }
1541
+ if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
1313
1542
 
1314
1543
  mismatchKeys = mismatchKeys || [];
1315
1544
  mismatchValues = mismatchValues || [];
@@ -1320,10 +1549,10 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1320
1549
 
1321
1550
  for (var property in this.sample) {
1322
1551
  if (!hasKey(other, property) && hasKey(this.sample, property)) {
1323
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1552
+ mismatchKeys.push('expected has key \'' + property + '\', but missing from actual.');
1324
1553
  }
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.");
1554
+ else if (!j$.matchersUtil.equals(other[property], this.sample[property])) {
1555
+ 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
1556
  }
1328
1557
  }
1329
1558
 
@@ -1331,7 +1560,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
1331
1560
  };
1332
1561
 
1333
1562
  ObjectContaining.prototype.jasmineToString = function() {
1334
- return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
1563
+ return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
1335
1564
  };
1336
1565
 
1337
1566
  return ObjectContaining;
@@ -1341,6 +1570,7 @@ getJasmineRequireObj().pp = function(j$) {
1341
1570
 
1342
1571
  function PrettyPrinter() {
1343
1572
  this.ppNestLevel_ = 0;
1573
+ this.seen = [];
1344
1574
  }
1345
1575
 
1346
1576
  PrettyPrinter.prototype.format = function(value) {
@@ -1350,6 +1580,8 @@ getJasmineRequireObj().pp = function(j$) {
1350
1580
  this.emitScalar('undefined');
1351
1581
  } else if (value === null) {
1352
1582
  this.emitScalar('null');
1583
+ } else if (value === 0 && 1/value === -Infinity) {
1584
+ this.emitScalar('-0');
1353
1585
  } else if (value === j$.getGlobal()) {
1354
1586
  this.emitScalar('<global>');
1355
1587
  } else if (value.jasmineToString) {
@@ -1357,7 +1589,7 @@ getJasmineRequireObj().pp = function(j$) {
1357
1589
  } else if (typeof value === 'string') {
1358
1590
  this.emitString(value);
1359
1591
  } else if (j$.isSpy(value)) {
1360
- this.emitScalar("spy on " + value.and.identity());
1592
+ this.emitScalar('spy on ' + value.and.identity());
1361
1593
  } else if (value instanceof RegExp) {
1362
1594
  this.emitScalar(value.toString());
1363
1595
  } else if (typeof value === 'function') {
@@ -1366,16 +1598,16 @@ getJasmineRequireObj().pp = function(j$) {
1366
1598
  this.emitScalar('HTMLNode');
1367
1599
  } else if (value instanceof Date) {
1368
1600
  this.emitScalar('Date(' + value + ')');
1369
- } else if (value.__Jasmine_been_here_before__) {
1601
+ } else if (j$.util.arrayContains(this.seen, value)) {
1370
1602
  this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
1371
1603
  } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
1372
- value.__Jasmine_been_here_before__ = true;
1604
+ this.seen.push(value);
1373
1605
  if (j$.isArray_(value)) {
1374
1606
  this.emitArray(value);
1375
1607
  } else {
1376
1608
  this.emitObject(value);
1377
1609
  }
1378
- delete value.__Jasmine_been_here_before__;
1610
+ this.seen.pop();
1379
1611
  } else {
1380
1612
  this.emitScalar(value.toString());
1381
1613
  }
@@ -1386,8 +1618,7 @@ getJasmineRequireObj().pp = function(j$) {
1386
1618
 
1387
1619
  PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1388
1620
  for (var property in obj) {
1389
- if (!obj.hasOwnProperty(property)) { continue; }
1390
- if (property == '__Jasmine_been_here_before__') { continue; }
1621
+ if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
1391
1622
  fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
1392
1623
  obj.__lookupGetter__(property) !== null) : false);
1393
1624
  }
@@ -1411,28 +1642,31 @@ getJasmineRequireObj().pp = function(j$) {
1411
1642
  };
1412
1643
 
1413
1644
  StringPrettyPrinter.prototype.emitString = function(value) {
1414
- this.append("'" + value + "'");
1645
+ this.append('\'' + value + '\'');
1415
1646
  };
1416
1647
 
1417
1648
  StringPrettyPrinter.prototype.emitArray = function(array) {
1418
1649
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1419
- this.append("Array");
1650
+ this.append('Array');
1420
1651
  return;
1421
1652
  }
1422
-
1653
+ var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
1423
1654
  this.append('[ ');
1424
- for (var i = 0; i < array.length; i++) {
1655
+ for (var i = 0; i < length; i++) {
1425
1656
  if (i > 0) {
1426
1657
  this.append(', ');
1427
1658
  }
1428
1659
  this.format(array[i]);
1429
1660
  }
1661
+ if(array.length > length){
1662
+ this.append(', ...');
1663
+ }
1430
1664
  this.append(' ]');
1431
1665
  };
1432
1666
 
1433
1667
  StringPrettyPrinter.prototype.emitObject = function(obj) {
1434
1668
  if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1435
- this.append("Object");
1669
+ this.append('Object');
1436
1670
  return;
1437
1671
  }
1438
1672
 
@@ -1448,7 +1682,7 @@ getJasmineRequireObj().pp = function(j$) {
1448
1682
  }
1449
1683
 
1450
1684
  self.append(property);
1451
- self.append(' : ');
1685
+ self.append(': ');
1452
1686
  if (isGetter) {
1453
1687
  self.append('<getter>');
1454
1688
  } else {
@@ -1470,32 +1704,45 @@ getJasmineRequireObj().pp = function(j$) {
1470
1704
  };
1471
1705
  };
1472
1706
 
1473
- getJasmineRequireObj().QueueRunner = function() {
1707
+ getJasmineRequireObj().QueueRunner = function(j$) {
1708
+
1709
+ function once(fn) {
1710
+ var called = false;
1711
+ return function() {
1712
+ if (!called) {
1713
+ called = true;
1714
+ fn();
1715
+ }
1716
+ };
1717
+ }
1474
1718
 
1475
1719
  function QueueRunner(attrs) {
1476
- this.fns = attrs.fns || [];
1720
+ this.queueableFns = attrs.queueableFns || [];
1477
1721
  this.onComplete = attrs.onComplete || function() {};
1478
1722
  this.clearStack = attrs.clearStack || function(fn) {fn();};
1479
1723
  this.onException = attrs.onException || function() {};
1480
1724
  this.catchException = attrs.catchException || function() { return true; };
1481
- this.userContext = {};
1725
+ this.userContext = attrs.userContext || {};
1726
+ this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
1727
+ this.fail = attrs.fail || function() {};
1482
1728
  }
1483
1729
 
1484
1730
  QueueRunner.prototype.execute = function() {
1485
- this.run(this.fns, 0);
1731
+ this.run(this.queueableFns, 0);
1486
1732
  };
1487
1733
 
1488
- QueueRunner.prototype.run = function(fns, recursiveIndex) {
1489
- var length = fns.length,
1490
- self = this,
1491
- iterativeIndex;
1734
+ QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
1735
+ var length = queueableFns.length,
1736
+ self = this,
1737
+ iterativeIndex;
1738
+
1492
1739
 
1493
1740
  for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
1494
- var fn = fns[iterativeIndex];
1495
- if (fn.length > 0) {
1496
- return attemptAsync(fn);
1741
+ var queueableFn = queueableFns[iterativeIndex];
1742
+ if (queueableFn.fn.length > 0) {
1743
+ return attemptAsync(queueableFn);
1497
1744
  } else {
1498
- attemptSync(fn);
1745
+ attemptSync(queueableFn);
1499
1746
  }
1500
1747
  }
1501
1748
 
@@ -1505,27 +1752,51 @@ getJasmineRequireObj().QueueRunner = function() {
1505
1752
  this.clearStack(this.onComplete);
1506
1753
  }
1507
1754
 
1508
- function attemptSync(fn) {
1755
+ function attemptSync(queueableFn) {
1509
1756
  try {
1510
- fn.call(self.userContext);
1757
+ queueableFn.fn.call(self.userContext);
1511
1758
  } catch (e) {
1512
- handleException(e);
1759
+ handleException(e, queueableFn);
1513
1760
  }
1514
1761
  }
1515
1762
 
1516
- function attemptAsync(fn) {
1517
- var next = function () { self.run(fns, iterativeIndex + 1); };
1763
+ function attemptAsync(queueableFn) {
1764
+ var clearTimeout = function () {
1765
+ Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
1766
+ },
1767
+ next = once(function () {
1768
+ clearTimeout(timeoutId);
1769
+ self.run(queueableFns, iterativeIndex + 1);
1770
+ }),
1771
+ timeoutId;
1772
+
1773
+ next.fail = function() {
1774
+ self.fail.apply(null, arguments);
1775
+ next();
1776
+ };
1777
+
1778
+ if (queueableFn.timeout) {
1779
+ timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
1780
+ var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
1781
+ onException(error, queueableFn);
1782
+ next();
1783
+ }, queueableFn.timeout()]]);
1784
+ }
1518
1785
 
1519
1786
  try {
1520
- fn.call(self.userContext, next);
1787
+ queueableFn.fn.call(self.userContext, next);
1521
1788
  } catch (e) {
1522
- handleException(e);
1789
+ handleException(e, queueableFn);
1523
1790
  next();
1524
1791
  }
1525
1792
  }
1526
1793
 
1527
- function handleException(e) {
1794
+ function onException(e, queueableFn) {
1528
1795
  self.onException(e);
1796
+ }
1797
+
1798
+ function handleException(e, queueableFn) {
1799
+ onException(e, queueableFn);
1529
1800
  if (!self.catchException(e)) {
1530
1801
  //TODO: set a var when we catch an exception and
1531
1802
  //use a finally block to close the loop in a nice way..
@@ -1573,12 +1844,58 @@ getJasmineRequireObj().ReportDispatcher = function() {
1573
1844
  };
1574
1845
 
1575
1846
 
1847
+ getJasmineRequireObj().SpyRegistry = function(j$) {
1848
+
1849
+ function SpyRegistry(options) {
1850
+ options = options || {};
1851
+ var currentSpies = options.currentSpies || function() { return []; };
1852
+
1853
+ this.spyOn = function(obj, methodName) {
1854
+ if (j$.util.isUndefined(obj)) {
1855
+ throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
1856
+ }
1857
+
1858
+ if (j$.util.isUndefined(obj[methodName])) {
1859
+ throw new Error(methodName + '() method does not exist');
1860
+ }
1861
+
1862
+ if (obj[methodName] && j$.isSpy(obj[methodName])) {
1863
+ //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
1864
+ throw new Error(methodName + ' has already been spied upon');
1865
+ }
1866
+
1867
+ var spy = j$.createSpy(methodName, obj[methodName]);
1868
+
1869
+ currentSpies().push({
1870
+ spy: spy,
1871
+ baseObj: obj,
1872
+ methodName: methodName,
1873
+ originalValue: obj[methodName]
1874
+ });
1875
+
1876
+ obj[methodName] = spy;
1877
+
1878
+ return spy;
1879
+ };
1880
+
1881
+ this.clearSpies = function() {
1882
+ var spies = currentSpies();
1883
+ for (var i = 0; i < spies.length; i++) {
1884
+ var spyEntry = spies[i];
1885
+ spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
1886
+ }
1887
+ };
1888
+ }
1889
+
1890
+ return SpyRegistry;
1891
+ };
1892
+
1576
1893
  getJasmineRequireObj().SpyStrategy = function() {
1577
1894
 
1578
1895
  function SpyStrategy(options) {
1579
1896
  options = options || {};
1580
1897
 
1581
- var identity = options.name || "unknown",
1898
+ var identity = options.name || 'unknown',
1582
1899
  originalFn = options.fn || function() {},
1583
1900
  getSpy = options.getSpy || function() {},
1584
1901
  plan = function() {};
@@ -1603,6 +1920,14 @@ getJasmineRequireObj().SpyStrategy = function() {
1603
1920
  return getSpy();
1604
1921
  };
1605
1922
 
1923
+ this.returnValues = function() {
1924
+ var values = Array.prototype.slice.call(arguments);
1925
+ plan = function () {
1926
+ return values.shift();
1927
+ };
1928
+ return getSpy();
1929
+ };
1930
+
1606
1931
  this.throwError = function(something) {
1607
1932
  var error = (something instanceof Error) ? something : new Error(something);
1608
1933
  plan = function() {
@@ -1634,9 +1959,13 @@ getJasmineRequireObj().Suite = function() {
1634
1959
  this.onStart = attrs.onStart || function() {};
1635
1960
  this.resultCallback = attrs.resultCallback || function() {};
1636
1961
  this.clearStack = attrs.clearStack || function(fn) {fn();};
1962
+ this.expectationFactory = attrs.expectationFactory;
1963
+ this.expectationResultFactory = attrs.expectationResultFactory;
1637
1964
 
1638
1965
  this.beforeFns = [];
1639
1966
  this.afterFns = [];
1967
+ this.beforeAllFns = [];
1968
+ this.afterAllFns = [];
1640
1969
  this.queueRunner = attrs.queueRunner || function() {};
1641
1970
  this.disabled = false;
1642
1971
 
@@ -1644,12 +1973,16 @@ getJasmineRequireObj().Suite = function() {
1644
1973
 
1645
1974
  this.result = {
1646
1975
  id: this.id,
1647
- status: this.disabled ? 'disabled' : '',
1648
1976
  description: this.description,
1649
- fullName: this.getFullName()
1977
+ fullName: this.getFullName(),
1978
+ failedExpectations: []
1650
1979
  };
1651
1980
  }
1652
1981
 
1982
+ Suite.prototype.expect = function(actual) {
1983
+ return this.expectationFactory(actual, this);
1984
+ };
1985
+
1653
1986
  Suite.prototype.getFullName = function() {
1654
1987
  var fullName = this.description;
1655
1988
  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
@@ -1668,16 +2001,39 @@ getJasmineRequireObj().Suite = function() {
1668
2001
  this.beforeFns.unshift(fn);
1669
2002
  };
1670
2003
 
2004
+ Suite.prototype.beforeAll = function(fn) {
2005
+ this.beforeAllFns.push(fn);
2006
+ };
2007
+
1671
2008
  Suite.prototype.afterEach = function(fn) {
1672
2009
  this.afterFns.unshift(fn);
1673
2010
  };
1674
2011
 
2012
+ Suite.prototype.afterAll = function(fn) {
2013
+ this.afterAllFns.push(fn);
2014
+ };
2015
+
1675
2016
  Suite.prototype.addChild = function(child) {
1676
2017
  this.children.push(child);
1677
2018
  };
1678
2019
 
2020
+ Suite.prototype.status = function() {
2021
+ if (this.disabled) {
2022
+ return 'disabled';
2023
+ }
2024
+
2025
+ if (this.result.failedExpectations.length > 0) {
2026
+ return 'failed';
2027
+ } else {
2028
+ return 'finished';
2029
+ }
2030
+ };
2031
+
1679
2032
  Suite.prototype.execute = function(onComplete) {
1680
2033
  var self = this;
2034
+
2035
+ this.onStart(this);
2036
+
1681
2037
  if (this.disabled) {
1682
2038
  complete();
1683
2039
  return;
@@ -1685,18 +2041,25 @@ getJasmineRequireObj().Suite = function() {
1685
2041
 
1686
2042
  var allFns = [];
1687
2043
 
1688
- for (var i = 0; i < this.children.length; i++) {
1689
- allFns.push(wrapChildAsAsync(this.children[i]));
1690
- }
2044
+ if (this.isExecutable()) {
2045
+ allFns = allFns.concat(this.beforeAllFns);
1691
2046
 
1692
- this.onStart(this);
2047
+ for (var i = 0; i < this.children.length; i++) {
2048
+ allFns.push(wrapChildAsAsync(this.children[i]));
2049
+ }
2050
+
2051
+ allFns = allFns.concat(this.afterAllFns);
2052
+ }
1693
2053
 
1694
2054
  this.queueRunner({
1695
- fns: allFns,
1696
- onComplete: complete
2055
+ queueableFns: allFns,
2056
+ onComplete: complete,
2057
+ userContext: this.sharedUserContext(),
2058
+ onException: function() { self.onException.apply(self, arguments); }
1697
2059
  });
1698
2060
 
1699
2061
  function complete() {
2062
+ self.result.status = self.status();
1700
2063
  self.resultCallback(self.result);
1701
2064
 
1702
2065
  if (onComplete) {
@@ -1705,23 +2068,99 @@ getJasmineRequireObj().Suite = function() {
1705
2068
  }
1706
2069
 
1707
2070
  function wrapChildAsAsync(child) {
1708
- return function(done) { child.execute(done); };
2071
+ return { fn: function(done) { child.execute(done); } };
2072
+ }
2073
+ };
2074
+
2075
+ Suite.prototype.isExecutable = function() {
2076
+ var foundActive = false;
2077
+ for(var i = 0; i < this.children.length; i++) {
2078
+ if(this.children[i].isExecutable()) {
2079
+ foundActive = true;
2080
+ break;
2081
+ }
2082
+ }
2083
+ return foundActive;
2084
+ };
2085
+
2086
+ Suite.prototype.sharedUserContext = function() {
2087
+ if (!this.sharedContext) {
2088
+ this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
2089
+ }
2090
+
2091
+ return this.sharedContext;
2092
+ };
2093
+
2094
+ Suite.prototype.clonedSharedUserContext = function() {
2095
+ return clone(this.sharedUserContext());
2096
+ };
2097
+
2098
+ Suite.prototype.onException = function() {
2099
+ if(isAfterAll(this.children)) {
2100
+ var data = {
2101
+ matcherName: '',
2102
+ passed: false,
2103
+ expected: '',
2104
+ actual: '',
2105
+ error: arguments[0]
2106
+ };
2107
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
2108
+ } else {
2109
+ for (var i = 0; i < this.children.length; i++) {
2110
+ var child = this.children[i];
2111
+ child.onException.apply(child, arguments);
2112
+ }
2113
+ }
2114
+ };
2115
+
2116
+ Suite.prototype.addExpectationResult = function () {
2117
+ if(isAfterAll(this.children) && isFailure(arguments)){
2118
+ var data = arguments[1];
2119
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
2120
+ } else {
2121
+ for (var i = 0; i < this.children.length; i++) {
2122
+ var child = this.children[i];
2123
+ child.addExpectationResult.apply(child, arguments);
2124
+ }
1709
2125
  }
1710
2126
  };
1711
2127
 
2128
+ function isAfterAll(children) {
2129
+ return children && children[0].result.status;
2130
+ }
2131
+
2132
+ function isFailure(args) {
2133
+ return !args[0];
2134
+ }
2135
+
2136
+ function clone(obj) {
2137
+ var clonedObj = {};
2138
+ for (var prop in obj) {
2139
+ if (obj.hasOwnProperty(prop)) {
2140
+ clonedObj[prop] = obj[prop];
2141
+ }
2142
+ }
2143
+
2144
+ return clonedObj;
2145
+ }
2146
+
1712
2147
  return Suite;
1713
2148
  };
1714
2149
 
1715
- if (typeof window == void 0 && typeof exports == "object") {
2150
+ if (typeof window == void 0 && typeof exports == 'object') {
1716
2151
  exports.Suite = jasmineRequire.Suite;
1717
2152
  }
1718
2153
 
1719
2154
  getJasmineRequireObj().Timer = function() {
2155
+ var defaultNow = (function(Date) {
2156
+ return function() { return new Date().getTime(); };
2157
+ })(Date);
2158
+
1720
2159
  function Timer(options) {
1721
2160
  options = options || {};
1722
2161
 
1723
- var now = options.now || function() { return new Date().getTime(); },
1724
- startTime;
2162
+ var now = options.now || defaultNow,
2163
+ startTime;
1725
2164
 
1726
2165
  this.start = function() {
1727
2166
  startTime = now();
@@ -1748,7 +2187,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1748
2187
  contains: function(haystack, needle, customTesters) {
1749
2188
  customTesters = customTesters || [];
1750
2189
 
1751
- if (Object.prototype.toString.apply(haystack) === "[object Array]") {
2190
+ if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
2191
+ (!!haystack && !haystack.indexOf))
2192
+ {
1752
2193
  for (var i = 0; i < haystack.length; i++) {
1753
2194
  if (eq(haystack[i], needle, [], [], customTesters)) {
1754
2195
  return true;
@@ -1756,7 +2197,8 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1756
2197
  }
1757
2198
  return false;
1758
2199
  }
1759
- return haystack.indexOf(needle) >= 0;
2200
+
2201
+ return !!haystack && haystack.indexOf(needle) >= 0;
1760
2202
  },
1761
2203
 
1762
2204
  buildFailureMessage: function() {
@@ -1767,21 +2209,21 @@ getJasmineRequireObj().matchersUtil = function(j$) {
1767
2209
  expected = args.slice(3),
1768
2210
  englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1769
2211
 
1770
- var message = "Expected " +
2212
+ var message = 'Expected ' +
1771
2213
  j$.pp(actual) +
1772
- (isNot ? " not " : " ") +
2214
+ (isNot ? ' not ' : ' ') +
1773
2215
  englishyPredicate;
1774
2216
 
1775
2217
  if (expected.length > 0) {
1776
2218
  for (var i = 0; i < expected.length; i++) {
1777
2219
  if (i > 0) {
1778
- message += ",";
2220
+ message += ',';
1779
2221
  }
1780
- message += " " + j$.pp(expected[i]);
2222
+ message += ' ' + j$.pp(expected[i]);
1781
2223
  }
1782
2224
  }
1783
2225
 
1784
- return message + ".";
2226
+ return message + '.';
1785
2227
  }
1786
2228
  };
1787
2229
 
@@ -2018,9 +2460,9 @@ getJasmineRequireObj().toBeNaN = function(j$) {
2018
2460
  };
2019
2461
 
2020
2462
  if (result.pass) {
2021
- result.message = "Expected actual not to be NaN.";
2463
+ result.message = 'Expected actual not to be NaN.';
2022
2464
  } else {
2023
- result.message = "Expected " + j$.pp(actual) + " to be NaN.";
2465
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
2024
2466
  }
2025
2467
 
2026
2468
  return result;
@@ -2132,8 +2574,8 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2132
2574
  result.pass = actual.calls.any();
2133
2575
 
2134
2576
  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.";
2577
+ 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
2578
+ 'Expected spy ' + actual.and.identity() + ' to have been called.';
2137
2579
 
2138
2580
  return result;
2139
2581
  }
@@ -2145,7 +2587,7 @@ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2145
2587
 
2146
2588
  getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2147
2589
 
2148
- function toHaveBeenCalledWith(util) {
2590
+ function toHaveBeenCalledWith(util, customEqualityTesters) {
2149
2591
  return {
2150
2592
  compare: function() {
2151
2593
  var args = Array.prototype.slice.call(arguments, 0),
@@ -2158,15 +2600,15 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2158
2600
  }
2159
2601
 
2160
2602
  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.";
2603
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
2162
2604
  return result;
2163
2605
  }
2164
2606
 
2165
- if (util.contains(actual.calls.allArgs(), expectedArgs)) {
2607
+ if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
2166
2608
  result.pass = true;
2167
- result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
2609
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
2168
2610
  } 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, '') + ".";
2611
+ 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
2612
  }
2171
2613
 
2172
2614
  return result;
@@ -2203,8 +2645,8 @@ getJasmineRequireObj().toThrow = function(j$) {
2203
2645
  threw = false,
2204
2646
  thrown;
2205
2647
 
2206
- if (typeof actual != "function") {
2207
- throw new Error("Actual is not a Function");
2648
+ if (typeof actual != 'function') {
2649
+ throw new Error('Actual is not a Function');
2208
2650
  }
2209
2651
 
2210
2652
  try {
@@ -2215,22 +2657,22 @@ getJasmineRequireObj().toThrow = function(j$) {
2215
2657
  }
2216
2658
 
2217
2659
  if (!threw) {
2218
- result.message = "Expected function to throw an exception.";
2660
+ result.message = 'Expected function to throw an exception.';
2219
2661
  return result;
2220
2662
  }
2221
2663
 
2222
2664
  if (arguments.length == 1) {
2223
2665
  result.pass = true;
2224
- result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
2666
+ result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
2225
2667
 
2226
2668
  return result;
2227
2669
  }
2228
2670
 
2229
2671
  if (util.equals(thrown, expected)) {
2230
2672
  result.pass = true;
2231
- result.message = "Expected function not to throw " + j$.pp(expected) + ".";
2673
+ result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
2232
2674
  } else {
2233
- result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";
2675
+ result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
2234
2676
  }
2235
2677
 
2236
2678
  return result;
@@ -2246,18 +2688,15 @@ getJasmineRequireObj().toThrowError = function(j$) {
2246
2688
  return {
2247
2689
  compare: function(actual) {
2248
2690
  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");
2691
+ pass = {pass: true},
2692
+ fail = {pass: false},
2693
+ thrown;
2694
+
2695
+ if (typeof actual != 'function') {
2696
+ throw new Error('Actual is not a Function');
2258
2697
  }
2259
2698
 
2260
- extractExpectedParams.apply(null, arguments);
2699
+ var errorMatcher = getMatcher.apply(null, arguments);
2261
2700
 
2262
2701
  try {
2263
2702
  actual();
@@ -2267,136 +2706,202 @@ getJasmineRequireObj().toThrowError = function(j$) {
2267
2706
  }
2268
2707
 
2269
2708
  if (!threw) {
2270
- return fail("Expected function to throw an Error.");
2709
+ fail.message = 'Expected function to throw an Error.';
2710
+ return fail;
2271
2711
  }
2272
2712
 
2273
2713
  if (!(thrown instanceof Error)) {
2274
- return fail("Expected function to throw an Error, but it threw " + thrown + ".");
2714
+ fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
2715
+ return fail;
2275
2716
  }
2276
2717
 
2277
- if (arguments.length == 1) {
2278
- return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
2718
+ if (errorMatcher.hasNoSpecifics()) {
2719
+ pass.message = 'Expected function not to throw an Error, but it threw ' + fnNameFor(thrown) + '.';
2720
+ return pass;
2279
2721
  }
2280
2722
 
2281
- if (errorType) {
2282
- name = fnNameFor(errorType);
2283
- constructorName = fnNameFor(thrown.constructor);
2723
+ if (errorMatcher.matches(thrown)) {
2724
+ pass.message = function() {
2725
+ return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
2726
+ };
2727
+ return pass;
2728
+ } else {
2729
+ fail.message = function() {
2730
+ return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
2731
+ ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
2732
+ };
2733
+ return fail;
2284
2734
  }
2735
+ }
2736
+ };
2285
2737
 
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
- }
2738
+ function getMatcher() {
2739
+ var expected = null,
2740
+ errorType = null;
2294
2741
 
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
- }
2742
+ if (arguments.length == 2) {
2743
+ expected = arguments[1];
2744
+ if (isAnErrorType(expected)) {
2745
+ errorType = expected;
2746
+ expected = null;
2302
2747
  }
2748
+ } else if (arguments.length > 2) {
2749
+ errorType = arguments[1];
2750
+ expected = arguments[2];
2751
+ if (!isAnErrorType(errorType)) {
2752
+ throw new Error('Expected error type is not an Error.');
2753
+ }
2754
+ }
2303
2755
 
2756
+ if (expected && !isStringOrRegExp(expected)) {
2304
2757
  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
- }
2758
+ throw new Error('Expected error message is not a string or RegExp.');
2759
+ } else {
2760
+ throw new Error('Expected is not an Error, string, or RegExp.');
2310
2761
  }
2762
+ }
2311
2763
 
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
- }
2764
+ function messageMatch(message) {
2765
+ if (typeof expected == 'string') {
2766
+ return expected == message;
2767
+ } else {
2768
+ return expected.test(message);
2319
2769
  }
2770
+ }
2771
+
2772
+ return {
2773
+ errorTypeDescription: errorType ? fnNameFor(errorType) : 'an exception',
2774
+ thrownDescription: function(thrown) {
2775
+ var thrownName = errorType ? fnNameFor(thrown.constructor) : 'an exception',
2776
+ thrownMessage = '';
2320
2777
 
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) + ".");
2778
+ if (expected) {
2779
+ thrownMessage = ' with message ' + j$.pp(thrown.message);
2780
+ }
2781
+
2782
+ return thrownName + thrownMessage;
2783
+ },
2784
+ messageDescription: function() {
2785
+ if (expected === null) {
2786
+ return '';
2787
+ } else if (expected instanceof RegExp) {
2788
+ return ' with a message matching ' + j$.pp(expected);
2324
2789
  } 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) + ".");
2790
+ return ' with message ' + j$.pp(expected);
2327
2791
  }
2792
+ },
2793
+ hasNoSpecifics: function() {
2794
+ return expected === null && errorType === null;
2795
+ },
2796
+ matches: function(error) {
2797
+ return (errorType === null || error.constructor === errorType) &&
2798
+ (expected === null || messageMatch(error.message));
2328
2799
  }
2800
+ };
2801
+ }
2329
2802
 
2330
- function fnNameFor(func) {
2331
- return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2332
- }
2803
+ function fnNameFor(func) {
2804
+ return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2805
+ }
2333
2806
 
2334
- function pass(notMessage) {
2335
- return {
2336
- pass: true,
2337
- message: notMessage
2338
- };
2339
- }
2807
+ function isStringOrRegExp(potential) {
2808
+ return potential instanceof RegExp || (typeof potential == 'string');
2809
+ }
2340
2810
 
2341
- function fail(message) {
2342
- return {
2343
- pass: false,
2344
- message: message
2345
- };
2346
- }
2811
+ function isAnErrorType(type) {
2812
+ if (typeof type !== 'function') {
2813
+ return false;
2814
+ }
2347
2815
 
2348
- function extractExpectedParams() {
2349
- if (arguments.length == 1) {
2350
- return;
2351
- }
2816
+ var Surrogate = function() {};
2817
+ Surrogate.prototype = type.prototype;
2818
+ return (new Surrogate()) instanceof Error;
2819
+ }
2820
+ }
2352
2821
 
2353
- if (arguments.length == 2) {
2354
- var expected = arguments[1];
2822
+ return toThrowError;
2823
+ };
2355
2824
 
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
- }
2825
+ getJasmineRequireObj().interface = function(jasmine, env) {
2826
+ var jasmineInterface = {
2827
+ describe: function(description, specDefinitions) {
2828
+ return env.describe(description, specDefinitions);
2829
+ },
2363
2830
 
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
- }
2831
+ xdescribe: function(description, specDefinitions) {
2832
+ return env.xdescribe(description, specDefinitions);
2833
+ },
2383
2834
 
2384
- function checkForAnErrorType(type) {
2385
- if (typeof type !== "function") {
2386
- return false;
2387
- }
2835
+ fdescribe: function(description, specDefinitions) {
2836
+ return env.fdescribe(description, specDefinitions);
2837
+ },
2388
2838
 
2389
- var Surrogate = function() {};
2390
- Surrogate.prototype = type.prototype;
2391
- return (new Surrogate()) instanceof Error;
2392
- }
2393
- }
2394
- };
2395
- }
2839
+ it: function(desc, func) {
2840
+ return env.it(desc, func);
2841
+ },
2396
2842
 
2397
- return toThrowError;
2843
+ xit: function(desc, func) {
2844
+ return env.xit(desc, func);
2845
+ },
2846
+
2847
+ fit: function(desc, func) {
2848
+ return env.fit(desc, func);
2849
+ },
2850
+
2851
+ beforeEach: function(beforeEachFunction) {
2852
+ return env.beforeEach(beforeEachFunction);
2853
+ },
2854
+
2855
+ afterEach: function(afterEachFunction) {
2856
+ return env.afterEach(afterEachFunction);
2857
+ },
2858
+
2859
+ beforeAll: function(beforeAllFunction) {
2860
+ return env.beforeAll(beforeAllFunction);
2861
+ },
2862
+
2863
+ afterAll: function(afterAllFunction) {
2864
+ return env.afterAll(afterAllFunction);
2865
+ },
2866
+
2867
+ expect: function(actual) {
2868
+ return env.expect(actual);
2869
+ },
2870
+
2871
+ pending: function() {
2872
+ return env.pending();
2873
+ },
2874
+
2875
+ fail: function() {
2876
+ return env.fail.apply(env, arguments);
2877
+ },
2878
+
2879
+ spyOn: function(obj, methodName) {
2880
+ return env.spyOn(obj, methodName);
2881
+ },
2882
+
2883
+ jsApiReporter: new jasmine.JsApiReporter({
2884
+ timer: new jasmine.Timer()
2885
+ }),
2886
+
2887
+ jasmine: jasmine
2888
+ };
2889
+
2890
+ jasmine.addCustomEqualityTester = function(tester) {
2891
+ env.addCustomEqualityTester(tester);
2892
+ };
2893
+
2894
+ jasmine.addMatchers = function(matchers) {
2895
+ return env.addMatchers(matchers);
2896
+ };
2897
+
2898
+ jasmine.clock = function() {
2899
+ return env.clock;
2900
+ };
2901
+
2902
+ return jasmineInterface;
2398
2903
  };
2399
2904
 
2400
2905
  getJasmineRequireObj().version = function() {
2401
- return "2.0.0";
2906
+ return '2.1.0';
2402
2907
  };