From 598eafe6d67a8867fb8d4a830f2cfd80fffda654 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 11:36:16 +0900 Subject: [PATCH 1/9] docs: start Vitest 5 migration guide Co-authored-by: Codex --- docs/api/describe.md | 24 ----------------------- docs/api/test.md | 42 ----------------------------------------- docs/guide/migration.md | 23 ++++++++++++++++++++++ 3 files changed, 23 insertions(+), 66 deletions(-) diff --git a/docs/api/describe.md b/docs/api/describe.md index 2d37a4c2fa5e..edddc0a1b62d 100644 --- a/docs/api/describe.md +++ b/docs/api/describe.md @@ -230,30 +230,6 @@ describe.concurrent('suite', () => { }) ``` -## describe.sequential {#describe-sequential} - -- **Alias:** `suite.sequential` - -::: warning DEPRECATED -Use [`concurrent: false`](/api/test#concurrent) instead when you need to override inherited or configured concurrency. -::: - -`describe.sequential` in a suite marks every test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. - -```ts -import { describe, test } from 'vitest' - -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - describe.sequential('', () => { - test('sequential test 1', async () => { /* ... */ }) - test('sequential test 2', async () => { /* ... */ }) - }) -}) -``` - ## describe.shuffle - **Alias:** `suite.shuffle` diff --git a/docs/api/test.md b/docs/api/test.md index 7618fa19a539..726165e7bcaa 100644 --- a/docs/api/test.md +++ b/docs/api/test.md @@ -217,18 +217,6 @@ Prefer using non-nested meta, if possible. Whether this test run concurrently with other concurrent tests in the suite. -### sequential - -- **Type:** `boolean` -- **Default:** `true` -- **Alias:** [`test.sequential`](#test-sequential) - -::: warning DEPRECATED -Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. -::: - -Whether tests run sequentially. When both `concurrent` and `sequential` are specified, `concurrent` takes precedence. - ### skip - **Type:** `boolean` @@ -457,36 +445,6 @@ test.concurrent('test 2', async ({ expect }) => { Note that if tests are synchronous, Vitest will still run them sequentially. -## test.sequential {#test-sequential} - -- **Alias:** `it.sequential` - -::: warning DEPRECATED -Use [`concurrent: false`](#concurrent) instead when you need to override inherited or configured concurrency. -::: - -`test.sequential` marks a test as sequential. This is useful if you want to run tests in sequence within `describe.concurrent` or with the `--sequence.concurrent` command option. - -```ts -import { describe, test } from 'vitest' - -// with config option { sequence: { concurrent: true } } -test('concurrent test 1', async () => { /* ... */ }) -test('concurrent test 2', async () => { /* ... */ }) - -test.sequential('sequential test 1', async () => { /* ... */ }) -test.sequential('sequential test 2', async () => { /* ... */ }) - -// within concurrent suite -describe.concurrent('suite', () => { - test('concurrent test 1', async () => { /* ... */ }) - test('concurrent test 2', async () => { /* ... */ }) - - test.sequential('sequential test 1', async () => { /* ... */ }) - test.sequential('sequential test 2', async () => { /* ... */ }) -}) -``` - ## test.todo - **Alias:** `it.todo` diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 82963564b1e7..e00326cd755e 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -7,6 +7,29 @@ outline: deep [Migrating to Vitest 3.0](https://v3.vitest.dev/guide/migration) | [Migrating to Vitest 2.0](https://v2.vitest.dev/guide/migration) +## Migrating to Vitest 5.0 {#vitest-5} + +### Removed `test.sequential`, `describe.sequential`, and `sequential` Options + +Vitest 5.0 removes the deprecated `test.sequential`, `describe.sequential`, and `sequential` test options. Use `concurrent: false` when you need a test or suite to opt out of inherited or globally configured concurrency. + +```ts +test.sequential('example', async () => { /* ... */ }) // [!code --] +test('example', { concurrent: false }, async () => { /* ... */ }) // [!code ++] +``` + +```ts +describe.sequential('suite', () => { /* ... */ }) // [!code --] +describe('suite', { concurrent: false }, () => { /* ... */ }) // [!code ++] +``` + +The same replacement applies to option objects: + +```ts +test('example', { sequential: true }, async () => { /* ... */ }) // [!code --] +test('example', { concurrent: false }, async () => { /* ... */ }) // [!code ++] +``` + ## Migrating to Vitest 4.0 {#vitest-4} ::: warning Prerequisites From e7ba4c44d561459d8652141ecc9d58936d10a4e2 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 11:44:21 +0900 Subject: [PATCH 2/9] fix: remove sequential from static collection Co-authored-by: Codex --- packages/vitest/src/node/ast-collect.ts | 25 +++----- test/cli/test/static-collect.test.ts | 80 ++++++++++--------------- 2 files changed, 40 insertions(+), 65 deletions(-) diff --git a/packages/vitest/src/node/ast-collect.ts b/packages/vitest/src/node/ast-collect.ts index 4e12e8a1b37a..209955127d6f 100644 --- a/packages/vitest/src/node/ast-collect.ts +++ b/packages/vitest/src/node/ast-collect.ts @@ -43,8 +43,7 @@ interface LocalCallDefinition { mode: 'run' | 'skip' | 'only' | 'todo' | 'queued' task: ParsedSuite | ParsedFile | ParsedTest dynamic: boolean - concurrent: boolean - sequential: boolean + concurrent: boolean | undefined tags: string[] } @@ -172,8 +171,7 @@ function astParseFile(filepath: string, code: string) { mode = 'skip' } } - let isConcurrent = properties.includes('concurrent') - let isSequential = properties.includes('sequential') + let concurrent = properties.includes('concurrent') || undefined let start: number const end = node.end @@ -249,15 +247,12 @@ function astParseFile(filepath: string, code: string) { } } } - else if (prop.value?.type === 'Literal' && prop.value.value === true) { - if (keyName === 'skip' || keyName === 'only' || keyName === 'todo') { + else if (prop.value?.type === 'Literal') { + if ((keyName === 'skip' || keyName === 'only' || keyName === 'todo') && prop.value.value === true) { mode = keyName } - else if (keyName === 'concurrent') { - isConcurrent = true - } - else if (keyName === 'sequential') { - isSequential = true + else if (keyName === 'concurrent' && typeof prop.value.value === 'boolean') { + concurrent = prop.value.value } } } @@ -272,8 +267,7 @@ function astParseFile(filepath: string, code: string) { mode, task: null as any, dynamic: isDynamicEach, - concurrent: isConcurrent, - sequential: isSequential, + concurrent, tags, } satisfies LocalCallDefinition) }, @@ -416,10 +410,7 @@ function createFileTask( // Inherit tags from parent suite and merge with own tags const parentTags = latestSuite.tags || [] const taskTags = unique([...parentTags, ...definition.tags]) - // resolve concurrent/sequential: sequential cancels inherited concurrent - const concurrent = definition.sequential - ? undefined - : (definition.concurrent || latestSuite.concurrent || undefined) + const concurrent = definition.concurrent ?? latestSuite.concurrent if (definition.type === 'suite') { const task: ParsedSuite = { diff --git a/test/cli/test/static-collect.test.ts b/test/cli/test/static-collect.test.ts index c245d2674611..7f5fc43a56f6 100644 --- a/test/cli/test/static-collect.test.ts +++ b/test/cli/test/static-collect.test.ts @@ -1137,14 +1137,15 @@ test('collects tags with other options', async () => { `) }) -test('sequential cancels inherited concurrent', async () => { +test('concurrent false cancels inherited concurrent', async () => { const testModule = await collectTests(` import { test, describe } from 'vitest' describe.concurrent('concurrent suite', () => { test('inherits concurrent', () => {}) + test('not concurrent via options', { concurrent: false }, () => {}) - describe.sequential('sequential nested', () => { + describe('non-concurrent nested', { concurrent: false }, () => { test('not concurrent', () => {}) }) @@ -1165,23 +1166,31 @@ test('sequential cancels inherited concurrent', async () => { "mode": "run", "state": "pending", }, - "regular nested": { - "still concurrent": { - "concurrent": true, + "non-concurrent nested": { + "not concurrent": { "errors": [], - "fullName": "concurrent suite > regular nested > still concurrent", + "fullName": "concurrent suite > non-concurrent nested > not concurrent", "id": "-1732721377_0_2_0", - "location": "12:8", + "location": "9:8", "mode": "run", "state": "pending", }, }, - "sequential nested": { - "not concurrent": { + "not concurrent via options": { + "errors": [], + "fullName": "concurrent suite > not concurrent via options", + "id": "-1732721377_0_1", + "location": "6:6", + "mode": "run", + "state": "pending", + }, + "regular nested": { + "still concurrent": { + "concurrent": true, "errors": [], - "fullName": "concurrent suite > sequential nested > not concurrent", - "id": "-1732721377_0_1_0", - "location": "8:8", + "fullName": "concurrent suite > regular nested > still concurrent", + "id": "-1732721377_0_3_0", + "location": "13:8", "mode": "run", "state": "pending", }, @@ -1191,40 +1200,6 @@ test('sequential cancels inherited concurrent', async () => { `) }) -test('collects tests with sequential modifier', async () => { - const testModule = await collectTests(` - import { test, describe } from 'vitest' - - describe.sequential('sequential suite', () => { - test('test in sequential suite', () => {}) - }) - - test.sequential('sequential test', () => {}) -`) - expect(testModule).toMatchInlineSnapshot(` - { - "sequential suite": { - "test in sequential suite": { - "errors": [], - "fullName": "sequential suite > test in sequential suite", - "id": "-1732721377_0_0", - "location": "5:6", - "mode": "run", - "state": "pending", - }, - }, - "sequential test": { - "errors": [], - "fullName": "sequential test", - "id": "-1732721377_1", - "location": "8:4", - "mode": "run", - "state": "pending", - }, - } - `) -}) - test('collects tests with concurrent modifier in different order', async () => { const testModule = await collectTests(` import { test, describe } from 'vitest' @@ -1269,6 +1244,7 @@ test('collects tests with options object modifiers', async () => { test('only via options', { only: true }, () => {}) test('todo via options', { todo: true }, () => {}) test('concurrent via options', { concurrent: true }, () => {}) + test('not concurrent via options', { concurrent: false }, () => {}) test('skip and concurrent via options', { skip: true, concurrent: true }, () => {}) }) `) @@ -1284,6 +1260,14 @@ test('collects tests with options object modifiers', async () => { "mode": "skip", "state": "skipped", }, + "not concurrent via options": { + "errors": [], + "fullName": "options tests > not concurrent via options", + "id": "-1732721377_0_4", + "location": "9:6", + "mode": "skip", + "state": "skipped", + }, "only via options": { "errors": [], "fullName": "options tests > only via options", @@ -1296,8 +1280,8 @@ test('collects tests with options object modifiers', async () => { "concurrent": true, "errors": [], "fullName": "options tests > skip and concurrent via options", - "id": "-1732721377_0_4", - "location": "9:6", + "id": "-1732721377_0_5", + "location": "10:6", "mode": "skip", "state": "skipped", }, From 76b803f525cdee0c8d67c08cbf5aedbd028e83be Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 11:50:53 +0900 Subject: [PATCH 3/9] docs: explain concurrent false opt out Co-authored-by: Codex --- docs/api/describe.md | 13 +++++++++++++ docs/api/test.md | 8 ++++++++ docs/guide/parallelism.md | 13 +++++++++++++ 3 files changed, 34 insertions(+) diff --git a/docs/api/describe.md b/docs/api/describe.md index edddc0a1b62d..f1a95f9ed74d 100644 --- a/docs/api/describe.md +++ b/docs/api/describe.md @@ -208,6 +208,19 @@ describe.concurrent('suite', () => { }) ``` +Set `concurrent` to `false` to opt out of concurrency inherited from a parent suite or [`sequence.concurrent`](/config/sequence#sequence-concurrent): + +```ts +describe.concurrent('suite', () => { + test('concurrent test', async () => { /* ... */ }) + + describe('sequential suite', { concurrent: false }, () => { + test('sequential test 1', async () => { /* ... */ }) + test('sequential test 2', async () => { /* ... */ }) + }) +}) +``` + `.skip`, `.only`, and `.todo` works with concurrent suites. All the following combinations are valid: ```ts diff --git a/docs/api/test.md b/docs/api/test.md index 726165e7bcaa..670f40067eae 100644 --- a/docs/api/test.md +++ b/docs/api/test.md @@ -217,6 +217,14 @@ Prefer using non-nested meta, if possible. Whether this test run concurrently with other concurrent tests in the suite. +Set `concurrent` to `false` to opt out of concurrency inherited from [`describe.concurrent`](/api/describe#describe-concurrent) or [`sequence.concurrent`](/config/sequence#sequence-concurrent): + +```ts +test('runs sequentially', { concurrent: false }, async () => { + // ... +}) +``` + ### skip - **Type:** `boolean` diff --git a/docs/guide/parallelism.md b/docs/guide/parallelism.md index 4c694c3b8c57..c273eeefbcdc 100644 --- a/docs/guide/parallelism.md +++ b/docs/guide/parallelism.md @@ -80,6 +80,19 @@ describe.concurrent('user API', () => { If you want *all* tests in your project to run concurrently by default, set [`sequence.concurrent`](/config/sequence#sequence-concurrent) to `true` in your config. +You can opt individual tests or suites out of inherited concurrency with `concurrent: false`: + +```ts +test('uses a shared resource', { concurrent: false }, async () => { + // ... +}) + +describe('shared resource suite', { concurrent: false }, () => { + test('step 1', async () => { /* ... */ }) + test('step 2', async () => { /* ... */ }) +}) +``` + ### Hooks with Concurrent Tests When tests run concurrently, lifecycle hooks behave differently. `beforeAll` and `afterAll` still run once for the group, but `beforeEach` and `afterEach` run for each test — potentially at the same time, since the tests themselves overlap. From 30e6dbf2e4770f61bcfb73a14ada1ac31a0e5e08 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 12:01:41 +0900 Subject: [PATCH 4/9] test: remove sequential API coverage Co-authored-by: Codex --- test/cli/test/test-tags.test.ts | 16 +++++----- ...equence-concurrent-true-sequential.test.ts | 31 ------------------- test/config/test/sequence-concurrent.test.ts | 15 +++------ test/core/test/concurrent-suite.test.ts | 8 ----- test/core/test/sequential.test.ts | 23 ++------------ 5 files changed, 16 insertions(+), 77 deletions(-) delete mode 100644 test/config/fixtures/sequence-concurrent/sequence-concurrent-true-sequential.test.ts diff --git a/test/cli/test/test-tags.test.ts b/test/cli/test/test-tags.test.ts index 742c8ae42d7b..a22ebb04e0a8 100644 --- a/test/cli/test/test-tags.test.ts +++ b/test/cli/test/test-tags.test.ts @@ -631,37 +631,39 @@ test('@module-tag with strictTags: false allows undefined tags', async () => { `) }) -test('sequential tag option makes tests run sequentially', async () => { +test('concurrent false tag option opts out of sequence.concurrent', async () => { const { stderr, buildTree } = await runInlineTests({ 'basic.test.js': ` - test('test 1', { tags: ['sequential-tag'] }, () => {}) - test('test 2', { tags: ['sequential-tag'] }, () => {}) + test('test 1', { tags: ['non-concurrent-tag'] }, () => {}) + test('test 2', { tags: ['non-concurrent-tag'] }, () => {}) `, 'vitest.config.js': { test: { globals: true, + sequence: { + concurrent: true, + }, tags: [ - { name: 'sequential-tag', sequential: true }, + { name: 'non-concurrent-tag', concurrent: false }, ], }, }, }) expect(stderr).toBe('') - // sequential is not visible in options, it affect "concurrent" only, which is not set if false expect(buildOptionsTree(buildTree)).toMatchInlineSnapshot(` { "basic.test.js": { "test 1": { "mode": "run", "tags": [ - "sequential-tag", + "non-concurrent-tag", ], "timeout": 5000, }, "test 2": { "mode": "run", "tags": [ - "sequential-tag", + "non-concurrent-tag", ], "timeout": 5000, }, diff --git a/test/config/fixtures/sequence-concurrent/sequence-concurrent-true-sequential.test.ts b/test/config/fixtures/sequence-concurrent/sequence-concurrent-true-sequential.test.ts deleted file mode 100644 index ed2772a7c939..000000000000 --- a/test/config/fixtures/sequence-concurrent/sequence-concurrent-true-sequential.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, test, vi } from 'vitest' - -const delay = (timeout: number) => new Promise(resolve => setTimeout(resolve, timeout)) - -let count = 0 - -describe.sequential('sequential suite', () => { - test('first test completes first', async ({ task }) => { - await delay(40) - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(1) - }) - - test('second test completes second', async ({ task }) => { - await delay(30) - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(2) - }) -}) - -test.sequential('third test completes third', async ({ task }) => { - await delay(20) - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(3) -}) - -test.sequential('last test completes last', async ({ task }) => { - await delay(10) - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(4) -}) diff --git a/test/config/test/sequence-concurrent.test.ts b/test/config/test/sequence-concurrent.test.ts index 8fff8cdda24b..a59a8a0564f8 100644 --- a/test/config/test/sequence-concurrent.test.ts +++ b/test/config/test/sequence-concurrent.test.ts @@ -2,10 +2,13 @@ import { expect, test } from 'vitest' import { runVitest } from '../../test-utils' -test('should run suites and tests concurrently unless sequential specified when sequence.concurrent is true', async () => { +test('should run suites and tests concurrently unless concurrent false is specified when sequence.concurrent is true', async () => { const { stderr, errorTree } = await runVitest({ root: './fixtures/sequence-concurrent', - include: ['sequence-concurrent-true-*.test.ts'], + include: [ + 'sequence-concurrent-true-concurrent.test.ts', + 'sequence-concurrent-true-concurrent-false.test.ts', + ], sequence: { concurrent: true, }, @@ -30,14 +33,6 @@ test('should run suites and tests concurrently unless sequential specified when "last test completes first": "passed", "third test completes second": "passed", }, - "sequence-concurrent-true-sequential.test.ts": { - "last test completes last": "passed", - "sequential suite": { - "first test completes first": "passed", - "second test completes second": "passed", - }, - "third test completes third": "passed", - }, } `) }) diff --git a/test/core/test/concurrent-suite.test.ts b/test/core/test/concurrent-suite.test.ts index 45200d8c3726..5dce907bdf18 100644 --- a/test/core/test/concurrent-suite.test.ts +++ b/test/core/test/concurrent-suite.test.ts @@ -115,14 +115,6 @@ describe('override concurrent', { concurrent: true }, () => { checkSequentialTests() }) - describe.sequential('s-x-1', () => { - checkSequentialTests() - }) - - describe('s-x-2', { sequential: true }, () => { - checkSequentialTests() - }) - describe('s-y', () => { checkParallelTests() }) diff --git a/test/core/test/sequential.test.ts b/test/core/test/sequential.test.ts index a6d6d8ce03f9..a3d49d4cf07f 100644 --- a/test/core/test/sequential.test.ts +++ b/test/core/test/sequential.test.ts @@ -42,27 +42,16 @@ function assertConcurrent() { expect(++count).toBe(1) }) - test.sequential('third test completes third', async ({ task }) => { + test('third test completes third', { concurrent: false }, async ({ task }) => { await delay(50) expect(task.concurrent).toBeFalsy() expect(++count).toBe(3) }) - test.sequential('fourth test completes fourth', ({ task }) => { + test('fourth test completes fourth', { concurrent: false }, ({ task }) => { expect(task.concurrent).toBeFalsy() expect(++count).toBe(4) }) - - test('fifth test completes fifth', { concurrent: false }, async ({ task }) => { - await delay(50) - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(5) - }) - - test('sixth test completes sixth', { concurrent: false }, ({ task }) => { - expect(task.concurrent).toBeFalsy() - expect(++count).toBe(6) - }) } assertSequential() @@ -72,14 +61,6 @@ describe.concurrent('describe.concurrent', () => { describe('describe', assertConcurrent) - describe.sequential('describe.sequential', () => { - assertSequential() - - describe('describe', assertSequential) - - describe.concurrent('describe.concurrent', assertConcurrent) - }) - describe('describe concurrent false', { concurrent: false }, () => { assertSequential() From df7272d0c9a7c7c7c9513be0a3d48b1968415d12 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 12:20:39 +0900 Subject: [PATCH 5/9] test: this is a bug --- test/cli/test/test-tags.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cli/test/test-tags.test.ts b/test/cli/test/test-tags.test.ts index a22ebb04e0a8..9567cb36d2f1 100644 --- a/test/cli/test/test-tags.test.ts +++ b/test/cli/test/test-tags.test.ts @@ -654,6 +654,7 @@ test('concurrent false tag option opts out of sequence.concurrent', async () => { "basic.test.js": { "test 1": { + "concurrent": true, "mode": "run", "tags": [ "non-concurrent-tag", @@ -661,6 +662,7 @@ test('concurrent false tag option opts out of sequence.concurrent', async () => "timeout": 5000, }, "test 2": { + "concurrent": true, "mode": "run", "tags": [ "non-concurrent-tag", From 3d684fe5910ff05c1178b987315b9f26dc2a878a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 26 Apr 2026 12:51:07 +0900 Subject: [PATCH 6/9] breaking: remove sequential test API Co-authored-by: Codex --- packages/runner/src/suite.ts | 34 ++++++++---------------------- packages/runner/src/types/tasks.ts | 11 ++-------- 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index cfc033157625..9cae53b0d71c 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -390,10 +390,7 @@ function createSuiteCollector( if (task.mode === 'run' && !handler) { task.mode = 'todo' } - if ( - options.concurrent - ?? (!options.sequential && runner.config.sequence.concurrent) - ) { + if (options.concurrent ?? runner.config.sequence.concurrent) { task.concurrent = true } task.shuffle = suiteOptions?.shuffle @@ -450,17 +447,12 @@ function createSuiteCollector( options = Object.assign({}, suiteOptions, options) } - // inherit concurrent / sequential from suite - const concurrent = this.concurrent ?? (!this.sequential && options?.concurrent) + // inherit concurrent from suite + const concurrent = this.concurrent ?? options?.concurrent if (options.concurrent != null && concurrent != null) { options.concurrent = concurrent } - const sequential = this.sequential ?? (!this.concurrent && options?.sequential) - if (options.sequential != null && sequential != null) { - options.sequential = sequential - } - const test = task(formatName(name), { ...this, ...options, @@ -602,8 +594,7 @@ function createSuite() { optionsOrFactory, ) as { options: SuiteOptions; handler: SuiteFactory | undefined } - const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false - const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false + const concurrent = this.concurrent ?? options.concurrent const { meta: parentMeta, ...parentOptions } = currentSuite?.options || {} // inherit options from current suite @@ -611,6 +602,9 @@ function createSuite() { ...parentOptions, ...options, } + if (concurrent != null) { + options.concurrent = concurrent + } const shuffle = this.shuffle ?? options.shuffle ?? currentSuite?.options?.shuffle ?? runner?.config.sequence.shuffle if (shuffle != null) { @@ -630,16 +624,6 @@ function createSuite() { mode = 'todo' } - // inherit concurrent / sequential from suite - const isConcurrent = isConcurrentSpecified || (options.concurrent && !isSequentialSpecified) - const isSequential = isSequentialSpecified || (options.sequential && !isConcurrentSpecified) - if (isConcurrent != null) { - options.concurrent = isConcurrent && !isSequential - } - if (isSequential != null) { - options.sequential = isSequential && !isConcurrent - } - if (parentMeta) { options.meta = Object.assign(Object.create(null), parentMeta, options.meta) } @@ -737,7 +721,7 @@ function createSuite() { (condition ? suite : suite.skip) as SuiteAPI return createChainable( - ['concurrent', 'sequential', 'shuffle', 'skip', 'only', 'todo'], + ['concurrent', 'shuffle', 'skip', 'only', 'todo'], suiteFn, ) as unknown as SuiteAPI } @@ -968,7 +952,7 @@ export function createTaskCollector( taskFn.aroundAll = aroundAll const _test = createChainable( - ['concurrent', 'sequential', 'skip', 'only', 'todo', 'fails'], + ['concurrent', 'skip', 'only', 'todo', 'fails'], taskFn, { fixtures: new TestFixtures() }, ) as TestAPI diff --git a/packages/runner/src/types/tasks.ts b/packages/runner/src/types/tasks.ts index d2931ea7b995..35ee6d841bcb 100644 --- a/packages/runner/src/types/tasks.ts +++ b/packages/runner/src/types/tasks.ts @@ -467,7 +467,7 @@ export interface InternalChainableContext { type ChainableTestContextMap = Pick< Required, - 'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'fails' + 'concurrent' | 'only' | 'skip' | 'todo' | 'fails' > type ChainableTestAPI = TypedChainableFunction< @@ -557,13 +557,6 @@ export interface TestOptions { * Tests inherit `concurrent` from `describe()` and nested `describe()` will inherit from parent's `concurrent`. */ concurrent?: boolean - /** - * Whether tests run sequentially. - * Tests inherit `sequential` from `describe()` and nested `describe()` will inherit from parent's `sequential`. - * - * @deprecated Use `concurrent: false` instead. - */ - sequential?: boolean /** * Whether the test should be skipped. */ @@ -1074,7 +1067,7 @@ interface SuiteCollectorCallable { type ChainableSuiteContextMap = Pick< Required, - 'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'shuffle' + 'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle' > type ChainableSuiteAPI = TypedChainableFunction< From 5e020b3cdb91c1882be1b3b091c674cdd61fbb32 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 27 Apr 2026 09:55:49 +0900 Subject: [PATCH 7/9] deslop --- packages/runner/src/suite.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 9cae53b0d71c..031eea7db5ae 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -447,9 +447,8 @@ function createSuiteCollector( options = Object.assign({}, suiteOptions, options) } - // inherit concurrent from suite const concurrent = this.concurrent ?? options?.concurrent - if (options.concurrent != null && concurrent != null) { + if (concurrent != null) { options.concurrent = concurrent } @@ -594,7 +593,6 @@ function createSuite() { optionsOrFactory, ) as { options: SuiteOptions; handler: SuiteFactory | undefined } - const concurrent = this.concurrent ?? options.concurrent const { meta: parentMeta, ...parentOptions } = currentSuite?.options || {} // inherit options from current suite @@ -602,9 +600,6 @@ function createSuite() { ...parentOptions, ...options, } - if (concurrent != null) { - options.concurrent = concurrent - } const shuffle = this.shuffle ?? options.shuffle ?? currentSuite?.options?.shuffle ?? runner?.config.sequence.shuffle if (shuffle != null) { @@ -624,6 +619,11 @@ function createSuite() { mode = 'todo' } + const concurrent = this.concurrent ?? options.concurrent + if (concurrent != null) { + options.concurrent = concurrent + } + if (parentMeta) { options.meta = Object.assign(Object.create(null), parentMeta, options.meta) } From 56cc71e47c12247b05221f3d57d631702df8a08a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 27 Apr 2026 10:00:14 +0900 Subject: [PATCH 8/9] deslop --- test/config/test/sequence-concurrent.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/config/test/sequence-concurrent.test.ts b/test/config/test/sequence-concurrent.test.ts index a59a8a0564f8..40505c68fc5e 100644 --- a/test/config/test/sequence-concurrent.test.ts +++ b/test/config/test/sequence-concurrent.test.ts @@ -5,10 +5,7 @@ import { runVitest } from '../../test-utils' test('should run suites and tests concurrently unless concurrent false is specified when sequence.concurrent is true', async () => { const { stderr, errorTree } = await runVitest({ root: './fixtures/sequence-concurrent', - include: [ - 'sequence-concurrent-true-concurrent.test.ts', - 'sequence-concurrent-true-concurrent-false.test.ts', - ], + include: ['sequence-concurrent-true-*.test.ts'], sequence: { concurrent: true, }, From 621d04722780efd6fe8c56c3ba0af4c0138de937 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 27 Apr 2026 10:11:39 +0900 Subject: [PATCH 9/9] chore: lint --- packages/runner/src/suite.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 031eea7db5ae..52ef60388172 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -593,7 +593,6 @@ function createSuite() { optionsOrFactory, ) as { options: SuiteOptions; handler: SuiteFactory | undefined } - const { meta: parentMeta, ...parentOptions } = currentSuite?.options || {} // inherit options from current suite options = {