diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 8bedc437..3f1242de 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -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(); }); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index e5543195..3300c1e8 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -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(), diff --git a/src/core/Env.js b/src/core/Env.js index f5877d92..81927ed9 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -238,6 +238,10 @@ getJasmineRequireObj().Env = function(j$) { reporter.suiteStarted(suite.result); }, nodeComplete: function(suite, result) { + if (suite !== currentSuite()) { + throw new Error('Tried to complete the wrong suite'); + } + if (!suite.markedPending) { clearResourcesForRunnable(suite.id); } diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 7d320b44..8cafd26f 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -24,6 +24,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { } QueueRunner.prototype.execute = function() { + var self = this; + this.handleFinalError = function(error) { + self.onException(error); + }; + this.globalErrors.pushListener(this.handleFinalError); this.run(this.queueableFns, 0); }; @@ -43,7 +48,10 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } - this.clearStack(this.onComplete); + this.clearStack(function() { + self.globalErrors.popListener(self.handleFinalError); + self.onComplete(); + }); function attemptSync(queueableFn) { try {