Last active
January 28, 2026 11:02
-
-
Save mdubourg001/982493993ce6cbefd061772450dfeb8c to your computer and use it in GitHub Desktop.
Vitest tests file execution order reporter (for tests dependencies and shared-state identification)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| SerializedError, | |
| TestModule, | |
| TestRunEndReason, | |
| TestSpecification, | |
| } from 'vitest/node'; | |
| import { Reporter } from 'vitest/reporters'; | |
| interface TestFilesOrderReporterConfig {} | |
| const DEFAULT_CONFIG: TestFilesOrderReporterConfig = {}; | |
| /** | |
| * This reporter helps identify test files order dependencies by reporting the order in which test files are executed. | |
| * It also provides guidance on how to bisect the test files to identify potential order dependencies. | |
| */ | |
| export class TestFilesOrderReporter implements Reporter { | |
| private config: TestFilesOrderReporterConfig; | |
| private seed: number | undefined = undefined; | |
| constructor(config: TestFilesOrderReporterConfig = DEFAULT_CONFIG) { | |
| this.config = config; | |
| } | |
| onInit(): void { | |
| console.log( | |
| `This reporter helps identify test files order dependencies by reporting the order in which test files are executed, and helping you bisecting the files that cause the failure. | |
| For predictible results, make sure to run this reporter with the following options: | |
| - --isolate=false | |
| - --sequence.shuffle.files | |
| - --fileParallelism=false | |
| - --bail=1\n`, | |
| ); | |
| } | |
| onTestRunStart(specifications: readonly TestSpecification[]) { | |
| this.seed = specifications[0]?.project.globalConfig.sequence.seed; | |
| if (this.seed) { | |
| console.log(`Running tests with seed "${this.seed}"\n\n`); | |
| } | |
| } | |
| onTestRunEnd( | |
| testModules: ReadonlyArray<TestModule>, | |
| unhandledErrors: ReadonlyArray<SerializedError>, | |
| reason: TestRunEndReason, | |
| ): void { | |
| const modulesOrder = testModules | |
| .filter((module) => module.task!.result.state !== 'skip') | |
| .map((module) => module.relativeModuleId); | |
| console.log( | |
| `SEED: ${this.seed}\n${reason !== 'passed' ? `FAILING: ${modulesOrder.at(-1)}\n` : ''} | |
| Test files execution order, (excluding skipped):`, | |
| ); | |
| console.log(modulesOrder); | |
| if (reason !== 'passed') { | |
| const failingModule = modulesOrder.at(-1); | |
| const firstHalf = modulesOrder.slice( | |
| 0, | |
| Math.floor(modulesOrder.length / 2), | |
| ); | |
| const secondHalf = modulesOrder.slice( | |
| Math.floor(modulesOrder.length / 2), | |
| ); | |
| const firstHalfMessage = | |
| firstHalf.length === 1 | |
| ? `\nYour potentially order-dependent test file is likely to be: ${firstHalf[0]} ${failingModule}. | |
| You should now investigate what state is being shared between these two test files and causes state pollution. Good luck!` | |
| : `\nTo bisect first half:\n | |
| for i in {1..10}; do pnpm test --isolate=false --sequence.shuffle.files --fileParallelism=false --bail=1 ${firstHalf.join( | |
| ' ', | |
| )} ${failingModule} || break; done`; | |
| const secondHalfMessage = | |
| secondHalf.length < 2 | |
| ? '' | |
| : `\nTo bisect second half:\n | |
| for i in {1..10}; do pnpm test --isolate=false --sequence.shuffle.files --fileParallelism=false --bail=1 ${secondHalf.join( | |
| ' ', | |
| )} || break; done`; | |
| console.log(`${firstHalfMessage}\n${secondHalfMessage}`); | |
| } else { | |
| console.log( | |
| `\nNo failing test. Try rerunning.`, | |
| ); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { defineConfig } from 'vitest/config'; | |
| import { TestFilesOrderReporter } from './test-files-order-reporter'; | |
| export default defineConfig({ | |
| // ... | |
| test: { | |
| globals: true, | |
| // ... | |
| reporters: [new TestFilesOrderReporter()], | |
| } | |
| }); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example of usage: