diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 1fb3973c..638f7410 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -83,6 +83,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( + j$ + ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ ); @@ -1612,15 +1615,19 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - if ( + if (options.isLeaf) { // A spec - options.isLeaf || - // A suite, and config.stopOnSpecFailure is set - (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) - ) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; - } else { + } else if (options.isReporter) { + // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; + } else { + // A suite + if (config.stopOnSpecFailure) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; + } } options.clearStack = options.clearStack || clearStack; @@ -3390,21 +3397,22 @@ getJasmineRequireObj().Clock = function() { getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { - this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; + this.skipping_ = false; } - CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( - lastRanFnIx, - errored - ) { - if (errored && lastRanFnIx < this.firstCleanupIx_) { + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { return this.firstCleanupIx_; } else { return lastRanFnIx + 1; } }; + CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { + this.skipping_ = true; + }; + return CompleteOnFirstErrorSkipPolicy; }; @@ -7288,10 +7296,12 @@ getJasmineRequireObj().MockDate = function(j$) { getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns, firstCleanupIx) {} - NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; + NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; + return NeverSkipPolicy; }; @@ -7762,7 +7772,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); - this.errored = false; + this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); @@ -7818,7 +7828,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } - self.errored = errored = true; + self.recordError_(iterativeIndex); } function runNext() { @@ -7844,7 +7854,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } ), - errored = false, timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, @@ -7852,7 +7861,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { next.fail = function nextFail() { self.fail.apply(null, arguments); - self.errored = errored = true; + self.recordError_(iterativeIndex); next(); }; @@ -7895,15 +7904,15 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } catch (e) { onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } cleanup(); - return { completedSynchronously: true, errored: errored }; + return { completedSynchronously: true }; function onException(e) { self.onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } function onPromiseRejection(e) { @@ -7927,14 +7936,12 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!result.completedSynchronously) { return; } - - self.errored = self.errored || result.errored; } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); - if (self.errored) { + if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); @@ -7943,7 +7950,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { - const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); @@ -7952,6 +7959,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { return result; }; + QueueRunner.prototype.recordError_ = function(currentFnIx) { + this.errored_ = true; + this.skipPolicy_.fnErrored(currentFnIx); + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; @@ -8496,6 +8508,39 @@ getJasmineRequireObj().interface = function(jasmine, env) { return jasmineInterface; }; +getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { + function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.skipping_ = false; + } + + SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_) { + return this.nextAfterAllAfter_(lastRanFnIx); + } else { + return lastRanFnIx + 1; + } + }; + + SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { + for ( + i++; + i < this.queueableFns_.length && + this.queueableFns_[i].type !== 'afterAll'; + i++ + ) {} + return i; + }; + + SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { + if (this.queueableFns_[fnIx].type === 'beforeAll') { + this.skipping_ = true; + } + }; + + return SkipAfterBeforeAllErrorPolicy; +}; + getJasmineRequireObj().Spy = function(j$) { var nextOrder = (function() { var order = 0; @@ -9942,7 +9987,16 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns.concat(result).concat(node.afterAllFns); + return node.beforeAllFns + .map(function(fn) { + return { type: 'beforeAll', ...fn }; + }) + .concat(result) + .concat( + node.afterAllFns.map(function(fn) { + return { type: 'afterAll', ...fn }; + }) + ); } } diff --git a/package.json b/package.json index 9edf722e..b7cbb3fa 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,9 @@ "node": true, "es2017": true }, + "parserOptions": { + "ecmaVersion": 2018 + }, "rules": { "quotes": [ "error", diff --git a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js index 5c746fb7..1064cc03 100644 --- a/spec/core/CompleteOnFirstErrorSkipPolicySpec.js +++ b/spec/core/CompleteOnFirstErrorSkipPolicySpec.js @@ -1,24 +1,25 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { describe('#skipTo', function() { - describe('When errored is false', function() { + describe('Before anything has errored', function() { it('returns the next index', function() { const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( arrayOfArbitraryFns(4), 4 ); - expect(policy.skipTo(1, false)).toEqual(2); + expect(policy.skipTo(1)).toEqual(2); }); }); - describe('When errored is true', function() { + describe('After something has errored', function() { it('returns the first cleanup fn when called with a non cleanup fn', function() { const policy = new jasmineUnderTest.CompleteOnFirstErrorSkipPolicy( arrayOfArbitraryFns(4), 2 ); - expect(policy.skipTo(0, true)).toEqual(2); - expect(policy.skipTo(1, true)).toEqual(2); + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(2); + expect(policy.skipTo(1)).toEqual(2); }); it('returns the next index when called with a cleanup fn', function() { @@ -27,8 +28,9 @@ describe('CompleteOnFirstErrorSkipPolicy', function() { 1 ); - expect(policy.skipTo(1, true)).toEqual(2); - expect(policy.skipTo(2, true)).toEqual(3); + policy.fnErrored(0); + expect(policy.skipTo(1)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); }); }); }); diff --git a/spec/core/QueueRunnerSpec.js b/spec/core/QueueRunnerSpec.js index 180736f2..87f575fe 100644 --- a/spec/core/QueueRunnerSpec.js +++ b/spec/core/QueueRunnerSpec.js @@ -674,7 +674,10 @@ describe('QueueRunner', function() { { fn: jasmine.createSpy('fn2').and.throwError(new Error('nope')) }, { fn: jasmine.createSpy('fn3') } ]; - const skipPolicy = jasmine.createSpyObj('skipPolicy', ['skipTo']); + const skipPolicy = jasmine.createSpyObj('skipPolicy', [ + 'skipTo', + 'fnErrored' + ]); skipPolicy.skipTo.and.callFake(function(lastRanIx) { return lastRanIx === 0 ? 2 : lastRanIx + 1; }); @@ -687,8 +690,9 @@ describe('QueueRunner', function() { queueRunner.execute(); - expect(skipPolicy.skipTo).toHaveBeenCalledWith(0, false); - expect(skipPolicy.skipTo).toHaveBeenCalledWith(2, true); + expect(skipPolicy.skipTo).toHaveBeenCalledWith(0); + expect(skipPolicy.skipTo).toHaveBeenCalledWith(2); + expect(skipPolicy.fnErrored).toHaveBeenCalledWith(2); expect(queueableFns[0].fn).toHaveBeenCalled(); expect(queueableFns[1].fn).not.toHaveBeenCalled(); expect(queueableFns[2].fn).toHaveBeenCalled(); diff --git a/spec/core/SkipAfterBeforeAllErrorPolicySpec.js b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js new file mode 100644 index 00000000..13a1e9ba --- /dev/null +++ b/spec/core/SkipAfterBeforeAllErrorPolicySpec.js @@ -0,0 +1,65 @@ +describe('SkipAfterBeforeAllErrorPolicy', function() { + describe('#skipTo', function() { + describe('When nothing has errored', function() { + it('does not skip anything', function() { + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + arrayOfArbitraryFns(4), + 2 + ); + + expect(policy.skipTo(0)).toEqual(1); + expect(policy.skipTo(1)).toEqual(2); + expect(policy.skipTo(2)).toEqual(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + + describe('When anything but a beforeAll has errored', function() { + it('does not skip anything', function() { + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + arrayOfArbitraryFns(4), + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(1); + policy.fnErrored(1); + expect(policy.skipTo(1)).toEqual(2); + policy.fnErrored(2); + expect(policy.skipTo(2)).toEqual(3); + policy.fnErrored(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + + describe('When a beforeAll has errored', function() { + it('skips subsequent functions other than afterAll', function() { + const fns = [ + { type: 'beforeAll', fn: () => {} }, + { fn: () => {} }, + { fn: () => {} }, + { type: 'afterAll', fn: () => {} }, + { type: 'afterAll', fn: () => {} } + ]; + const policy = new jasmineUnderTest.SkipAfterBeforeAllErrorPolicy( + fns, + 2 + ); + + policy.fnErrored(0); + expect(policy.skipTo(0)).toEqual(3); + expect(policy.skipTo(3)).toEqual(4); + }); + }); + }); +}); + +function arrayOfArbitraryFns(n) { + const result = []; + + for (let i = 0; i < n; i++) { + result.push({ fn: () => {} }); + } + + return result; +} diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index b494d1ac..a3967d42 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -482,7 +482,10 @@ describe('TreeProcessor', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], - beforeAllFns: ['beforeAll1', 'beforeAll2'] + beforeAllFns: [ + { fn: 'beforeAll1', timeout: 1 }, + { fn: 'beforeAll2', timeout: 2 } + ] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -502,8 +505,8 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, - 'beforeAll1', - 'beforeAll2', + { type: 'beforeAll', fn: 'beforeAll1', timeout: 1 }, + { type: 'beforeAll', fn: 'beforeAll2', timeout: 2 }, { fn: jasmine.any(Function) } ]); }); @@ -512,7 +515,7 @@ describe('TreeProcessor', function() { var leaf = new Leaf(), node = new Node({ children: [leaf], - afterAllFns: ['afterAll1', 'afterAll2'] + afterAllFns: [{ fn: 'afterAll1' }, { fn: 'afterAll2' }] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -533,15 +536,15 @@ describe('TreeProcessor', function() { expect(queueableFns).toEqual([ { fn: jasmine.any(Function) }, { fn: jasmine.any(Function) }, - 'afterAll1', - 'afterAll2' + { type: 'afterAll', fn: 'afterAll1' }, + { type: 'afterAll', fn: 'afterAll2' } ]); }); it('does not run beforeAlls or afterAlls for a node with no children', function() { var node = new Node({ - beforeAllFns: ['before'], - afterAllFns: ['after'] + beforeAllFns: [{ fn: 'before' }], + afterAllFns: [{ fn: 'after' }] }), root = new Node({ children: [node] }), queueRunner = jasmine.createSpy('queueRunner'), @@ -566,8 +569,8 @@ describe('TreeProcessor', function() { var leaf = new Leaf({ markedPending: true }), node = new Node({ children: [leaf], - beforeAllFns: ['before'], - afterAllFns: ['after'], + beforeAllFns: [{ fn: 'before' }], + afterAllFns: [{ fn: 'after' }], markedPending: false }), root = new Node({ children: [node] }), diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 52d8ab32..60b9c0e4 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -1158,6 +1158,68 @@ describe('spec running', function() { }); }); + describe('When a beforeAll function fails', function() { + it('skips contained specs and suites', async function() { + const outerBeforeEach = jasmine.createSpy('outerBeforeEach'); + const nestedBeforeEach = jasmine.createSpy('nestedBeforeEach'); + const outerAfterEach = jasmine.createSpy('outerAfterEach'); + const nestedAfterEach = jasmine.createSpy('nestedAfterEach'); + const outerIt = jasmine.createSpy('outerIt'); + const nestedIt = jasmine.createSpy('nestedIt'); + const nestedBeforeAll = jasmine.createSpy('nestedBeforeAll'); + + env.beforeAll(function() { + throw new Error('nope'); + }); + + env.beforeEach(outerBeforeEach); + env.it('a spec', outerIt); + env.describe('a nested suite', function() { + env.beforeAll(nestedBeforeAll); + env.beforeEach(nestedBeforeEach); + env.it('a nested spec', nestedIt); + env.afterEach(nestedAfterEach); + }); + env.afterEach(outerAfterEach); + + await env.execute(); + + expect(outerBeforeEach).not.toHaveBeenCalled(); + expect(outerIt).not.toHaveBeenCalled(); + expect(nestedBeforeAll).not.toHaveBeenCalled(); + expect(nestedBeforeEach).not.toHaveBeenCalled(); + expect(nestedIt).not.toHaveBeenCalled(); + expect(nestedAfterEach).not.toHaveBeenCalled(); + expect(outerAfterEach).not.toHaveBeenCalled(); + }); + + it('runs afterAll functions in the current suite and outer scopes', async function() { + const outerAfterAll = jasmine.createSpy('outerAfterAll'); + const nestedAfterAll = jasmine.createSpy('nestedAfterAll'); + const secondNestedAfterAll = jasmine.createSpy('secondNestedAfterAll'); + + env.describe('a nested suite', function() { + env.beforeAll(function() { + throw new Error('nope'); + }); + + env.describe('more nesting', function() { + env.it('a nested spec', function() {}); + env.afterAll(secondNestedAfterAll); + }); + + env.afterAll(nestedAfterAll); + }); + env.afterAll(outerAfterAll); + + await env.execute(); + + expect(secondNestedAfterAll).not.toHaveBeenCalled(); + expect(nestedAfterAll).toHaveBeenCalled(); + expect(outerAfterAll).toHaveBeenCalled(); + }); + }); + describe('when stopOnSpecFailure is on', function() { it('does not run further specs when one fails', function(done) { var actions = [], diff --git a/src/core/CompleteOnFirstErrorSkipPolicy.js b/src/core/CompleteOnFirstErrorSkipPolicy.js index 89a6070f..d99e0124 100644 --- a/src/core/CompleteOnFirstErrorSkipPolicy.js +++ b/src/core/CompleteOnFirstErrorSkipPolicy.js @@ -1,19 +1,20 @@ getJasmineRequireObj().CompleteOnFirstErrorSkipPolicy = function(j$) { function CompleteOnFirstErrorSkipPolicy(queueableFns, firstCleanupIx) { - this.queueableFns_ = queueableFns; this.firstCleanupIx_ = firstCleanupIx; + this.skipping_ = false; } - CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function( - lastRanFnIx, - errored - ) { - if (errored && lastRanFnIx < this.firstCleanupIx_) { + CompleteOnFirstErrorSkipPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_ && lastRanFnIx < this.firstCleanupIx_) { return this.firstCleanupIx_; } else { return lastRanFnIx + 1; } }; + CompleteOnFirstErrorSkipPolicy.prototype.fnErrored = function(fnIx) { + this.skipping_ = true; + }; + return CompleteOnFirstErrorSkipPolicy; }; diff --git a/src/core/Env.js b/src/core/Env.js index 15f06f6a..ce6cf454 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -502,15 +502,19 @@ getJasmineRequireObj().Env = function(j$) { }; var queueRunnerFactory = function(options, args) { - if ( + if (options.isLeaf) { // A spec - options.isLeaf || - // A suite, and config.stopOnSpecFailure is set - (!options.isLeaf && !options.isReporter && config.stopOnSpecFailure) - ) { options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; - } else { + } else if (options.isReporter) { + // A reporter queue options.SkipPolicy = j$.NeverSkipPolicy; + } else { + // A suite + if (config.stopOnSpecFailure) { + options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy; + } else { + options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy; + } } options.clearStack = options.clearStack || clearStack; diff --git a/src/core/NeverSkipPolicy.js b/src/core/NeverSkipPolicy.js index c256bd3c..75fb78d9 100644 --- a/src/core/NeverSkipPolicy.js +++ b/src/core/NeverSkipPolicy.js @@ -1,9 +1,11 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) { function NeverSkipPolicy(queueableFns, firstCleanupIx) {} - NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx, errored) { + NeverSkipPolicy.prototype.skipTo = function(lastRanFnIx) { return lastRanFnIx + 1; }; + NeverSkipPolicy.prototype.fnErrored = function(fnIx) {}; + return NeverSkipPolicy; }; diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 03089d0c..9223c5e0 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -59,7 +59,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { const SkipPolicy = attrs.SkipPolicy || j$.NeverSkipPolicy; this.skipPolicy_ = new SkipPolicy(this.queueableFns, this.firstCleanupIx); - this.errored = false; + this.errored_ = false; if (typeof this.onComplete !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); @@ -115,7 +115,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!(err instanceof StopExecutionError) && !err.jasmineMessage) { self.fail(err); } - self.errored = errored = true; + self.recordError_(iterativeIndex); } function runNext() { @@ -141,7 +141,6 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } ), - errored = false, timedOut = false, queueableFn = self.queueableFns[iterativeIndex], timeoutId, @@ -149,7 +148,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { next.fail = function nextFail() { self.fail.apply(null, arguments); - self.errored = errored = true; + self.recordError_(iterativeIndex); next(); }; @@ -192,15 +191,15 @@ getJasmineRequireObj().QueueRunner = function(j$) { } } catch (e) { onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } cleanup(); - return { completedSynchronously: true, errored: errored }; + return { completedSynchronously: true }; function onException(e) { self.onException(e); - self.errored = errored = true; + self.recordError_(iterativeIndex); } function onPromiseRejection(e) { @@ -224,14 +223,12 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (!result.completedSynchronously) { return; } - - self.errored = self.errored || result.errored; } this.clearStack(function() { self.globalErrors.popListener(self.handleFinalError); - if (self.errored) { + if (self.errored_) { self.onComplete(new StopExecutionError()); } else { self.onComplete(); @@ -240,7 +237,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { }; QueueRunner.prototype.nextFnIx_ = function(currentFnIx) { - const result = this.skipPolicy_.skipTo(currentFnIx, this.errored); + const result = this.skipPolicy_.skipTo(currentFnIx); if (result === currentFnIx) { throw new Error("Can't skip to the same queueable fn that just finished"); @@ -249,6 +246,11 @@ getJasmineRequireObj().QueueRunner = function(j$) { return result; }; + QueueRunner.prototype.recordError_ = function(currentFnIx) { + this.errored_ = true; + this.skipPolicy_.fnErrored(currentFnIx); + }; + QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) { var msg; diff --git a/src/core/SkipAfterBeforeAllErrorPolicy.js b/src/core/SkipAfterBeforeAllErrorPolicy.js new file mode 100644 index 00000000..e2d37630 --- /dev/null +++ b/src/core/SkipAfterBeforeAllErrorPolicy.js @@ -0,0 +1,32 @@ +getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) { + function SkipAfterBeforeAllErrorPolicy(queueableFns, firstCleanupIx) { + this.queueableFns_ = queueableFns; + this.skipping_ = false; + } + + SkipAfterBeforeAllErrorPolicy.prototype.skipTo = function(lastRanFnIx) { + if (this.skipping_) { + return this.nextAfterAllAfter_(lastRanFnIx); + } else { + return lastRanFnIx + 1; + } + }; + + SkipAfterBeforeAllErrorPolicy.prototype.nextAfterAllAfter_ = function(i) { + for ( + i++; + i < this.queueableFns_.length && + this.queueableFns_[i].type !== 'afterAll'; + i++ + ) {} + return i; + }; + + SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) { + if (this.queueableFns_[fnIx].type === 'beforeAll') { + this.skipping_ = true; + } + }; + + return SkipAfterBeforeAllErrorPolicy; +}; diff --git a/src/core/TreeProcessor.js b/src/core/TreeProcessor.js index f93fc044..e3d8eeff 100644 --- a/src/core/TreeProcessor.js +++ b/src/core/TreeProcessor.js @@ -253,7 +253,16 @@ getJasmineRequireObj().TreeProcessor = function() { return result; } - return node.beforeAllFns.concat(result).concat(node.afterAllFns); + return node.beforeAllFns + .map(function(fn) { + return { type: 'beforeAll', ...fn }; + }) + .concat(result) + .concat( + node.afterAllFns.map(function(fn) { + return { type: 'afterAll', ...fn }; + }) + ); } } diff --git a/src/core/requireCore.js b/src/core/requireCore.js index 08c1e006..e8e17994 100644 --- a/src/core/requireCore.js +++ b/src/core/requireCore.js @@ -61,6 +61,9 @@ var getJasmineRequireObj = (function(jasmineGlobal) { j$.SetContaining = jRequire.SetContaining(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.NeverSkipPolicy = jRequire.NeverSkipPolicy(j$); + j$.SkipAfterBeforeAllErrorPolicy = jRequire.SkipAfterBeforeAllErrorPolicy( + j$ + ); j$.CompleteOnFirstErrorSkipPolicy = jRequire.CompleteOnFirstErrorSkipPolicy( j$ );