From c2ce55580c4246173c664e6c9760aaddf1c5e484 Mon Sep 17 00:00:00 2001 From: Steve Gravrock Date: Sat, 27 Sep 2025 13:33:25 -0700 Subject: [PATCH] Remove support for excution orders that re-enter suites --- lib/jasmine-core/jasmine.js | 30 ++---- spec/core/RunnerSpec.js | 131 ----------------------- spec/core/TreeProcessorSpec.js | 48 +++------ spec/core/TreeRunnerSpec.js | 12 +-- spec/core/integration/SpecRunningSpec.js | 63 +---------- src/core/TreeProcessor.js | 22 ++-- src/core/TreeRunner.js | 8 +- 7 files changed, 42 insertions(+), 272 deletions(-) diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 3d927b00..9a614a5d 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -11336,8 +11336,7 @@ getJasmineRequireObj().TreeProcessor = function(j$) { const defaultMax = 1 - Infinity; // Transforms the suite tree into an execution tree, which represents the set - // of specs and (possibly interleaved) suites to be run in the order they are - // to be run in. + // of specs and suites to be run in the order they are to be run in. class TreeProcessor { #tree; #runnableIds; @@ -11419,15 +11418,7 @@ getJasmineRequireObj().TreeProcessor = function(j$) { segmentChildren(node, orderedChildren, this.#stats, executableIndex); if (this.#stats[node.id].segments.length > 1) { - if (node.canBeReentered()) { - j$.getEnv().deprecated( - 'The specified spec/suite order splits up a suite, running unrelated specs in the middle of it. This will become an error in a future release.' - ); - } else { - throw new Error( - 'Invalid order: would cause a beforeAll or afterAll to be run multiple times' - ); - } + throw new Error('Invalid order: would split up a suite'); } } } @@ -11445,15 +11436,14 @@ getJasmineRequireObj().TreeProcessor = function(j$) { } childrenOfTopSuite() { - return this.childrenOfSuiteSegment(this.topSuite, 0); + return this.childrenOfSuite(this.topSuite); } - childrenOfSuiteSegment(suite, segmentNumber) { - const segmentChildren = this.#stats[suite.id].segments[segmentNumber] - .nodes; + childrenOfSuite(suite) { + const segmentChildren = this.#stats[suite.id].segments[0].nodes; return segmentChildren.map(function(child) { if (child.owner.children) { - return { suite: child.owner, segmentNumber: child.index }; + return { suite: child.owner }; } else { return { spec: child.owner }; } @@ -11574,7 +11564,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { async execute() { this.#hasFailures = false; await new Promise(resolve => { - this.#executeSuiteSegment(this.#executionTree.topSuite, 0, resolve); + this.#executeSuite(this.#executionTree.topSuite, resolve); }); return { hasFailures: this.#hasFailures }; } @@ -11584,7 +11574,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { return { fn: done => { if (node.suite) { - this.#executeSuiteSegment(node.suite, node.segmentNumber, done); + this.#executeSuite(node.suite, done); } else { this._executeSpec(node.spec, done); } @@ -11674,7 +11664,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { return fns; } - #executeSuiteSegment(suite, segmentNumber, done) { + #executeSuite(suite, done) { const isTopSuite = suite === this.#executionTree.topSuite; const isExcluded = this.#executionTree.isExcluded(suite); let befores = []; @@ -11696,7 +11686,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { const children = isTopSuite ? this.#executionTree.childrenOfTopSuite() - : this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber); + : this.#executionTree.childrenOfSuite(suite); const queueableFns = [ ...befores, ...this.#wrapNodes(children), diff --git a/spec/core/RunnerSpec.js b/spec/core/RunnerSpec.js index b4170886..c3cb65b0 100644 --- a/spec/core/RunnerSpec.js +++ b/spec/core/RunnerSpec.js @@ -470,137 +470,6 @@ describe('Runner', function() { await expectAsync(promise).toBePending(); }); - it('runs a suite multiple times if the order specified leaves and re-enters it', async function() { - const spec1 = new StubSpec(); - const spec2 = new StubSpec(); - const spec3 = new StubSpec(); - const spec4 = new StubSpec(); - const spec5 = new StubSpec(); - const reentered = new StubSuite({ children: [spec1, spec2, spec3] }); - const topSuite = new StubSuite({ children: [reentered, spec4, spec5] }); - const subject = makeRunner(topSuite); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - const promise = subject.execute([ - spec1.id, - spec4.id, - spec2.id, - spec5.id, - spec3.id - ]); - await Promise.resolve(); - expect(runQueue).toHaveBeenCalledTimes(1); - const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns; - - queueableFns[0].fn(); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec1, 'done'); - - queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec4, 'done'); - - queueableFns[2].fn(); - expect(runQueue.calls.count()).toBe(3); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec2, 'done'); - - queueableFns[3].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec5, 'done'); - - queueableFns[4].fn(); - expect(runQueue.calls.count()).toBe(4); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec3, 'done'); - - await expectAsync(promise).toBePending(); - }); - - it('runs a parent of a suite with multiple segments correctly', async function() { - const spec1 = new StubSpec(); - const spec2 = new StubSpec(); - const spec3 = new StubSpec(); - const spec4 = new StubSpec(); - const spec5 = new StubSpec(); - const parent = new StubSuite({ children: [spec1, spec2, spec3] }); - const grandparent = new StubSuite({ children: [parent] }); - const topSuite = new StubSuite({ children: [grandparent, spec4, spec5] }); - const subject = makeRunner(topSuite); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - const promise = subject.execute([ - spec1.id, - spec4.id, - spec2.id, - spec5.id, - spec3.id - ]); - await Promise.resolve(); - expect(runQueue).toHaveBeenCalledTimes(1); - const queueableFns = runQueue.calls.mostRecent().args[0].queueableFns; - expect(queueableFns.length).toBe(5); - - queueableFns[0].fn(); - expect(runQueue.calls.count()).toBe(2); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn(); - expect(runQueue.calls.count()).toBe(3); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec1, 'done'); - - queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec4, 'done'); - - queueableFns[2].fn(); - expect(runQueue.calls.count()).toBe(4); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn(); - expect(runQueue.calls.count()).toBe(5); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec2, 'done'); - - queueableFns[3].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec5, 'done'); - - queueableFns[4].fn(); - expect(runQueue.calls.count()).toBe(6); - expect(runQueue.calls.mostRecent().args[0].queueableFns.length).toBe(2); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn(); - expect(runQueue.calls.count()).toBe(7); - - runQueue.calls.mostRecent().args[0].queueableFns[1].fn('done'); - expect( - privateUnderTest.TreeRunner.prototype._executeSpec - ).toHaveBeenCalledWith(spec3, 'done'); - - await expectAsync(promise).toBePending(); - }); - it('runs large segments of nodes in the order they were declared', async function() { const specs = []; diff --git a/spec/core/TreeProcessorSpec.js b/spec/core/TreeProcessorSpec.js index ceabd5fc..699be65c 100644 --- a/spec/core/TreeProcessorSpec.js +++ b/spec/core/TreeProcessorSpec.js @@ -135,11 +135,9 @@ describe('TreeProcessor', function() { const result = processor.processTree(); - expect(result.childrenOfTopSuite()).toEqual([ - { suite: node, segmentNumber: 0 } - ]); + expect(result.childrenOfTopSuite()).toEqual([{ suite: node }]); expect(result.isExcluded(node)).toEqual(true); - expect(result.childrenOfSuiteSegment(node, 0)).toEqual([{ spec: leaf1 }]); + expect(result.childrenOfSuite(node)).toEqual([{ spec: leaf1 }]); expect(result.isExcluded(node)).toEqual(true); }); @@ -167,37 +165,37 @@ describe('TreeProcessor', function() { expect(result.isExcluded(parent)).toEqual(false); expect(result.childrenOfTopSuite()).toEqual([ - { suite: parent, segmentNumber: 0 }, - { suite: parentOfPendings, segmentNumber: 0 } + { suite: parent }, + { suite: parentOfPendings } ]); expect(result.isExcluded(parentOfPendings)).toEqual(true); - expect(result.childrenOfSuiteSegment(parentOfPendings, 0)).toEqual([ - { suite: childless, segmentNumber: 0 }, - { suite: pendingNode, segmentNumber: 0 } + expect(result.childrenOfSuite(parentOfPendings)).toEqual([ + { suite: childless }, + { suite: pendingNode } ]); expect(result.isExcluded(childless)).toEqual(true); - expect(result.childrenOfSuiteSegment(childless, 0)).toEqual([]); + expect(result.childrenOfSuite(childless)).toEqual([]); expect(result.isExcluded(pendingLeaf)).toEqual(false); expect(result.isExcluded(executableLeaf)).toEqual(false); expect(result.isExcluded(parent)).toEqual(false); - expect(result.childrenOfSuiteSegment(parent, 0)).toEqual([ + expect(result.childrenOfSuite(parent)).toEqual([ { spec: pendingLeaf }, { spec: executableLeaf } ]); expect(result.isExcluded(pendingNode)).toEqual(true); - expect(result.childrenOfSuiteSegment(pendingNode, 0)).toEqual([ + expect(result.childrenOfSuite(pendingNode)).toEqual([ { spec: childOfPending } ]); expect(result.isExcluded(childOfPending)).toEqual(false); }); - it('throws if the specified order would re-enter a node that does not allow re-entry', function() { + it('throws if the specified order would re-enter a node', function() { const leaf1 = new Leaf(), leaf2 = new Leaf(), leaf3 = new Leaf(), @@ -210,29 +208,7 @@ describe('TreeProcessor', function() { expect(function() { processor.processTree(); - }).toThrowError( - 'Invalid order: would cause a beforeAll or afterAll to be run multiple times' - ); - }); - - it('does not throw if a node being re-entered allows re-entry', function() { - const leaf1 = new Leaf(); - const leaf2 = new Leaf(); - const leaf3 = new Leaf(); - const reentered = new Node({ children: [leaf1, leaf2] }); - const root = new Node({ children: [reentered, leaf3] }); - const processor = new privateUnderTest.TreeProcessor({ - tree: root, - runnableIds: [leaf1.id, leaf3.id, leaf2.id] - }); - const env = jasmineUnderTest.getEnv(); - spyOn(env, 'deprecated'); - - processor.processTree(); - - expect(env.deprecated).toHaveBeenCalledWith( - 'The specified spec/suite order splits up a suite, running unrelated specs in the middle of it. This will become an error in a future release.' - ); + }).toThrowError('Invalid order: would split up a suite'); }); it("does not throw if a node which can't be re-entered is only entered once", function() { diff --git a/spec/core/TreeRunnerSpec.js b/spec/core/TreeRunnerSpec.js index 634098df..d9771a2c 100644 --- a/spec/core/TreeRunnerSpec.js +++ b/spec/core/TreeRunnerSpec.js @@ -180,7 +180,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return []; }, isExcluded() { @@ -240,7 +240,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite: failingSuite }, { suite: passingSuite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return []; }, isExcluded() { @@ -308,7 +308,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return [{ spec }]; }, isExcluded() { @@ -371,7 +371,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return [{ spec }]; }, isExcluded() { @@ -519,7 +519,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return [{ spec }]; }, isExcluded() { @@ -588,7 +588,7 @@ describe('TreeRunner', function() { childrenOfTopSuite() { return [{ suite }]; }, - childrenOfSuiteSegment() { + childrenOfSuite() { return [{ spec }]; }, isExcluded() { diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index 932c6788..355d0407 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -601,37 +601,7 @@ describe('spec running', function() { ]); }); - it('re-enters suites that have no *Alls', async function() { - const actions = []; - let spec1; - let spec2; - let spec3; - - env.describe('top', function() { - spec1 = env.it('spec1', function() { - actions.push('spec1'); - }); - - spec2 = env.it('spec2', function() { - actions.push('spec2'); - }); - }); - - spec3 = env.it('spec3', function() { - actions.push('spec3'); - }); - - spyOn(jasmineUnderTest.getEnv(), 'deprecated'); - - await env.execute([spec2.id, spec3.id, spec1.id]); - - expect(actions).toEqual(['spec2', 'spec3', 'spec1']); - expect(jasmineUnderTest.getEnv().deprecated).toHaveBeenCalledWith( - 'The specified spec/suite order splits up a suite, running unrelated specs in the middle of it. This will become an error in a future release.' - ); - }); - - it('refuses to re-enter suites with a beforeAll', async function() { + it('refuses to re-enter suites', async function() { const actions = []; let spec1; let spec2; @@ -654,34 +624,9 @@ describe('spec running', function() { }); const promise = env.execute([spec2.id, spec3.id, spec1.id]); - await expectAsync(promise).toBeRejectedWithError(/beforeAll/); - expect(actions).toEqual([]); - }); - - it('refuses to re-enter suites with a afterAll', async function() { - const actions = []; - let spec1; - let spec2; - let spec3; - - env.describe('top', function() { - env.afterAll(function() {}); - - spec1 = env.it('spec1', function() { - actions.push('spec1'); - }); - - spec2 = env.it('spec2', function() { - actions.push('spec2'); - }); - }); - - spec3 = env.it('spec3', function() { - actions.push('spec3'); - }); - - const promise = env.execute([spec2.id, spec3.id, spec1.id]); - await expectAsync(promise).toBeRejectedWithError(/afterAll/); + await expectAsync(promise).toBeRejectedWithError( + 'Invalid order: would split up a suite' + ); expect(actions).toEqual([]); }); diff --git a/src/core/TreeProcessor.js b/src/core/TreeProcessor.js index a26a80b6..72f7bfec 100644 --- a/src/core/TreeProcessor.js +++ b/src/core/TreeProcessor.js @@ -3,8 +3,7 @@ getJasmineRequireObj().TreeProcessor = function(j$) { const defaultMax = 1 - Infinity; // Transforms the suite tree into an execution tree, which represents the set - // of specs and (possibly interleaved) suites to be run in the order they are - // to be run in. + // of specs and suites to be run in the order they are to be run in. class TreeProcessor { #tree; #runnableIds; @@ -86,15 +85,7 @@ getJasmineRequireObj().TreeProcessor = function(j$) { segmentChildren(node, orderedChildren, this.#stats, executableIndex); if (this.#stats[node.id].segments.length > 1) { - if (node.canBeReentered()) { - j$.getEnv().deprecated( - 'The specified spec/suite order splits up a suite, running unrelated specs in the middle of it. This will become an error in a future release.' - ); - } else { - throw new Error( - 'Invalid order: would cause a beforeAll or afterAll to be run multiple times' - ); - } + throw new Error('Invalid order: would split up a suite'); } } } @@ -112,15 +103,14 @@ getJasmineRequireObj().TreeProcessor = function(j$) { } childrenOfTopSuite() { - return this.childrenOfSuiteSegment(this.topSuite, 0); + return this.childrenOfSuite(this.topSuite); } - childrenOfSuiteSegment(suite, segmentNumber) { - const segmentChildren = this.#stats[suite.id].segments[segmentNumber] - .nodes; + childrenOfSuite(suite) { + const segmentChildren = this.#stats[suite.id].segments[0].nodes; return segmentChildren.map(function(child) { if (child.owner.children) { - return { suite: child.owner, segmentNumber: child.index }; + return { suite: child.owner }; } else { return { spec: child.owner }; } diff --git a/src/core/TreeRunner.js b/src/core/TreeRunner.js index 5d96d4da..ece555d9 100644 --- a/src/core/TreeRunner.js +++ b/src/core/TreeRunner.js @@ -24,7 +24,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { async execute() { this.#hasFailures = false; await new Promise(resolve => { - this.#executeSuiteSegment(this.#executionTree.topSuite, 0, resolve); + this.#executeSuite(this.#executionTree.topSuite, resolve); }); return { hasFailures: this.#hasFailures }; } @@ -34,7 +34,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { return { fn: done => { if (node.suite) { - this.#executeSuiteSegment(node.suite, node.segmentNumber, done); + this.#executeSuite(node.suite, done); } else { this._executeSpec(node.spec, done); } @@ -124,7 +124,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { return fns; } - #executeSuiteSegment(suite, segmentNumber, done) { + #executeSuite(suite, done) { const isTopSuite = suite === this.#executionTree.topSuite; const isExcluded = this.#executionTree.isExcluded(suite); let befores = []; @@ -146,7 +146,7 @@ getJasmineRequireObj().TreeRunner = function(j$) { const children = isTopSuite ? this.#executionTree.childrenOfTopSuite() - : this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber); + : this.#executionTree.childrenOfSuite(suite); const queueableFns = [ ...befores, ...this.#wrapNodes(children),