diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b2bf0729..fe43148b 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3490,6 +3490,12 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } + // firstCleanupIx_ isn't correct for suites with afterAll functions. + // Rely on the type for those. + if (this.queueableFns_[fnIx].type === 'afterAll') { + return false; + } + const candidateSuite = this.queueableFns_[fnIx].suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; return ( diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index b415d916..b1536ae0 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -95,6 +95,23 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { policy.fnErrored(0); expect(policy.skipTo(0)).toEqual(1); }); + + it('does not skip afterAll fns, even if before the first cleanup fn index', function() { + const fns = [ + { fn: () => {} }, + { + fn: () => {}, + type: 'afterAll' + } + ]; + const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(1); + }); }); }); }); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 9212e88a..a7457d3b 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1153,6 +1153,41 @@ describe('spec running', function() { done(); }); }); + + it('runs afterAll functions', async function() { + const actions = []; + + env.describe('outer suite', function() { + env.describe('inner suite', function() { + env.it('fails', function() { + actions.push('fails'); + env.expect(1).toBe(2); + }); + + env.afterAll(function() { + actions.push('inner afterAll'); + }); + }); + + env.afterAll(function() { + actions.push('outer afterAll'); + }); + }); + + env.afterAll(function() { + actions.push('top afterAll'); + }); + + env.configure({ stopOnSpecFailure: true }); + await env.execute(); + + expect(actions).toEqual([ + 'fails', + 'inner afterAll', + 'outer afterAll', + 'top afterAll' + ]); + }); }); describe('run multiple times', function() { diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index 98ad7caa..afca843c 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -23,6 +23,12 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { return false; } + // firstCleanupIx_ isn't correct for suites with afterAll functions. + // Rely on the type for those. + if (this.queueableFns_[fnIx].type === 'afterAll') { + return false; + } + const candidateSuite = this.queueableFns_[fnIx].suite; const errorSuite = this.queueableFns_[this.erroredFnIx_].suite; return (