[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

feat(runner)!: support `describe(..., { shuffle: boolean })` and inherit from parent suite (#6670)

authored by

Hiroshi Ogawa and committed by
GitHub
(Dec 5, 2024, 4:03 PM +0100) aa1dac3d e3144fd8

+119 -25
+13
docs/api/index.md
··· 906 906 ```ts 907 907 import { describe, test } from 'vitest' 908 908 909 + // or describe('suite', { shuffle: true }, ...) 909 910 describe.shuffle('suite', () => { 910 911 test('random test 1', async () => { /* ... */ }) 911 912 test('random test 2', async () => { /* ... */ }) 912 913 test('random test 3', async () => { /* ... */ }) 914 + 915 + // `shuffle` is inherited 916 + describe('still random', () => { 917 + test('random 4.1', async () => { /* ... */ }) 918 + test('random 4.2', async () => { /* ... */ }) 919 + }) 920 + 921 + // disable shuffle inside 922 + describe('not random', { shuffle: false }, () => { 923 + test('in order 5.1', async () => { /* ... */ }) 924 + test('in order 5.2', async () => { /* ... */ }) 925 + }) 913 926 }) 914 927 // order depends on sequence.seed option in config (Date.now() by default) 915 928 ```
+1
packages/runner/src/collect.ts
··· 32 32 const testLocations = typeof spec === 'string' ? undefined : spec.testLocations 33 33 34 34 const file = createFileTask(filepath, config.root, config.name, runner.pool) 35 + file.shuffle = config.sequence.shuffle 35 36 36 37 runner.onCollectStart?.(file) 37 38
+1 -1
packages/runner/src/run.ts
··· 412 412 } 413 413 else { 414 414 const { sequence } = runner.config 415 - if (sequence.shuffle || suite.shuffle) { 415 + if (suite.shuffle) { 416 416 // run describe block independently from tests 417 417 const suites = tasksGroup.filter( 418 418 group => group.type === 'suite',
+7 -10
packages/runner/src/suite.ts
··· 207 207 208 208 function createDefaultSuite(runner: VitestRunner) { 209 209 const config = runner.config.sequence 210 - const api = config.shuffle ? suite.shuffle : suite 211 - return api('', { concurrent: config.concurrent }, () => {}) 210 + return suite('', { concurrent: config.concurrent }, () => {}) 212 211 } 213 212 214 213 export function clearCollectorContext( ··· 292 291 name: string, 293 292 factory: SuiteFactory = () => {}, 294 293 mode: RunMode, 295 - shuffle?: boolean, 296 294 each?: boolean, 297 295 suiteOptions?: TestOptions, 298 296 ) { ··· 331 329 ) { 332 330 task.concurrent = true 333 331 } 334 - if (shuffle) { 335 - task.shuffle = true 336 - } 332 + task.shuffle = suiteOptions?.shuffle 337 333 338 334 const context = createTestContext(task, runner) 339 335 // create test context ··· 425 421 mode, 426 422 each, 427 423 file: undefined!, 428 - shuffle, 424 + shuffle: suiteOptions?.shuffle, 429 425 tasks: [], 430 426 meta: Object.create(null), 431 427 concurrent: suiteOptions?.concurrent, ··· 523 519 const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false 524 520 525 521 // inherit options from current suite 526 - if (currentSuite?.options) { 527 - options = { ...currentSuite.options, ...options } 522 + options = { 523 + ...currentSuite?.options, 524 + ...options, 525 + shuffle: this.shuffle ?? options.shuffle ?? currentSuite?.options?.shuffle ?? runner?.config.sequence.shuffle, 528 526 } 529 527 530 528 // inherit concurrent / sequential from suite ··· 537 535 formatName(name), 538 536 factory, 539 537 mode, 540 - this.shuffle, 541 538 this.each, 542 539 options, 543 540 )
+15
test/config/test/shuffle-options.test.ts
··· 47 47 const { ctx } = await run({ shuffle, sequencer: CustomSequencer }) 48 48 expect(ctx?.config.sequence.sequencer.name).toBe('CustomSequencer') 49 49 }) 50 + 51 + test('shuffle', async () => { 52 + const { stderr, ctx } = await runVitest({ 53 + root: './fixtures/shuffle', 54 + }) 55 + expect(stderr).toBe('') 56 + expect(ctx?.state.getFiles().map(f => [f.name, f.result?.state])).toMatchInlineSnapshot(` 57 + [ 58 + [ 59 + "basic.test.ts", 60 + "pass", 61 + ], 62 + ] 63 + `) 64 + })
+32 -7
test/core/test/random.test.ts
··· 1 - import { afterAll, describe, expect, test } from 'vitest' 1 + import { describe, expect, test } from 'vitest' 2 2 3 3 // tests use seed of 101, so they have deterministic random order 4 4 const numbers: number[] = [] 5 5 6 6 describe.shuffle('random tests', () => { 7 - describe('inside', () => { 8 - // shuffle is not inherited from parent 9 - 7 + describe('suite unshuffle', { shuffle: false }, () => { 10 8 test('inside 1', () => { 11 9 numbers.push(1) 12 10 }) 11 + test('inside 1.5', () => { 12 + numbers.push(1.5) 13 + }) 13 14 test('inside 2', () => { 14 15 numbers.push(2) 16 + }) 17 + 18 + describe('suite shuffle', { shuffle: true }, () => { 19 + test('inside 2.1', () => { 20 + numbers.push(2.1) 21 + }) 22 + test('inside 2.2', () => { 23 + numbers.push(2.2) 24 + }) 25 + test('inside 2.3', () => { 26 + numbers.push(2.3) 27 + }) 15 28 }) 16 29 }) 17 30 ··· 24 37 test('test 3', () => { 25 38 numbers.push(5) 26 39 }) 40 + }) 27 41 28 - afterAll(() => { 29 - expect(numbers).toStrictEqual([4, 5, 3, 1, 2]) 30 - }) 42 + test('assert', () => { 43 + expect(numbers).toMatchInlineSnapshot(` 44 + [ 45 + 4, 46 + 5, 47 + 3, 48 + 1, 49 + 1.5, 50 + 2, 51 + 2.2, 52 + 2.3, 53 + 2.1, 54 + ] 55 + `) 31 56 })
+13 -7
packages/runner/src/types/tasks.ts
··· 286 286 ( 287 287 name: string | Function, 288 288 fn: (...args: T) => Awaitable<void>, 289 - options: TestOptions 289 + options: TestCollectorOptions 290 290 ): void 291 291 ( 292 292 name: string | Function, 293 293 fn: (...args: T) => Awaitable<void>, 294 - options?: number | TestOptions 294 + options?: number | TestCollectorOptions 295 295 ): void 296 296 ( 297 297 name: string | Function, 298 - options: TestOptions, 298 + options: TestCollectorOptions, 299 299 fn: (...args: T) => Awaitable<void> 300 300 ): void 301 301 } ··· 316 316 ): void 317 317 ( 318 318 name: string | Function, 319 - options: TestOptions, 319 + options: TestCollectorOptions, 320 320 fn: (args: Arg, context: Context) => Awaitable<void> 321 321 ): void 322 322 } ··· 347 347 <ExtraContext extends C>( 348 348 name: string | Function, 349 349 fn: TestFunction<ExtraContext>, 350 - options: TestOptions 350 + options: TestCollectorOptions 351 351 ): void 352 352 <ExtraContext extends C>( 353 353 name: string | Function, 354 354 fn?: TestFunction<ExtraContext>, 355 - options?: number | TestOptions 355 + options?: number | TestCollectorOptions 356 356 ): void 357 357 <ExtraContext extends C>( 358 358 name: string | Function, 359 - options?: TestOptions, 359 + options?: TestCollectorOptions, 360 360 fn?: TestFunction<ExtraContext> 361 361 ): void 362 362 } ··· 369 369 for: TestForFunction<ExtraContext> 370 370 } 371 371 > 372 + 373 + type TestCollectorOptions = Omit<TestOptions, 'shuffle'> 372 374 373 375 export interface TestOptions { 374 376 /** ··· 399 401 * Tests inherit `sequential` from `describe()` and nested `describe()` will inherit from parent's `sequential`. 400 402 */ 401 403 sequential?: boolean 404 + /** 405 + * Whether the tasks of the suite run in a random order. 406 + */ 407 + shuffle?: boolean 402 408 /** 403 409 * Whether the test should be skipped. 404 410 */
+27
test/config/fixtures/shuffle/basic.test.ts
··· 1 + import { afterAll, describe, expect, test } from 'vitest' 2 + 3 + const numbers: number[] = [] 4 + 5 + test.for([1, 2, 3, 4, 5])('test %s', (v) => { 6 + numbers.push(10 + v) 7 + }) 8 + 9 + describe("inherit shuffle", () => { 10 + test.for([1, 2, 3, 4, 5])('test %s', (v) => { 11 + numbers.push(20 + v) 12 + }) 13 + }) 14 + 15 + describe('unshuffle', { shuffle: false }, () => { 16 + test.for([1, 2, 3, 4, 5])('test %s', (v) => { 17 + numbers.push(30 + v) 18 + }) 19 + }) 20 + 21 + afterAll(() => { 22 + expect(numbers).toEqual([ 23 + 11, 14, 13, 15, 12, 24 + 31, 32, 33, 34, 35, 25 + 21, 24, 23, 25, 22 26 + ]) 27 + })
+10
test/config/fixtures/shuffle/vitest.config.ts
··· 1 + import { defineConfig } from 'vitest/config' 2 + 3 + export default defineConfig({ 4 + test: { 5 + sequence: { 6 + seed: 101, 7 + shuffle: true, 8 + } 9 + } 10 + })