jasmine-core 2.5.0 → 2.99.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/console/console.js +1 -1
  3. data/lib/jasmine-core/boot/boot.js +4 -1
  4. data/lib/jasmine-core/boot.js +5 -2
  5. data/lib/jasmine-core/jasmine-html.js +95 -31
  6. data/lib/jasmine-core/jasmine.css +1 -0
  7. data/lib/jasmine-core/jasmine.js +3635 -1684
  8. data/lib/jasmine-core/node_boot.js +1 -1
  9. data/lib/jasmine-core/spec/core/CallTrackerSpec.js +10 -0
  10. data/lib/jasmine-core/spec/core/ClearStackSpec.js +137 -0
  11. data/lib/jasmine-core/spec/core/ClockSpec.js +94 -14
  12. data/lib/jasmine-core/spec/core/DelayedFunctionSchedulerSpec.js +26 -8
  13. data/lib/jasmine-core/spec/core/EnvSpec.js +142 -10
  14. data/lib/jasmine-core/spec/core/ExpectationSpec.js +52 -7
  15. data/lib/jasmine-core/spec/core/GlobalErrorsSpec.js +110 -0
  16. data/lib/jasmine-core/spec/core/PrettyPrintSpec.js +132 -4
  17. data/lib/jasmine-core/spec/core/QueueRunnerSpec.js +333 -23
  18. data/lib/jasmine-core/spec/core/ReportDispatcherSpec.js +16 -1
  19. data/lib/jasmine-core/spec/core/SpecSpec.js +30 -8
  20. data/lib/jasmine-core/spec/core/SpyRegistrySpec.js +225 -1
  21. data/lib/jasmine-core/spec/core/SpySpec.js +44 -2
  22. data/lib/jasmine-core/spec/core/SpyStrategySpec.js +28 -5
  23. data/lib/jasmine-core/spec/core/SuiteSpec.js +14 -19
  24. data/lib/jasmine-core/spec/core/UserContextSpec.js +54 -0
  25. data/lib/jasmine-core/spec/core/UtilSpec.js +71 -0
  26. data/lib/jasmine-core/spec/core/asymmetric_equality/AnySpec.js +32 -0
  27. data/lib/jasmine-core/spec/core/asymmetric_equality/AnythingSpec.js +32 -0
  28. data/lib/jasmine-core/spec/core/asymmetric_equality/ArrayContainingSpec.js +13 -0
  29. data/lib/jasmine-core/spec/core/asymmetric_equality/ArrayWithExactContentsSpec.js +47 -0
  30. data/lib/jasmine-core/spec/core/asymmetric_equality/ObjectContainingSpec.js +13 -0
  31. data/lib/jasmine-core/spec/core/integration/CustomMatchersSpec.js +48 -0
  32. data/lib/jasmine-core/spec/core/integration/EnvSpec.js +339 -38
  33. data/lib/jasmine-core/spec/core/integration/SpecRunningSpec.js +156 -3
  34. data/lib/jasmine-core/spec/core/matchers/DiffBuilderSpec.js +47 -0
  35. data/lib/jasmine-core/spec/core/matchers/NullDiffBuilderSpec.js +13 -0
  36. data/lib/jasmine-core/spec/core/matchers/ObjectPathSpec.js +43 -0
  37. data/lib/jasmine-core/spec/core/matchers/matchersUtilSpec.js +231 -8
  38. data/lib/jasmine-core/spec/core/matchers/nothingSpec.js +8 -0
  39. data/lib/jasmine-core/spec/core/matchers/toBeCloseToSpec.js +42 -0
  40. data/lib/jasmine-core/spec/core/matchers/toBeNegativeInfinitySpec.js +31 -0
  41. data/lib/jasmine-core/spec/core/matchers/toBePositiveInfinitySpec.js +31 -0
  42. data/lib/jasmine-core/spec/core/matchers/toEqualSpec.js +780 -4
  43. data/lib/jasmine-core/spec/core/matchers/toHaveBeenCalledBeforeSpec.js +99 -0
  44. data/lib/jasmine-core/spec/core/matchers/toThrowErrorSpec.js +37 -0
  45. data/lib/jasmine-core/spec/helpers/BrowserFlags.js +4 -0
  46. data/lib/jasmine-core/spec/helpers/asyncAwait.js +27 -0
  47. data/lib/jasmine-core/spec/helpers/checkForMap.js +37 -0
  48. data/lib/jasmine-core/spec/helpers/checkForSet.js +41 -0
  49. data/lib/jasmine-core/spec/helpers/checkForSymbol.js +28 -0
  50. data/lib/jasmine-core/spec/helpers/checkForTypedArrays.js +20 -0
  51. data/lib/jasmine-core/spec/html/HtmlReporterSpec.js +105 -23
  52. data/lib/jasmine-core/spec/html/SpyRegistryHtmlSpec.js +34 -0
  53. data/lib/jasmine-core/spec/npmPackage/npmPackageSpec.js +1 -1
  54. data/lib/jasmine-core/version.rb +1 -1
  55. metadata +19 -4
@@ -0,0 +1,110 @@
1
+ describe("GlobalErrors", function() {
2
+ it("calls the added handler on error", function() {
3
+ var fakeGlobal = { onerror: null },
4
+ handler = jasmine.createSpy('errorHandler'),
5
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
6
+
7
+ errors.install();
8
+ errors.pushListener(handler);
9
+
10
+ fakeGlobal.onerror('foo');
11
+
12
+ expect(handler).toHaveBeenCalledWith('foo');
13
+ });
14
+
15
+ it("only calls the most recent handler", function() {
16
+ var fakeGlobal = { onerror: null },
17
+ handler1 = jasmine.createSpy('errorHandler1'),
18
+ handler2 = jasmine.createSpy('errorHandler2'),
19
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
20
+
21
+ errors.install();
22
+ errors.pushListener(handler1);
23
+ errors.pushListener(handler2);
24
+
25
+ fakeGlobal.onerror('foo');
26
+
27
+ expect(handler1).not.toHaveBeenCalled();
28
+ expect(handler2).toHaveBeenCalledWith('foo');
29
+ });
30
+
31
+ it("calls previous handlers when one is removed", function() {
32
+ var fakeGlobal = { onerror: null },
33
+ handler1 = jasmine.createSpy('errorHandler1'),
34
+ handler2 = jasmine.createSpy('errorHandler2'),
35
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
36
+
37
+ errors.install();
38
+ errors.pushListener(handler1);
39
+ errors.pushListener(handler2);
40
+
41
+ errors.popListener();
42
+
43
+ fakeGlobal.onerror('foo');
44
+
45
+ expect(handler1).toHaveBeenCalledWith('foo');
46
+ expect(handler2).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it("uninstalls itself, putting back a previous callback", function() {
50
+ var originalCallback = jasmine.createSpy('error'),
51
+ fakeGlobal = { onerror: originalCallback },
52
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
53
+
54
+ expect(fakeGlobal.onerror).toBe(originalCallback);
55
+
56
+ errors.install();
57
+
58
+ expect(fakeGlobal.onerror).not.toBe(originalCallback);
59
+
60
+ errors.uninstall();
61
+
62
+ expect(fakeGlobal.onerror).toBe(originalCallback);
63
+ });
64
+
65
+ it("rethrows the original error when there is no handler", function() {
66
+ var fakeGlobal = { },
67
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
68
+ originalError = new Error('nope');
69
+
70
+ errors.install();
71
+
72
+ try {
73
+ fakeGlobal.onerror(originalError);
74
+ } catch (e) {
75
+ expect(e).toBe(originalError);
76
+ }
77
+
78
+ errors.uninstall();
79
+ });
80
+
81
+ it("works in node.js", function() {
82
+ var fakeGlobal = {
83
+ process: {
84
+ on: jasmine.createSpy('process.on'),
85
+ removeListener: jasmine.createSpy('process.removeListener'),
86
+ listeners: jasmine.createSpy('process.listeners').and.returnValue(['foo']),
87
+ removeAllListeners: jasmine.createSpy('process.removeAllListeners')
88
+ }
89
+ },
90
+ handler = jasmine.createSpy('errorHandler'),
91
+ errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
92
+
93
+ errors.install();
94
+ expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', jasmine.any(Function));
95
+ expect(fakeGlobal.process.listeners).toHaveBeenCalledWith('uncaughtException');
96
+ expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith('uncaughtException');
97
+
98
+ errors.pushListener(handler);
99
+
100
+ var addedListener = fakeGlobal.process.on.calls.argsFor(0)[1];
101
+ addedListener(new Error('bar'));
102
+
103
+ expect(handler).toHaveBeenCalledWith(new Error('bar'));
104
+
105
+ errors.uninstall();
106
+
107
+ expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith('uncaughtException', addedListener);
108
+ expect(fakeGlobal.process.on).toHaveBeenCalledWith('uncaughtException', 'foo');
109
+ });
110
+ });
@@ -14,6 +14,58 @@ describe("jasmineUnderTest.pp", function () {
14
14
  expect(jasmineUnderTest.pp(-0)).toEqual("-0");
15
15
  });
16
16
 
17
+ describe('stringify sets', function() {
18
+ it("should stringify sets properly", function() {
19
+ jasmine.getEnv().requireFunctioningSets();
20
+ var set = new Set();
21
+ set.add(1);
22
+ set.add(2);
23
+ expect(jasmineUnderTest.pp(set)).toEqual("Set( 1, 2 )");
24
+ });
25
+
26
+ it("should truncate sets with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
27
+ jasmine.getEnv().requireFunctioningSets();
28
+ var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
29
+
30
+ try {
31
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
32
+ var set = new Set();
33
+ set.add('a');
34
+ set.add('b');
35
+ set.add('c');
36
+ expect(jasmineUnderTest.pp(set)).toEqual("Set( 'a', 'b', ... )");
37
+ } finally {
38
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
39
+ }
40
+ })
41
+ });
42
+
43
+ describe('stringify maps', function() {
44
+ it("should stringify maps properly", function() {
45
+ jasmine.getEnv().requireFunctioningMaps();
46
+ var map = new Map();
47
+ map.set(1,2);
48
+ expect(jasmineUnderTest.pp(map)).toEqual("Map( [ 1, 2 ] )");
49
+ });
50
+
51
+ it("should truncate maps with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
52
+ jasmine.getEnv().requireFunctioningMaps();
53
+ var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
54
+
55
+ try {
56
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
57
+ var map = new Map();
58
+ map.set("a",1);
59
+ map.set("b",2);
60
+ map.set("c",3);
61
+ expect(jasmineUnderTest.pp(map)).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )");
62
+ } finally {
63
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
64
+ }
65
+ })
66
+ });
67
+
68
+
17
69
  describe('stringify arrays', function() {
18
70
  it("should stringify arrays properly", function() {
19
71
  expect(jasmineUnderTest.pp([1, 2])).toEqual("[ 1, 2 ]");
@@ -80,6 +132,58 @@ describe("jasmineUnderTest.pp", function () {
80
132
  }, bar: [1, 2, 3]})).toEqual("Object({ foo: Function, bar: [ 1, 2, 3 ] })");
81
133
  });
82
134
 
135
+ it("should truncate objects with too many keys", function () {
136
+ var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
137
+ var long = {a: 1, b: 2, c: 3};
138
+
139
+ try {
140
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
141
+ expect(jasmineUnderTest.pp(long)).toEqual("Object({ a: 1, b: 2, ... })");
142
+ } finally {
143
+ jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength;
144
+ }
145
+ });
146
+
147
+ function withMaxChars(maxChars, fn) {
148
+ var originalMaxChars = jasmineUnderTest.MAX_PRETTY_PRINT_CHARS;
149
+
150
+ try {
151
+ jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = maxChars;
152
+ fn();
153
+ } finally {
154
+ jasmineUnderTest.MAX_PRETTY_PRINT_CHARS = originalMaxChars;
155
+ }
156
+ }
157
+
158
+ it("should truncate outputs that are too long", function() {
159
+ var big = [
160
+ { a: 1, b: "a long string" },
161
+ {}
162
+ ];
163
+
164
+ withMaxChars(34, function() {
165
+ expect(jasmineUnderTest.pp(big)).toEqual("[ Object({ a: 1, b: 'a long st ...");
166
+ });
167
+ });
168
+
169
+ it("should not serialize more objects after hitting MAX_PRETTY_PRINT_CHARS", function() {
170
+ var a = { jasmineToString: function() { return 'object a'; } },
171
+ b = { jasmineToString: function() { return 'object b'; } },
172
+ c = { jasmineToString: jasmine.createSpy('c jasmineToString').and.returnValue('') },
173
+ d = { jasmineToString: jasmine.createSpy('d jasmineToString').and.returnValue('') };
174
+
175
+ withMaxChars(30, function() {
176
+ jasmineUnderTest.pp([{a: a, b: b, c: c}, d]);
177
+ expect(c.jasmineToString).not.toHaveBeenCalled();
178
+ expect(d.jasmineToString).not.toHaveBeenCalled();
179
+ });
180
+ });
181
+
182
+ it("should print 'null' as the constructor of an object with its own constructor property", function() {
183
+ expect(jasmineUnderTest.pp({constructor: function() {}})).toContain("null({");
184
+ expect(jasmineUnderTest.pp({constructor: 'foo'})).toContain("null({");
185
+ });
186
+
83
187
  it("should not include inherited properties when stringifying an object", function() {
84
188
  var SomeClass = function SomeClass() {};
85
189
  SomeClass.prototype.foo = "inherited foo";
@@ -145,7 +249,6 @@ describe("jasmineUnderTest.pp", function () {
145
249
  }
146
250
  });
147
251
 
148
-
149
252
  it('should not do HTML escaping of strings', function() {
150
253
  expect(jasmineUnderTest.pp('some <b>html string</b> &', false)).toEqual('\'some <b>html string</b> &\'');
151
254
  });
@@ -161,9 +264,9 @@ describe("jasmineUnderTest.pp", function () {
161
264
 
162
265
  it("should stringify spy objects properly", function() {
163
266
  var TestObject = {
164
- someFunction: function() {}
165
- },
166
- env = new jasmineUnderTest.Env();
267
+ someFunction: function() {}
268
+ },
269
+ env = new jasmineUnderTest.Env();
167
270
 
168
271
  var spyRegistry = new jasmineUnderTest.SpyRegistry({currentSpies: function() {return [];}});
169
272
 
@@ -187,6 +290,31 @@ describe("jasmineUnderTest.pp", function () {
187
290
  };
188
291
 
189
292
  expect(jasmineUnderTest.pp(obj)).toEqual("my toString");
293
+
294
+ // Simulate object from another global context (e.g. an iframe or Web Worker) that does not actually have a custom
295
+ // toString despite obj.toString !== Object.prototype.toString
296
+ var objFromOtherContext = {
297
+ foo: 'bar',
298
+ toString: function () { return Object.prototype.toString.call(this); }
299
+ };
300
+
301
+ if (jasmine.getEnv().ieVersion < 9) {
302
+ expect(jasmineUnderTest.pp(objFromOtherContext)).toEqual("Object({ foo: 'bar' })");
303
+ } else {
304
+ expect(jasmineUnderTest.pp(objFromOtherContext)).toEqual("Object({ foo: 'bar', toString: Function })");
305
+ }
306
+ });
307
+
308
+ it("should stringify objects have have a toString that isn't a function", function() {
309
+ var obj = {
310
+ toString: "foo"
311
+ };
312
+
313
+ if (jasmine.getEnv().ieVersion < 9) {
314
+ expect(jasmineUnderTest.pp(obj)).toEqual("Object({ })");
315
+ } else {
316
+ expect(jasmineUnderTest.pp(obj)).toEqual("Object({ toString: 'foo' })");
317
+ }
190
318
  });
191
319
 
192
320
  it("should stringify objects from anonymous constructors with custom toString", function () {
@@ -19,6 +19,26 @@ describe("QueueRunner", function() {
19
19
  expect(calls).toEqual(['fn1', 'fn2']);
20
20
  });
21
21
 
22
+ it("runs cleanup functions after the others", function() {
23
+ var calls = [],
24
+ queueableFn1 = { fn: jasmine.createSpy('fn1') },
25
+ queueableFn2 = { fn: jasmine.createSpy('fn2') },
26
+ queueRunner = new jasmineUnderTest.QueueRunner({
27
+ queueableFns: [queueableFn1],
28
+ cleanupFns: [queueableFn2]
29
+ });
30
+ queueableFn1.fn.and.callFake(function() {
31
+ calls.push('fn1');
32
+ });
33
+ queueableFn2.fn.and.callFake(function() {
34
+ calls.push('fn2');
35
+ });
36
+
37
+ queueRunner.execute();
38
+
39
+ expect(calls).toEqual(['fn1', 'fn2']);
40
+ });
41
+
22
42
  it("calls each function with a consistent 'this'-- an empty object", function() {
23
43
  var queueableFn1 = { fn: jasmine.createSpy('fn1') },
24
44
  queueableFn2 = { fn: jasmine.createSpy('fn2') },
@@ -31,7 +51,7 @@ describe("QueueRunner", function() {
31
51
  queueRunner.execute();
32
52
 
33
53
  var context = queueableFn1.fn.calls.first().object;
34
- expect(context).toEqual({});
54
+ expect(context).toEqual(new jasmineUnderTest.UserContext());
35
55
  expect(queueableFn2.fn.calls.first().object).toBe(context);
36
56
  expect(asyncContext).toBe(context);
37
57
  });
@@ -189,6 +209,7 @@ describe("QueueRunner", function() {
189
209
 
190
210
  queueRunner.execute();
191
211
 
212
+ jasmine.clock().tick(1);
192
213
  expect(onComplete).toHaveBeenCalled();
193
214
 
194
215
  jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
@@ -197,12 +218,13 @@ describe("QueueRunner", function() {
197
218
 
198
219
  it("only moves to the next spec the first time you call done", function() {
199
220
  var queueableFn = { fn: function(done) {done(); done();} },
200
- nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
201
- queueRunner = new jasmineUnderTest.QueueRunner({
202
- queueableFns: [queueableFn, nextQueueableFn]
203
- });
221
+ nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
222
+ queueRunner = new jasmineUnderTest.QueueRunner({
223
+ queueableFns: [queueableFn, nextQueueableFn]
224
+ });
204
225
 
205
226
  queueRunner.execute();
227
+ jasmine.clock().tick(1);
206
228
  expect(nextQueueableFn.fn.calls.count()).toEqual(1);
207
229
  });
208
230
 
@@ -211,10 +233,10 @@ describe("QueueRunner", function() {
211
233
  setTimeout(done, 1);
212
234
  throw new Error('error!');
213
235
  } },
214
- nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
215
- queueRunner = new jasmineUnderTest.QueueRunner({
216
- queueableFns: [queueableFn, nextQueueableFn]
217
- });
236
+ nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
237
+ queueRunner = new jasmineUnderTest.QueueRunner({
238
+ queueableFns: [queueableFn, nextQueueableFn]
239
+ });
218
240
 
219
241
  queueRunner.execute();
220
242
  jasmine.clock().tick(1);
@@ -234,6 +256,151 @@ describe("QueueRunner", function() {
234
256
  queueRunner.execute();
235
257
  expect(doneReturn).toBe(null);
236
258
  });
259
+
260
+ it("continues running functions when an exception is thrown in async code without timing out", function() {
261
+ var queueableFn = { fn: function(done) { throwAsync(); }, timeout: function() { return 1; } },
262
+ nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
263
+ onException = jasmine.createSpy('onException'),
264
+ globalErrors = { pushListener: jasmine.createSpy('pushListener'), popListener: jasmine.createSpy('popListener') },
265
+ queueRunner = new jasmineUnderTest.QueueRunner({
266
+ queueableFns: [queueableFn, nextQueueableFn],
267
+ onException: onException,
268
+ globalErrors: globalErrors
269
+ }),
270
+ throwAsync = function() {
271
+ globalErrors.pushListener.calls.mostRecent().args[0](new Error('foo'));
272
+ jasmine.clock().tick(2);
273
+ };
274
+
275
+ nextQueueableFn.fn.and.callFake(function() {
276
+ // should remove the same function that was added
277
+ expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(1)[0]);
278
+ });
279
+
280
+ queueRunner.execute();
281
+
282
+ function errorWithMessage(message) {
283
+ return {
284
+ asymmetricMatch: function(other) {
285
+ return new RegExp(message).test(other.message);
286
+ },
287
+ toString: function() {
288
+ return '<Error with message like "' + message + '">';
289
+ }
290
+ };
291
+ }
292
+ expect(onException).not.toHaveBeenCalledWith(errorWithMessage(/DEFAULT_TIMEOUT_INTERVAL/));
293
+ expect(onException).toHaveBeenCalledWith(errorWithMessage(/^foo$/));
294
+ expect(nextQueueableFn.fn).toHaveBeenCalled();
295
+ });
296
+
297
+ it("handles exceptions thrown while waiting for the stack to clear", function() {
298
+ var queueableFn = { fn: function(done) { done() } },
299
+ global = {},
300
+ errorListeners = [],
301
+ globalErrors = {
302
+ pushListener: function(f) { errorListeners.push(f); },
303
+ popListener: function() { errorListeners.pop(); }
304
+ },
305
+ clearStack = jasmine.createSpy('clearStack'),
306
+ onException = jasmine.createSpy('onException'),
307
+ queueRunner = new jasmineUnderTest.QueueRunner({
308
+ queueableFns: [queueableFn],
309
+ globalErrors: globalErrors,
310
+ clearStack: clearStack,
311
+ onException: onException
312
+ }),
313
+ error = new Error('nope');
314
+
315
+ queueRunner.execute();
316
+ jasmine.clock().tick();
317
+ expect(clearStack).toHaveBeenCalled();
318
+ expect(errorListeners.length).toEqual(1);
319
+ errorListeners[0](error);
320
+ clearStack.calls.argsFor(0)[0]();
321
+ expect(onException).toHaveBeenCalledWith(error);
322
+ });
323
+ });
324
+
325
+ describe("with a function that returns a promise", function() {
326
+ function StubPromise() {}
327
+
328
+ StubPromise.prototype.then = function(resolve, reject) {
329
+ this.resolveHandler = resolve;
330
+ this.rejectHandler = reject;
331
+ };
332
+
333
+ beforeEach(function() {
334
+ jasmine.clock().install();
335
+ });
336
+
337
+ afterEach(function() {
338
+ jasmine.clock().uninstall();
339
+ });
340
+
341
+ it("runs the function asynchronously, advancing once the promise is settled", function() {
342
+ var onComplete = jasmine.createSpy('onComplete'),
343
+ fnCallback = jasmine.createSpy('fnCallback'),
344
+ p1 = new StubPromise(),
345
+ p2 = new StubPromise(),
346
+ queueableFn1 = { fn: function() {
347
+ setTimeout(function() {
348
+ p1.resolveHandler();
349
+ }, 100);
350
+ return p1;
351
+ } };
352
+ queueableFn2 = { fn: function() {
353
+ fnCallback();
354
+ setTimeout(function() {
355
+ p2.resolveHandler();
356
+ }, 100);
357
+ return p2;
358
+ } },
359
+ queueRunner = new jasmineUnderTest.QueueRunner({
360
+ queueableFns: [queueableFn1, queueableFn2],
361
+ onComplete: onComplete
362
+ });
363
+
364
+ queueRunner.execute();
365
+ expect(fnCallback).not.toHaveBeenCalled();
366
+ expect(onComplete).not.toHaveBeenCalled();
367
+
368
+ jasmine.clock().tick(100);
369
+
370
+ expect(fnCallback).toHaveBeenCalled();
371
+ expect(onComplete).not.toHaveBeenCalled();
372
+
373
+ jasmine.clock().tick(100);
374
+
375
+ expect(onComplete).toHaveBeenCalled();
376
+ });
377
+
378
+ it("handles a rejected promise like an unhandled exception", function() {
379
+ var promise = new StubPromise(),
380
+ queueableFn1 = { fn: function() {
381
+ setTimeout(function() {
382
+ promise.rejectHandler('foo')
383
+ }, 100);
384
+ return promise;
385
+ } },
386
+ queueableFn2 = { fn: jasmine.createSpy('fn2') },
387
+ failFn = jasmine.createSpy('fail'),
388
+ onExceptionCallback = jasmine.createSpy('on exception callback'),
389
+ queueRunner = new jasmineUnderTest.QueueRunner({
390
+ queueableFns: [queueableFn1, queueableFn2],
391
+ onException: onExceptionCallback
392
+ });
393
+
394
+ queueRunner.execute();
395
+
396
+ expect(onExceptionCallback).not.toHaveBeenCalled();
397
+ expect(queueableFn2.fn).not.toHaveBeenCalled();
398
+
399
+ jasmine.clock().tick(100);
400
+
401
+ expect(onExceptionCallback).toHaveBeenCalledWith('foo');
402
+ expect(queueableFn2.fn).toHaveBeenCalled();
403
+ });
237
404
  });
238
405
 
239
406
  it("calls exception handlers when an exception is thrown in a fn", function() {
@@ -277,6 +444,87 @@ describe("QueueRunner", function() {
277
444
  expect(nextQueueableFn.fn).toHaveBeenCalled();
278
445
  });
279
446
 
447
+ describe("When configured to complete on first error", function() {
448
+ it("skips to cleanup functions on the first exception", function() {
449
+ var queueableFn = { fn: function() { throw new Error("error"); } },
450
+ nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
451
+ cleanupFn = { fn: jasmine.createSpy("cleanup") },
452
+ queueRunner = new jasmineUnderTest.QueueRunner({
453
+ queueableFns: [queueableFn, nextQueueableFn],
454
+ cleanupFns: [cleanupFn],
455
+ completeOnFirstError: true
456
+ });
457
+
458
+ queueRunner.execute();
459
+ expect(nextQueueableFn.fn).not.toHaveBeenCalled();
460
+ expect(cleanupFn.fn).toHaveBeenCalled();
461
+ });
462
+
463
+ it("does not skip when a cleanup function throws", function() {
464
+ var queueableFn = { fn: function() { } },
465
+ cleanupFn1 = { fn: function() { throw new Error("error"); } },
466
+ cleanupFn2 = { fn: jasmine.createSpy("cleanupFn2") },
467
+ queueRunner = new jasmineUnderTest.QueueRunner({
468
+ queueableFns: [queueableFn],
469
+ cleanupFns: [cleanupFn1, cleanupFn2],
470
+ completeOnFirstError: true
471
+ });
472
+
473
+ queueRunner.execute();
474
+ expect(cleanupFn2.fn).toHaveBeenCalled();
475
+ });
476
+
477
+ describe("with an asynchronous function", function() {
478
+ beforeEach(function() {
479
+ jasmine.clock().install();
480
+ });
481
+
482
+ afterEach(function() {
483
+ jasmine.clock().uninstall();
484
+ });
485
+
486
+
487
+ it("skips to cleanup functions on the first exception", function() {
488
+ var errorListeners = [],
489
+ queueableFn = { fn: function(done) {} },
490
+ nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
491
+ cleanupFn = { fn: jasmine.createSpy('cleanup') },
492
+ queueRunner = new jasmineUnderTest.QueueRunner({
493
+ globalErrors: {
494
+ pushListener: function(f) { errorListeners.push(f); },
495
+ popListener: function() { errorListeners.pop(); },
496
+ },
497
+ queueableFns: [queueableFn, nextQueueableFn],
498
+ cleanupFns: [cleanupFn],
499
+ completeOnFirstError: true,
500
+ });
501
+
502
+ queueRunner.execute();
503
+ errorListeners[errorListeners.length - 1](new Error('error'));
504
+ expect(nextQueueableFn.fn).not.toHaveBeenCalled();
505
+ expect(cleanupFn.fn).toHaveBeenCalled();
506
+ });
507
+
508
+ it("skips to cleanup functions when next.fail is called", function() {
509
+ var queueableFn = { fn: function(done) {
510
+ done.fail('nope');
511
+ } },
512
+ nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
513
+ cleanupFn = { fn: jasmine.createSpy('cleanup') },
514
+ queueRunner = new jasmineUnderTest.QueueRunner({
515
+ queueableFns: [queueableFn, nextQueueableFn],
516
+ cleanupFns: [cleanupFn],
517
+ completeOnFirstError: true,
518
+ });
519
+
520
+ queueRunner.execute();
521
+ jasmine.clock().tick();
522
+ expect(nextQueueableFn.fn).not.toHaveBeenCalled();
523
+ expect(cleanupFn.fn).toHaveBeenCalled();
524
+ });
525
+ });
526
+ });
527
+
280
528
  it("calls a provided complete callback when done", function() {
281
529
  var queueableFn = { fn: jasmine.createSpy('fn') },
282
530
  completeCallback = jasmine.createSpy('completeCallback'),
@@ -290,21 +538,83 @@ describe("QueueRunner", function() {
290
538
  expect(completeCallback).toHaveBeenCalled();
291
539
  });
292
540
 
293
- it("calls a provided stack clearing function when done", function() {
294
- var asyncFn = { fn: function(done) { done() } },
295
- afterFn = { fn: jasmine.createSpy('afterFn') },
296
- completeCallback = jasmine.createSpy('completeCallback'),
297
- clearStack = jasmine.createSpy('clearStack'),
298
- queueRunner = new jasmineUnderTest.QueueRunner({
299
- queueableFns: [asyncFn, afterFn],
300
- clearStack: clearStack,
301
- onComplete: completeCallback
302
- });
541
+ describe("clearing the stack", function() {
542
+ beforeEach(function() {
543
+ jasmine.clock().install();
544
+ });
303
545
 
304
- clearStack.and.callFake(function(fn) { fn(); });
546
+ afterEach(function() {
547
+ jasmine.clock().uninstall();
548
+ });
305
549
 
306
- queueRunner.execute();
307
- expect(afterFn.fn).toHaveBeenCalled();
308
- expect(clearStack).toHaveBeenCalledWith(completeCallback);
550
+ it("calls a provided stack clearing function when done", function() {
551
+ var asyncFn = { fn: function(done) { done() } },
552
+ afterFn = { fn: jasmine.createSpy('afterFn') },
553
+ completeCallback = jasmine.createSpy('completeCallback'),
554
+ clearStack = jasmine.createSpy('clearStack'),
555
+ queueRunner = new jasmineUnderTest.QueueRunner({
556
+ queueableFns: [asyncFn, afterFn],
557
+ clearStack: clearStack,
558
+ onComplete: completeCallback
559
+ });
560
+
561
+ clearStack.and.callFake(function(fn) { fn(); });
562
+
563
+ queueRunner.execute();
564
+ jasmine.clock().tick();
565
+ expect(afterFn.fn).toHaveBeenCalled();
566
+ expect(clearStack).toHaveBeenCalled();
567
+ clearStack.calls.argsFor(0)[0]();
568
+ expect(completeCallback).toHaveBeenCalled();
569
+ });
570
+ });
571
+
572
+ describe('when user context has not been defined', function() {
573
+ beforeEach(function() {
574
+ var fn;
575
+
576
+ this.fn = fn = jasmine.createSpy('fn1');
577
+ this.queueRunner = new jasmineUnderTest.QueueRunner({
578
+ queueableFns: [{ fn: fn }]
579
+ });
580
+ });
581
+
582
+ it('runs the functions on the scope of a UserContext', function() {
583
+ var calls = [],
584
+ context;
585
+
586
+ this.fn.and.callFake(function() {
587
+ context = this;
588
+ });
589
+
590
+ this.queueRunner.execute();
591
+
592
+ expect(context.constructor).toBe(jasmineUnderTest.UserContext);
593
+ });
594
+ });
595
+
596
+ describe('when user context has been defined', function() {
597
+ beforeEach(function() {
598
+ var fn, context;
599
+
600
+ this.fn = fn = jasmine.createSpy('fn1');
601
+ this.context = context = new jasmineUnderTest.UserContext();
602
+ this.queueRunner = new jasmineUnderTest.QueueRunner({
603
+ queueableFns: [{ fn: fn }],
604
+ userContext: context
605
+ });
606
+ });
607
+
608
+ it('runs the functions on the scope of a UserContext', function() {
609
+ var calls = [],
610
+ context;
611
+ this.fn.and.callFake(function() {
612
+ context = this;
613
+ });
614
+
615
+ this.queueRunner.execute();
616
+
617
+ expect(context).toBe(this.context);
618
+ });
309
619
  });
310
620
  });