Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: support multiple parallel child_process #3925

Merged
merged 3 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ jobs:
- name: Test
run: pnpm run test:ci

- name: Test Single Thread
run: pnpm run test:ci:single-thread
- name: Test No Threads
run: pnpm run test:ci:no-threads

- name: Test Vm Threads
run: pnpm run test:ci:vm-threads
Expand Down
7 changes: 7 additions & 0 deletions docs/api/vi.md
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,15 @@ unmockedIncrement(30) === 31

To enable mocking timers, you need to call this method. It will wrap all further calls to timers (such as `setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, `nextTick`, `setImmediate`, `clearImmediate`, and `Date`), until [`vi.useRealTimers()`](#vi-userealtimers) is called.

Mocking `nextTick` is not supported when running Vitest inside `node:child_process` by using `--no-threads`. NodeJS uses `process.nextTick` internally in `node:child_process` and hangs when it is mocked. Mocking `nextTick` is supported when running Vitest with `--threads`.

The implementation is based internally on [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers).

::: tip
Since version `0.35.0` `vi.useFakeTimers()` no longer automatically mocks `process.nextTick`.
It can still be mocked by specyfing the option in `toFake` argument: `vi.useFakeTimers({ toFake: ['nextTick'] })`.
:::

## vi.isFakeTimers

- **Type:** `() => boolean`
Expand Down
2 changes: 1 addition & 1 deletion docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ Percentage based memory limit [does not work on Linux CircleCI](https://github.c

Enable multi-threading using [tinypool](https://github.com/tinylibs/tinypool) (a lightweight fork of [Piscina](https://github.com/piscinajs/piscina)). Prior to Vitest 0.29.0, Vitest was still running tests inside worker thread, even if this option was disabled. Since 0.29.0, if this option is disabled, Vitest uses `child_process` to spawn a process to run tests inside, meaning you can use `process.chdir` and other API that was not available inside workers. If you want to revert to the previous behaviour, use `--single-thread` option instead.

Disabling this option also disables module isolation, meaning all tests with the same environment are running inside a single child process.
Disabling this option makes all tests run inside multiple child processes.

### singleThread

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Vitest also supports debugging tests without IDEs. However this requires that te
vitest --inspect-brk --single-thread

# To run in a child process
vitest --inspect-brk --no-threads
vitest --inspect-brk --single-thread --no-threads
```

Once Vitest starts it will stop execution and waits for you to open developer tools that can connect to [NodeJS inspector](https://nodejs.org/en/docs/guides/debugging-getting-started/). You can use Chrome DevTools for this by opening `chrome://inspect` on browser.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"test:all": "CI=true pnpm -r --stream run test --allowOnly",
"test:ci": "CI=true pnpm -r --stream --filter !test-fails --filter !test-browser --filter !test-esm --filter !test-browser run test --allowOnly",
"test:ci:vm-threads": "CI=true pnpm -r --stream --filter !test-fails --filter !test-single-thread --filter !test-browser --filter !test-esm --filter !test-browser run test --allowOnly --experimental-vm-threads",
"test:ci:single-thread": "CI=true pnpm -r --stream --filter !test-fails --filter !test-coverage --filter !test-watch --filter !test-bail --filter !test-esm --filter !test-browser run test --allowOnly --no-threads",
"test:ci:no-threads": "CI=true pnpm -r --stream --filter !test-fails --filter !test-coverage --filter !test-watch --filter !test-bail --filter !test-esm --filter !test-browser run test --allowOnly --no-threads",
"typecheck": "tsc --noEmit",
"typecheck:why": "tsc --noEmit --explainFiles > explainTypes.txt",
"ui:build": "vite build packages/ui",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"@vitest/ws-client": "workspace:*",
"@vueuse/core": "^10.2.1",
"ansi-to-html": "^0.7.2",
"birpc": "0.2.12",
"birpc": "0.2.14",
"codemirror": "^5.65.13",
"codemirror-theme-vars": "^0.1.2",
"cypress": "^12.16.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
"std-env": "^3.3.3",
"strip-literal": "^1.0.1",
"tinybench": "^2.5.0",
"tinypool": "^0.7.0",
"tinypool": "^0.8.1",
"vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0",
"vite-node": "workspace:*",
"why-is-node-running": "^2.2.2"
Expand All @@ -180,7 +180,7 @@
"@types/micromatch": "^4.0.2",
"@types/prompts": "^2.4.4",
"@types/sinonjs__fake-timers": "^8.1.2",
"birpc": "0.2.12",
"birpc": "0.2.14",
"chai-subset": "^1.6.0",
"cli-truncate": "^3.1.0",
"event-target-polyfill": "^0.0.3",
Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/api/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, server?: Vit

const wss = new WebSocketServer({ noServer: true })

const clients = new Map<WebSocket, BirpcReturn<WebSocketEvents>>()
const clients = new Map<WebSocket, BirpcReturn<WebSocketEvents, WebSocketHandlers>>()

;(server || ctx.server).httpServer?.on('upgrade', (request, socket, head) => {
if (!request.url)
Expand Down Expand Up @@ -154,7 +154,7 @@ class WebSocketReporter implements Reporter {
constructor(
public ctx: Vitest,
public wss: WebSocketServer,
public clients: Map<WebSocket, BirpcReturn<WebSocketEvents>>,
public clients: Map<WebSocket, BirpcReturn<WebSocketEvents, WebSocketHandlers>>,
) {}

onCollected(files?: File[]) {
Expand Down
8 changes: 7 additions & 1 deletion packages/vitest/src/integrations/mock/timers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,13 @@ export class FakeTimers {
}

if (!this._fakingTime) {
const toFake = Object.keys(this._fakeTimers.timers) as Array<keyof FakeTimerWithContext['timers']>
const toFake = Object.keys(this._fakeTimers.timers)
// Do not mock nextTick by default. It can still be mocked through userConfig.
.filter(timer => timer !== 'nextTick') as (keyof FakeTimerWithContext['timers'])[]

// @ts-expect-error -- untyped internal
if (this._userConfig?.toFake?.includes('nextTick') && globalThis.__vitest_worker__.isChildProcess)
throw new Error('process.nextTick cannot be mocked inside child_process')

this._clock = this._fakeTimers.install({
now: Date.now(),
Expand Down
18 changes: 13 additions & 5 deletions packages/vitest/src/integrations/vi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,21 @@ function createVitest(): VitestUtils {

const utils: VitestUtils = {
useFakeTimers(config?: FakeTimerInstallOpts) {
if (config) {
_timers.configure(config)
const workerState = getWorkerState()

if (workerState.isChildProcess) {
if (config?.toFake?.includes('nextTick') || workerState.config?.fakeTimers?.toFake?.includes('nextTick')) {
throw new Error(
'vi.useFakeTimers({ toFake: ["nextTick"] }) is not supported in node:child_process. Use --threads if mocking nextTick is required.',
)
}
}
else {
const workerState = getWorkerState()

if (config)
_timers.configure(config)
else
_timers.configure(workerState.config.fakeTimers)
}

_timers.useFakeTimers()
return utils
},
Expand Down
Loading
Loading