From 40be00310dda9261e31c0e179c88fd0bac057e12 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Fri, 24 Sep 2021 11:22:04 -0700 Subject: [PATCH] Don't immediately move to the next queueable fn on async error This allows assertion failures and other errors that occcur after the async error to be routed to the correct spec/suite. Previously, Jasmine treated global errors and unhandled promise rejections just like exceptions thrown from a synchronous spec: it recorded the error as a spec failure and moved on. Now, global errors and uhandled rejections are recorded as failures but the current queueable fn will continue until it either signals completion or times out. Global errors and unhandled rejections are different from synchronous exceptions: it's common for the queueable fn that caused them to continue executing. Immediately moving on often meant that the queueable fn would produce expectation failures or other errors when a different spec or suite was running, thus causing those failures to be routed to the wrong place. --- lib/jasmine-core/jasmine.js | 1 - spec/core/QueueRunnerSpec.js | 13 ++++++++++--- src/core/QueueRunner.js | 1 - 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 6c05f9c1..7ac7ad41 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -7872,7 +7872,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { completedSynchronously = true, handleError = function handleError(error) { onException(error); - next(error); }, cleanup = once(function cleanup() { if (timeoutId !== void 0) { diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 7333b02a..7eea2563 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -669,9 +669,13 @@ describe('QueueRunner', function() { jasmine.clock().uninstall(); }); - it('skips to cleanup functions on the first exception', function() { + it('skips to cleanup functions once the fn completes after an unhandled exception', function() { var errorListeners = [], - queueableFn = { fn: function(done) {} }, + queueableFn = { + fn: function(done) { + queueableFnDone = done; + } + }, nextQueueableFn = { fn: jasmine.createSpy('nextFunction') }, cleanupFn = { fn: jasmine.createSpy('cleanup') }, queueRunner = new jasmineUnderTest.QueueRunner({ @@ -686,10 +690,13 @@ describe('QueueRunner', function() { queueableFns: [queueableFn, nextQueueableFn], cleanupFns: [cleanupFn], completeOnFirstError: true - }); + }), + queueableFnDone; queueRunner.execute(); errorListeners[errorListeners.length - 1](new Error('error')); + expect(cleanupFn.fn).not.toHaveBeenCalled(); + queueableFnDone(); expect(nextQueueableFn.fn).not.toHaveBeenCalled(); expect(cleanupFn.fn).toHaveBeenCalled(); }); diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index be9e7f62..679da4a5 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -89,7 +89,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { completedSynchronously = true, handleError = function handleError(error) { onException(error); - next(error); }, cleanup = once(function cleanup() { if (timeoutId !== void 0) {