311 lines
11 KiB
JavaScript
311 lines
11 KiB
JavaScript
describe("QueueRunner", function() {
|
|
|
|
it("runs all the functions it's passed", function() {
|
|
var calls = [],
|
|
queueableFn1 = { fn: jasmine.createSpy('fn1') },
|
|
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn1, queueableFn2]
|
|
});
|
|
queueableFn1.fn.and.callFake(function() {
|
|
calls.push('fn1');
|
|
});
|
|
queueableFn2.fn.and.callFake(function() {
|
|
calls.push('fn2');
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(calls).toEqual(['fn1', 'fn2']);
|
|
});
|
|
|
|
it("calls each function with a consistent 'this'-- an empty object", function() {
|
|
var queueableFn1 = { fn: jasmine.createSpy('fn1') },
|
|
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
|
queueableFn3 = { fn: function(done) { asyncContext = this; done(); } },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn1, queueableFn2, queueableFn3]
|
|
}),
|
|
asyncContext;
|
|
|
|
queueRunner.execute();
|
|
|
|
var context = queueableFn1.fn.calls.first().object;
|
|
expect(context).toEqual({});
|
|
expect(queueableFn2.fn.calls.first().object).toBe(context);
|
|
expect(asyncContext).toBe(context);
|
|
});
|
|
|
|
describe("with an asynchronous function", function() {
|
|
beforeEach(function() {
|
|
jasmine.clock().install();
|
|
});
|
|
|
|
afterEach(function() {
|
|
jasmine.clock().uninstall();
|
|
});
|
|
|
|
it("supports asynchronous functions, only advancing to next function after a done() callback", function() {
|
|
//TODO: it would be nice if spy arity could match the fake, so we could do something like:
|
|
//createSpy('asyncfn').and.callFake(function(done) {});
|
|
|
|
var onComplete = jasmine.createSpy('onComplete'),
|
|
beforeCallback = jasmine.createSpy('beforeCallback'),
|
|
fnCallback = jasmine.createSpy('fnCallback'),
|
|
afterCallback = jasmine.createSpy('afterCallback'),
|
|
queueableFn1 = { fn: function(done) {
|
|
beforeCallback();
|
|
setTimeout(done, 100);
|
|
} },
|
|
queueableFn2 = { fn: function(done) {
|
|
fnCallback();
|
|
setTimeout(done, 100);
|
|
} },
|
|
queueableFn3 = { fn: function(done) {
|
|
afterCallback();
|
|
setTimeout(done, 100);
|
|
} },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn1, queueableFn2, queueableFn3],
|
|
onComplete: onComplete
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(beforeCallback).toHaveBeenCalled();
|
|
expect(fnCallback).not.toHaveBeenCalled();
|
|
expect(afterCallback).not.toHaveBeenCalled();
|
|
expect(onComplete).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(100);
|
|
|
|
expect(fnCallback).toHaveBeenCalled();
|
|
expect(afterCallback).not.toHaveBeenCalled();
|
|
expect(onComplete).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(100);
|
|
|
|
expect(afterCallback).toHaveBeenCalled();
|
|
expect(onComplete).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(100);
|
|
|
|
expect(onComplete).toHaveBeenCalled();
|
|
});
|
|
|
|
it("explicitly fails an async function with a provided fail function and moves to the next function", function() {
|
|
var queueableFn1 = { fn: function(done) {
|
|
setTimeout(function() { done.fail('foo'); }, 100);
|
|
} },
|
|
queueableFn2 = { fn: jasmine.createSpy('fn2') },
|
|
failFn = jasmine.createSpy('fail'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn1, queueableFn2],
|
|
fail: failFn
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(failFn).not.toHaveBeenCalled();
|
|
expect(queueableFn2.fn).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(100);
|
|
|
|
expect(failFn).toHaveBeenCalledWith('foo');
|
|
expect(queueableFn2.fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("sets a timeout if requested for asynchronous functions so they don't go on forever", function() {
|
|
var timeout = 3,
|
|
beforeFn = { fn: function(done) { }, type: 'before', timeout: function() { return timeout; } },
|
|
queueableFn = { fn: jasmine.createSpy('fn'), type: 'queueable' },
|
|
onComplete = jasmine.createSpy('onComplete'),
|
|
onException = jasmine.createSpy('onException'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [beforeFn, queueableFn],
|
|
onComplete: onComplete,
|
|
onException: onException
|
|
});
|
|
|
|
queueRunner.execute();
|
|
expect(queueableFn.fn).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(timeout);
|
|
|
|
expect(onException).toHaveBeenCalledWith(jasmine.any(Error));
|
|
expect(queueableFn.fn).toHaveBeenCalled();
|
|
expect(onComplete).toHaveBeenCalled();
|
|
});
|
|
|
|
it("by default does not set a timeout for asynchronous functions", function() {
|
|
var beforeFn = { fn: function(done) { } },
|
|
queueableFn = { fn: jasmine.createSpy('fn') },
|
|
onComplete = jasmine.createSpy('onComplete'),
|
|
onException = jasmine.createSpy('onException'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [beforeFn, queueableFn],
|
|
onComplete: onComplete,
|
|
onException: onException,
|
|
});
|
|
|
|
queueRunner.execute();
|
|
expect(queueableFn.fn).not.toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
|
|
|
|
expect(onException).not.toHaveBeenCalled();
|
|
expect(queueableFn.fn).not.toHaveBeenCalled();
|
|
expect(onComplete).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("clears the timeout when an async function throws an exception, to prevent additional exception reporting", function() {
|
|
var queueableFn = { fn: function(done) { throw new Error("error!"); } },
|
|
onComplete = jasmine.createSpy('onComplete'),
|
|
onException = jasmine.createSpy('onException'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn],
|
|
onComplete: onComplete,
|
|
onException: onException
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(onComplete).toHaveBeenCalled();
|
|
expect(onException).toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
|
|
expect(onException.calls.count()).toEqual(1);
|
|
});
|
|
|
|
it("clears the timeout when the done callback is called", function() {
|
|
var queueableFn = { fn: function(done) { done(); } },
|
|
onComplete = jasmine.createSpy('onComplete'),
|
|
onException = jasmine.createSpy('onException'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn],
|
|
onComplete: onComplete,
|
|
onException: onException
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(onComplete).toHaveBeenCalled();
|
|
|
|
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
|
|
expect(onException).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("only moves to the next spec the first time you call done", function() {
|
|
var queueableFn = { fn: function(done) {done(); done();} },
|
|
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn, nextQueueableFn]
|
|
});
|
|
|
|
queueRunner.execute();
|
|
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
|
});
|
|
|
|
it("does not move to the next spec if done is called after an exception has ended the spec", function() {
|
|
var queueableFn = { fn: function(done) {
|
|
setTimeout(done, 1);
|
|
throw new Error('error!');
|
|
} },
|
|
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn, nextQueueableFn]
|
|
});
|
|
|
|
queueRunner.execute();
|
|
jasmine.clock().tick(1);
|
|
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
|
|
});
|
|
|
|
it("should return a null when you call done", function () {
|
|
// Some promises want handlers to return anything but undefined to help catch "forgotten returns".
|
|
var doneReturn,
|
|
queueableFn = { fn: function(done) {
|
|
doneReturn = done();
|
|
} },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn]
|
|
});
|
|
|
|
queueRunner.execute();
|
|
expect(doneReturn).toBe(null);
|
|
});
|
|
});
|
|
|
|
it("calls exception handlers when an exception is thrown in a fn", function() {
|
|
var queueableFn = { type: 'queueable',
|
|
fn: function() {
|
|
throw new Error('fake error');
|
|
} },
|
|
onExceptionCallback = jasmine.createSpy('on exception callback'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn],
|
|
onException: onExceptionCallback
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(onExceptionCallback).toHaveBeenCalledWith(jasmine.any(Error));
|
|
});
|
|
|
|
it("rethrows an exception if told to", function() {
|
|
var queueableFn = { fn: function() {
|
|
throw new Error('fake error');
|
|
} },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn],
|
|
catchException: function(e) { return false; }
|
|
});
|
|
|
|
expect(function() {
|
|
queueRunner.execute();
|
|
}).toThrowError('fake error');
|
|
});
|
|
|
|
it("continues running the functions even after an exception is thrown in an async spec", function() {
|
|
var queueableFn = { fn: function(done) { throw new Error("error"); } },
|
|
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn, nextQueueableFn]
|
|
});
|
|
|
|
queueRunner.execute();
|
|
expect(nextQueueableFn.fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("calls a provided complete callback when done", function() {
|
|
var queueableFn = { fn: jasmine.createSpy('fn') },
|
|
completeCallback = jasmine.createSpy('completeCallback'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [queueableFn],
|
|
onComplete: completeCallback
|
|
});
|
|
|
|
queueRunner.execute();
|
|
|
|
expect(completeCallback).toHaveBeenCalled();
|
|
});
|
|
|
|
it("calls a provided stack clearing function when done", function() {
|
|
var asyncFn = { fn: function(done) { done() } },
|
|
afterFn = { fn: jasmine.createSpy('afterFn') },
|
|
completeCallback = jasmine.createSpy('completeCallback'),
|
|
clearStack = jasmine.createSpy('clearStack'),
|
|
queueRunner = new jasmineUnderTest.QueueRunner({
|
|
queueableFns: [asyncFn, afterFn],
|
|
clearStack: clearStack,
|
|
onComplete: completeCallback
|
|
});
|
|
|
|
clearStack.and.callFake(function(fn) { fn(); });
|
|
|
|
queueRunner.execute();
|
|
expect(afterFn.fn).toHaveBeenCalled();
|
|
expect(clearStack).toHaveBeenCalledWith(completeCallback);
|
|
});
|
|
});
|