Correctly route errors that occur while a QueueRunner is clearing stack

Besides surfacing the error in the hopefully-correct place, this also
prevents the queue runners for sibling suites from interleaving, which
in turn prevents all kinds of internal state corruption.

Signed-off-by: Gregg Van Hove <gvanhove@pivotal.io>
This commit is contained in:
Steve Gravrock
2017-05-09 14:44:53 -07:00
committed by Gregg Van Hove
parent 2835ca3cce
commit b1e97cfb09
4 changed files with 75 additions and 3 deletions

View File

@@ -252,7 +252,7 @@ describe("QueueRunner", function() {
nextQueueableFn.fn.and.callFake(function() {
// should remove the same function that was added
expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(0)[0]);
expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(1)[0]);
});
queueRunner.execute();
@@ -314,6 +314,32 @@ describe("QueueRunner", function() {
expect(nextQueueableFn.fn).toHaveBeenCalled();
});
it("handles exceptions thrown while waiting for the stack to clear", function() {
var queueableFn = { fn: function(done) { done() } },
global = {},
errorListeners = [],
globalErrors = {
pushListener: function(f) { errorListeners.push(f); },
popListener: function() { errorListeners.pop(); }
},
clearStack = jasmine.createSpy('clearStack'),
onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
globalErrors: globalErrors,
clearStack: clearStack,
onException: onException
}),
error = new Error('nope');
queueRunner.execute();
expect(clearStack).toHaveBeenCalled();
expect(errorListeners.length).toEqual(1);
errorListeners[0](error);
clearStack.calls.argsFor(0)[0]();
expect(onException).toHaveBeenCalledWith(error);
});
it("calls a provided complete callback when done", function() {
var queueableFn = { fn: jasmine.createSpy('fn') },
completeCallback = jasmine.createSpy('completeCallback'),
@@ -342,6 +368,8 @@ describe("QueueRunner", function() {
queueRunner.execute();
expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalledWith(completeCallback);
expect(clearStack).toHaveBeenCalled();
clearStack.calls.argsFor(0)[0]();
expect(completeCallback).toHaveBeenCalled();
});
});

View File

@@ -456,6 +456,38 @@ describe("Env integration", function() {
env.execute();
});
it("copes with late async failures", function(done) {
var global = {
setTimeout: function(fn, delay) { setTimeout(fn, delay) },
clearTimeout: function(fn, delay) { clearTimeout(fn, delay) },
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone", "suiteDone" ]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('A suite', ['fail thrown']);
done();
});
env.addReporter(reporter);
env.fdescribe('A suite', function() {
env.it('fails', function(specDone) {
specDone();
setTimeout(function() {
global.onerror('fail');
});
});
});
env.describe('Ignored', function() {
env.it('is not run', function() {});
});
env.execute();
});
describe('suiteDone reporting', function(){
it("reports when an afterAll fails an expectation", function(done) {
var env = new jasmineUnderTest.Env(),