[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.

docs: explain globalSetup/setupFiles and add Lifecyle page (#9385)

authored by

Vladimir and committed by
GitHub
(Jan 8, 2026, 1:34 PM +0100) 5ec44b73 fb50d337

+374 -34
+6 -2
docs/.vitepress/config.ts
··· 731 731 link: '/guide/environment', 732 732 }, 733 733 { 734 + text: 'Test Run Lifecycle', 735 + link: '/guide/lifecycle', 736 + }, 737 + { 734 738 text: 'Snapshot', 735 739 link: '/guide/snapshot', 736 740 }, ··· 858 862 }, 859 863 { 860 864 text: 'Advanced', 861 - collapsed: true, 865 + collapsed: false, 862 866 items: [ 863 867 { 864 868 text: 'Getting Started', ··· 947 951 }, 948 952 { 949 953 text: 'Advanced', 950 - collapsed: true, 954 + collapsed: false, 951 955 items: [ 952 956 { 953 957 text: 'Vitest',
+32 -22
docs/config/globalsetup.md
··· 7 7 8 8 - **Type:** `string | string[]` 9 9 10 - Path to global setup files, relative to project root. 10 + Path to global setup files relative to project [root](/config/root). 11 11 12 - A global setup file can either export named functions `setup` and `teardown` or a `default` function that returns a teardown function ([example](https://github.com/vitest-dev/vitest/blob/main/test/global-setup/vitest.config.ts)). 12 + A global setup file can either export named functions `setup` and `teardown` or a `default` function that returns a teardown function: 13 13 14 - ::: info 15 - Multiple globalSetup files are possible. setup and teardown are executed sequentially with teardown in reverse order. 14 + ::: code-group 15 + ```js [exports] 16 + export function setup(project) { 17 + console.log('setup') 18 + } 19 + 20 + export function teardown() { 21 + console.log('teardown') 22 + } 23 + ``` 24 + ```js [default] 25 + export default function setup(project) { 26 + console.log('setup') 27 + 28 + return function teardown() { 29 + console.log('teardown') 30 + } 31 + } 32 + ``` 16 33 ::: 17 34 18 - ::: warning 19 - Global setup runs only if there is at least one running test. This means that global setup might start running during watch mode after test file is changed (the test file will wait for global setup to finish before running). 35 + Note that the `setup` method and a `default` function receive a [test project](/api/advanced/test-project) as the first argument. The global setup is called before the test workers are created and only if there is at least one test queued, and teardown is called after all test files have finished running. In [watch mode](/config/watch), the teardown is called before the process is exited instead. If you need to reconfigure your setup before the test rerun, you can use [`onTestsRerun`](#handling-test-reruns) hook instead. 20 36 21 - Beware that the global setup is running in a different global scope, so your tests don't have access to variables defined here. However, you can pass down serializable data to tests via [`provide`](#provide) method: 37 + Multiple global setup files are possible. `setup` and `teardown` are executed sequentially with teardown in reverse order. 38 + 39 + ::: danger 40 + Beware that the global setup is running in a different global scope before test workers are even created, so your tests don't have access to global variables defined here. However, you can pass down serializable data to tests via [`provide`](/config/provide) method and read them in your tests via `inject` imported from `vitest`: 22 41 23 42 :::code-group 24 - ```ts [example.test.js] 43 + ```ts [example.test.ts] 25 44 import { inject } from 'vitest' 26 45 27 46 inject('wsPort') === 3000 28 47 ``` 29 - ```ts [globalSetup.ts <Version>3.0.0</Version>] 48 + ```ts [globalSetup.ts] 30 49 import type { TestProject } from 'vitest/node' 31 50 32 51 export default function setup(project: TestProject) { ··· 39 58 } 40 59 } 41 60 ``` 42 - ```ts [globalSetup.ts <Version>2.0.0</Version>] 43 - import type { GlobalSetupContext } from 'vitest/node' 44 61 45 - export default function setup({ provide }: GlobalSetupContext) { 46 - provide('wsPort', 3000) 47 - } 48 - 49 - declare module 'vitest' { 50 - export interface ProvidedContext { 51 - wsPort: number 52 - } 53 - } 54 - ``` 62 + If you need to execute code in the same process as tests, use [`setupFiles`](/config/setupfiles) instead, but note that it runs before every test file. 55 63 ::: 56 64 57 - Since Vitest 3, you can define a custom callback function to be called when Vitest reruns tests. If the function is asynchronous, the runner will wait for it to complete before executing tests. Note that you cannot destruct the `project` like `{ onTestsRerun }` because it relies on the context. 65 + ### Handling Test Reruns 66 + 67 + You can define a custom callback function to be called when Vitest reruns tests. The test runner will wait for it to complete before executing tests. Note that you cannot destruct the `project` like `{ onTestsRerun }` because it relies on the context. 58 68 59 69 ```ts [globalSetup.ts] 60 70 import type { TestProject } from 'vitest/node'
+2 -2
docs/config/sequence.md
··· 26 26 27 27 If [`sequencer.groupOrder`](#grouporder) is specified, the sequencer will be called once for each group and pool. 28 28 29 - ## groupOrder 29 + ## sequence.groupOrder 30 30 31 31 - **Type:** `number` 32 32 - **Default:** `0` ··· 97 97 98 98 If you want files and tests to run randomly, you can enable it with this option, or CLI argument [`--sequence.shuffle`](/guide/cli). 99 99 100 - Vitest usually uses cache to sort tests, so long running tests start earlier - this makes tests run faster. If your files and tests will run in random order you will lose this performance improvement, but it may be useful to track tests that accidentally depend on another run previously. 100 + Vitest usually uses cache to sort tests, so long-running tests start earlier, which makes tests run faster. If your files and tests run in random order, you will lose this performance improvement, but it may be useful to track tests that accidentally depend on another test run previously. 101 101 102 102 ### sequence.shuffle.files {#sequence-shuffle-files} 103 103
+14 -8
docs/config/setupfiles.md
··· 7 7 8 8 - **Type:** `string | string[]` 9 9 10 - Path to setup files. They will be run before each test file. 10 + Paths to setup files resolved relative to the [`root`](/config/root). They will run before each _test file_ in the same process. By default, all test files run in parallel, but you can configure it with [`sequence.setupFiles`](/config/sequence#sequence-setupfiles) option. 11 + 12 + Vitest will ignore any exports from these files. 13 + 14 + :::warning 15 + Note that setup files are executed in the same process as tests, unlike [`globalSetup`](/config/globalsetup) that runs once in the main thread before any test worker is created. 16 + ::: 11 17 12 18 :::info 13 19 Editing a setup file will automatically trigger a rerun of all tests. 14 20 ::: 15 21 16 - You can use `process.env.VITEST_POOL_ID` (integer-like string) inside to distinguish between workers. 22 + If you have a heavy process running in the background, you can use `process.env.VITEST_POOL_ID` (integer-like string) inside to distinguish between workers and spread the workload. 17 23 18 - :::tip 19 - Note, that if you are running [`--isolate=false`](#isolate), this setup file will be run in the same global scope multiple times. Meaning, that you are accessing the same global object before each test, so make sure you are not doing the same thing more than you need. 20 - ::: 24 + :::warning 25 + If [isolation](/config/isolate) is disabled, imported modules are cached, but the setup file itself is executed again before each test file, meaning that you are accessing the same global object before each test file. Make sure you are not doing the same thing more than necessary. 21 26 22 27 For example, you may rely on a global variable: 23 28 24 29 ```ts 25 30 import { config } from '@some-testing-lib' 26 31 27 - if (!globalThis.defined) { 32 + if (!globalThis.setupInitialized) { 28 33 config.plugins = [myCoolPlugin] 29 34 computeHeavyThing() 30 - globalThis.defined = true 35 + globalThis.setupInitialized = true 31 36 } 32 37 33 - // hooks are reset before each suite 38 + // hooks reset before each test file 34 39 afterEach(() => { 35 40 cleanup() 36 41 }) 37 42 38 43 globalThis.resetBeforeEachTest = true 39 44 ``` 45 + :::
+320
docs/guide/lifecycle.md
··· 1 + --- 2 + title: Test Run Lifecycle | Guide 3 + outline: deep 4 + --- 5 + 6 + # Test Run Lifecycle 7 + 8 + Understanding the test run lifecycle is essential for writing effective tests, debugging issues, and optimizing your test suite. This guide explains when and in what order different lifecycle phases occur in Vitest, from initialization to teardown. 9 + 10 + ## Overview 11 + 12 + A typical Vitest test run goes through these main phases: 13 + 14 + 1. **Initialization** - Configuration loading and project setup 15 + 2. **Global Setup** - One-time setup before any tests run 16 + 3. **Worker Creation** - Test workers are spawned based on the [pool](/config/pool) configuration 17 + 4. **Test File Collection** - Test files are discovered and organized 18 + 5. **Test Execution** - Tests run with their hooks and assertions 19 + 6. **Reporting** - Results are collected and reported 20 + 7. **Global Teardown** - Final cleanup after all tests complete 21 + 22 + Phases 4–6 run once for each test file, so across your test suite they will execute multiple times and may also run in parallel across different files when you use more than [1 worker](/config/maxworkers). 23 + 24 + ## Detailed Lifecycle Phases 25 + 26 + ### 1. Initialization Phase 27 + 28 + When you run `vitest`, the framework first loads your configuration and prepares the test environment. 29 + 30 + **What happens:** 31 + - [Command-line](/guide/cli) arguments are parsed 32 + - [Configuration file](/config/) is loaded 33 + - Project structure is validated 34 + 35 + This phase can run again if the config file or one of its imports changes. 36 + 37 + **Scope:** Main process (before any test workers are created) 38 + 39 + ### 2. Global Setup Phase 40 + 41 + If you have configured [`globalSetup`](/config/globalsetup) files, they run once before any test workers are created. 42 + 43 + **What happens:** 44 + - `setup()` functions (or exported `default` function) from global setup files execute sequentially 45 + - Multiple global setup files run in the order they are defined 46 + 47 + **Scope:** Main process (separate from test workers) 48 + 49 + **Important notes:** 50 + - Global setup runs in a **different global scope** from your tests 51 + - Tests cannot access variables defined in global setup (use [`provide`/`inject`](/config/provide) instead) 52 + - Global setup only runs if there is at least one test queued 53 + 54 + ```ts [globalSetup.ts] 55 + export function setup(project) { 56 + // Runs once before all tests 57 + console.log('Global setup') 58 + 59 + // Share data with tests 60 + project.provide('apiUrl', 'http://localhost:3000') 61 + } 62 + 63 + export function teardown() { 64 + // Runs once after all tests 65 + console.log('Global teardown') 66 + } 67 + ``` 68 + 69 + ### 3. Worker Creation Phase 70 + 71 + After global setup completes, Vitest creates test workers based on your [pool configuration](/config/pool). 72 + 73 + **What happens:** 74 + - Workers are spawned according to the `browser.enabled` or `pool` setting (`threads`, `forks`, `vmThreads`, or `vmForks`) 75 + - Each worker gets its own isolated environment (unless [isolation](/config/isolate) is disabled) 76 + - By default, workers are not reused to provide isolation. Workers are reused only if: 77 + - [isolation](/config/isolate) is disabled 78 + - OR pool is `vmThreads` or `vmForks` because [VM](https://nodejs.org/api/vm.html) provides enough isolation 79 + 80 + **Scope:** Worker processes/threads 81 + 82 + ### 4. Test File Setup Phase 83 + 84 + Before each test file runs, [setup files](/config/setupfiles) are executed. 85 + 86 + **What happens:** 87 + - Setup files run in the same process as your tests 88 + - By default, setup files run in **parallel** (configurable via [`sequence.setupFiles`](/config/sequence#sequence-setupfiles)) 89 + - Setup files execute before **each test file** 90 + - Any global _state_ or configuration can be initialized here 91 + 92 + **Scope:** Worker process (same as your tests) 93 + 94 + **Important notes:** 95 + - If [isolation](/config/isolate) is disabled, setup files still rerun before each test file to trigger side effects, but imported modules are cached 96 + - Editing a setup file triggers a rerun of all tests in watch mode 97 + 98 + ```ts [setupFile.ts] 99 + import { afterEach } from 'vitest' 100 + 101 + // Runs before each test file 102 + console.log('Setup file executing') 103 + 104 + // Register hooks that apply to all tests 105 + afterEach(() => { 106 + cleanup() 107 + }) 108 + ``` 109 + 110 + ### 5. Test Collection and Execution Phase 111 + 112 + This is the main phase where your tests actually run. 113 + 114 + #### Test File Execution Order 115 + 116 + Test files are executed based on your configuration: 117 + 118 + - **Sequential by default** within a worker 119 + - Files will run in **parallel** across different workers, configured by [`maxWorkers`](/config/maxworkers) 120 + - Order can be randomized with [`sequence.shuffle`](/config/sequence#sequence-shuffle) or fine-tuned with [`sequence.sequencer`](/config/sequence#sequence-sequencer) 121 + - Long-running tests typically start earlier (based on cache) unless shuffle is enabled 122 + 123 + #### Within Each Test File 124 + 125 + The execution follows this order: 126 + 127 + 1. **File-level code** - All code outside `describe` blocks runs immediately 128 + 2. **Test collection** - `describe` blocks are processed, and tests are registered as side effects of importing the test file 129 + 3. **`beforeAll` hooks** - Run once before any tests in the suite 130 + 4. **For each test:** 131 + - `beforeEach` hooks execute (in order defined, or based on [`sequence.hooks`](/config/sequence#sequence-hooks)) 132 + - Test function executes 133 + - `afterEach` hooks execute (reverse order by default with `sequence.hooks: 'stack'`) 134 + - [`onTestFinished`](/api/#ontestfinished) callbacks run (always in reverse order) 135 + - If test failed: [`onTestFailed`](/api/#ontestfailed) callbacks run 136 + - Note: if `repeats` or `retry` are set, all of these steps are executed again 137 + 5. **`afterAll` hooks** - Run once after all tests in the suite complete 138 + 139 + **Example execution flow:** 140 + 141 + ```ts 142 + // This runs immediately (collection phase) 143 + console.log('File loaded') 144 + 145 + describe('User API', () => { 146 + // This runs immediately (collection phase) 147 + console.log('Suite defined') 148 + 149 + beforeAll(() => { 150 + // Runs once before all tests in this suite 151 + console.log('beforeAll') 152 + }) 153 + 154 + beforeEach(() => { 155 + // Runs before each test 156 + console.log('beforeEach') 157 + }) 158 + 159 + test('creates user', () => { 160 + // Test executes 161 + console.log('test 1') 162 + }) 163 + 164 + test('updates user', () => { 165 + // Test executes 166 + console.log('test 2') 167 + }) 168 + 169 + afterEach(() => { 170 + // Runs after each test 171 + console.log('afterEach') 172 + }) 173 + 174 + afterAll(() => { 175 + // Runs once after all tests in this suite 176 + console.log('afterAll') 177 + }) 178 + }) 179 + 180 + // Output: 181 + // File loaded 182 + // Suite defined 183 + // beforeAll 184 + // beforeEach 185 + // test 1 186 + // afterEach 187 + // beforeEach 188 + // test 2 189 + // afterEach 190 + // afterAll 191 + ``` 192 + 193 + #### Nested Suites 194 + 195 + When using nested `describe` blocks, hooks follow a hierarchical pattern: 196 + 197 + ```ts 198 + describe('outer', () => { 199 + beforeAll(() => console.log('outer beforeAll')) 200 + beforeEach(() => console.log('outer beforeEach')) 201 + 202 + test('outer test', () => console.log('outer test')) 203 + 204 + describe('inner', () => { 205 + beforeAll(() => console.log('inner beforeAll')) 206 + beforeEach(() => console.log('inner beforeEach')) 207 + 208 + test('inner test', () => console.log('inner test')) 209 + 210 + afterEach(() => console.log('inner afterEach')) 211 + afterAll(() => console.log('inner afterAll')) 212 + }) 213 + 214 + afterEach(() => console.log('outer afterEach')) 215 + afterAll(() => console.log('outer afterAll')) 216 + }) 217 + 218 + // Output: 219 + // outer beforeAll 220 + // outer beforeEach 221 + // outer test 222 + // outer afterEach 223 + // inner beforeAll 224 + // outer beforeEach 225 + // inner beforeEach 226 + // inner test 227 + // inner afterEach (with stack mode) 228 + // outer afterEach (with stack mode) 229 + // inner afterAll 230 + // outer afterAll 231 + ``` 232 + 233 + #### Concurrent Tests 234 + 235 + When using `test.concurrent` or [`sequence.concurrent`](/config/sequence#sequence-concurrent): 236 + 237 + - Tests within the same file can run in parallel 238 + - Each concurrent test still runs its own `beforeEach` and `afterEach` hooks 239 + - Use [test context](/guide/test-context) for concurrent snapshots: `test.concurrent('name', async ({ expect }) => {})` 240 + 241 + ### 6. Reporting Phase 242 + 243 + Throughout the test run, reporters receive lifecycle events and display results. 244 + 245 + **What happens:** 246 + - Reporters receive events as tests progress 247 + - Results are collected and formatted 248 + - Test summaries are generated 249 + - Coverage reports are generated (if enabled) 250 + 251 + For detailed information about the reporter lifecycle, see the [Reporters](/api/advanced/reporters) guide. 252 + 253 + ### 7. Global Teardown Phase 254 + 255 + After all tests complete, global teardown functions execute. 256 + 257 + **What happens:** 258 + - `teardown()` functions from [`globalSetup`](/config/globalsetup) files run 259 + - Multiple teardown functions run in **reverse order** of their setup 260 + - In watch mode, teardown runs before process exit, not between test reruns 261 + 262 + **Scope:** Main process 263 + 264 + ```ts [globalSetup.ts] 265 + export function teardown() { 266 + // Clean up global resources 267 + console.log('Global teardown complete') 268 + } 269 + ``` 270 + 271 + ## Lifecycle in Different Scopes 272 + 273 + Understanding where code executes is crucial for avoiding common pitfalls: 274 + 275 + | Phase | Scope | Access to Test Context | Runs | 276 + |-------|-------|----------------------|------| 277 + | Config File | Main process | ❌ No | Once per Vitest run | 278 + | Global Setup | Main process | ❌ No (use `provide`/`inject`) | Once per Vitest run | 279 + | Setup Files | Worker (same as tests) | ✅ Yes | Before each test file | 280 + | File-level code | Worker | ✅ Yes | Once per test file | 281 + | `beforeAll` / `afterAll` | Worker | ✅ Yes | Once per suite | 282 + | `beforeEach` / `afterEach` | Worker | ✅ Yes | Per test | 283 + | Test function | Worker | ✅ Yes | Once (or more with retries/repeats) | 284 + | Global Teardown | Main process | ❌ No | Once per Vitest run | 285 + 286 + ## Watch Mode Lifecycle 287 + 288 + In watch mode, the lifecycle repeats with some differences: 289 + 290 + 1. **Initial run** - Full lifecycle as described above 291 + 2. **On file change:** 292 + - New [test run](/api/advanced/reporters#ontestrunstart) starts 293 + - Only affected test files are re-run 294 + - [Setup files](/config/setupfiles) run again for those test files 295 + - [Global setup](/config/globalsetup) does **not** re-run (use [`project.onTestsRerun`](/config/globalsetup#handling-test-reruns) for rerun-specific logic) 296 + 3. **On exit:** 297 + - Global teardown executes 298 + - Process terminates 299 + 300 + ## Performance Considerations 301 + 302 + Understanding the lifecycle helps optimize test performance: 303 + 304 + - **Global setup** is ideal for expensive one-time operations (database seeding, server startup) 305 + - **Setup files** run before each test file - avoid heavy operations here if you have many test files 306 + - **`beforeAll`** is better than `beforeEach` for expensive setup that doesn't need isolation 307 + - **Disabling [isolation](/config/isolate)** improves performance, but setup files still execute before each file 308 + - **[Pool configuration](/config/pool)** affects parallelization and available APIs 309 + 310 + For tips on how to improve performance, read the [Improving Performance](/guide/improving-performance) guide. 311 + 312 + ## Related Documentation 313 + 314 + - [Global Setup Configuration](/config/globalsetup) 315 + - [Setup Files Configuration](/config/setupfiles) 316 + - [Test Sequencing Options](/config/sequence) 317 + - [Isolation Configuration](/config/isolate) 318 + - [Pool Configuration](/config/pool) 319 + - [Extending Reporters](/guide/advanced/reporters) - for reporter lifecycle events 320 + - [Test API Reference](/api/) - for hook APIs and test functions