diff --git a/docs/config/index.md b/docs/config/index.md index 9db22a946cdf..63d7a2e61150 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -586,7 +586,7 @@ By providing an object instead of a string you can define individual outputs whe ### pool 1.0.0+ {#pool} - **Type:** `'threads' | 'forks' | 'vmThreads' | 'vmForks'` -- **Default:** `'threads'` +- **Default:** `'forks'` (in v1 `'threads'`) - **CLI:** `--pool=threads` Pool used to run tests in. diff --git a/docs/guide/common-errors.md b/docs/guide/common-errors.md index 5831dbae0674..b0b5082d7f58 100644 --- a/docs/guide/common-errors.md +++ b/docs/guide/common-errors.md @@ -65,9 +65,8 @@ This error can happen when NodeJS's `fetch` is used with default [`pool: 'thread As work-around you can switch to [`pool: 'forks'`](/config/#forks) or [`pool: 'vmForks'`](/config/#vmforks). -Specify `pool` in your configuration file: - -```ts +::: code-group +```ts [vitest.config.js] import { defineConfig } from 'vitest/config' export default defineConfig({ @@ -76,12 +75,33 @@ export default defineConfig({ }, }) ``` +```bash [CLI] +vitest --pool=forks +``` +::: -Or in your `package.json` scripts: +## Segfaults and native code errors -```diff -scripts: { -- "test": "vitest" -+ "test": "vitest --pool=forks" -} +Running [native NodeJS modules](https://nodejs.org/api/addons.html) in `pool: 'threads'` can run into cryptic errors coming from the native code. + +- `Segmentation fault (core dumped)` +- `thread '' panicked at 'assertion failed` +- `Abort trap: 6` +- `internal error: entered unreachable code` + +In these cases the native module is likely not built to be multi-thread safe. As work-around, you can switch to `pool: 'forks'` which runs the test cases in multiple `node:child_process` instead of multiple `node:worker_threads`. + +::: code-group +```ts [vitest.config.js] +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + pool: 'forks', + }, +}) +``` +```bash [CLI] +vitest --pool=forks ``` +::: diff --git a/docs/guide/improving-performance.md b/docs/guide/improving-performance.md index 1ef6066ad4f0..71c6a0edba3e 100644 --- a/docs/guide/improving-performance.md +++ b/docs/guide/improving-performance.md @@ -1,5 +1,7 @@ # Improving Performance +## Test isolation + By default Vitest runs every test file in an isolated environment based on the [pool](/config/#pool): - `threads` pool runs every test file in a separate [`Worker`](https://nodejs.org/api/worker_threads.html#class-worker) @@ -49,3 +51,24 @@ export default defineConfig({ }) ``` ::: + +## Pool + +By default Vitest runs tests in `pool: 'forks'`. While `'forks'` pool is better for compatibility issues ([hanging process](/guide/common-errors.html#failed-to-terminate-worker) and [segfaults](/guide/common-errors.html#segfaults-and-native-code-errors)), it may be slightly slower than `pool: 'threads'` in larger projects. + +You can try to improve test run time by switching `pool` option in configuration: + +::: code-group +```bash [CLI] +vitest --pool=threads +``` +```ts [vitest.config.js] +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + pool: 'threads', + }, +}) +``` +::: diff --git a/packages/vitest/src/defaults.ts b/packages/vitest/src/defaults.ts index 560e6a977a96..1dee107a6c00 100644 --- a/packages/vitest/src/defaults.ts +++ b/packages/vitest/src/defaults.ts @@ -67,7 +67,7 @@ const config = { watch: !isCI, globals: false, environment: 'node' as const, - pool: 'threads' as const, + pool: 'forks' as const, clearMocks: false, restoreMocks: false, mockReset: false, diff --git a/test/browser/vitest.config.unit.mts b/test/browser/vitest.config.unit.mts index 0fa549ea6d1d..a2a1707127d2 100644 --- a/test/browser/vitest.config.unit.mts +++ b/test/browser/vitest.config.unit.mts @@ -4,8 +4,8 @@ export default defineConfig({ test: { include: ['specs/**/*.{spec,test}.ts'], poolOptions: { - threads: { - singleThread: true, + forks: { + singleFork: true, }, }, hookTimeout: process.env.CI ? 120_000 : 10_000, diff --git a/test/config/test/chai-config.test.ts b/test/config/test/chai-config.test.ts index 9d99ba26eb5b..08c4f471d255 100644 --- a/test/config/test/chai-config.test.ts +++ b/test/config/test/chai-config.test.ts @@ -18,8 +18,7 @@ describe('truncateThreshold', () => { ok 6 - test-each-title.test.ts > [ 'one', 'two', 'three', 'four', …(1) ] ok 7 - test-each-title.test.ts > { one: 1, two: 2, three: 3 } ok 8 - test-each-title.test.ts > { one: 1, two: 2, three: 3, four: 4 } - ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, …(2) } - " + ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, …(2) }" `) expect(result.exitCode).toBe(0) }) @@ -43,8 +42,7 @@ describe('truncateThreshold', () => { ok 6 - test-each-title.test.ts > [ 'one', 'two', 'three', 'four', …(1) ] ok 7 - test-each-title.test.ts > { one: 1, two: 2, three: 3 } ok 8 - test-each-title.test.ts > { one: 1, two: 2, three: 3, four: 4 } - ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, …(2) } - " + ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, …(2) }" `) expect(result.exitCode).toBe(0) }) @@ -68,8 +66,7 @@ describe('truncateThreshold', () => { ok 6 - test-each-title.test.ts > [ 'one', 'two', 'three', 'four', 'five' ] ok 7 - test-each-title.test.ts > { one: 1, two: 2, three: 3 } ok 8 - test-each-title.test.ts > { one: 1, two: 2, three: 3, four: 4 } - ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, four: 4, five: 5 } - " + ok 9 - test-each-title.test.ts > { one: 1, two: 2, three: 3, four: 4, five: 5 }" `) expect(result.exitCode).toBe(0) }) @@ -77,5 +74,5 @@ describe('truncateThreshold', () => { function cleanOutput(output: string) { // remove non-deterministic output - return output.replaceAll(/\s*# time=.*/g, '') + return output.replaceAll(/\s*# time=.*/g, '').trim() } diff --git a/test/config/test/failures.test.ts b/test/config/test/failures.test.ts index 85a2973d7f84..4f3ca721d13e 100644 --- a/test/config/test/failures.test.ts +++ b/test/config/test/failures.test.ts @@ -144,7 +144,6 @@ test('boolean flag 100 should not crash CLI', async () => { test('nextTick cannot be mocked inside child_process', async () => { const { stderr } = await runVitest({ - pool: 'forks', fakeTimers: { toFake: ['nextTick'] }, include: ['./fake-timers.test.ts'], }) @@ -154,6 +153,7 @@ test('nextTick cannot be mocked inside child_process', async () => { test('nextTick can be mocked inside worker_threads', async () => { const { stderr } = await runVitest({ + pool: 'threads', fakeTimers: { toFake: ['nextTick'] }, include: ['./fixtures/test/fake-timers.test.ts'], }) diff --git a/test/watch/vitest.config.ts b/test/watch/vitest.config.ts index a4a312f5d826..3eda83706106 100644 --- a/test/watch/vitest.config.ts +++ b/test/watch/vitest.config.ts @@ -13,13 +13,10 @@ export default defineConfig({ testTimeout: process.env.CI ? 60_000 : 10_000, // Test cases may have side effects, e.g. files under fixtures/ are modified on the fly to trigger file watchers - poolOptions: { - forks: { singleFork: true }, - threads: { singleThread: true }, - vmThreads: { singleThread: true }, - }, + fileParallelism: false, // TODO: Fix flakiness and remove allowOnly: true, + bail: 1, }, })