Skip to content
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
2 changes: 1 addition & 1 deletion docs/api/advanced/reporters.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function onInit(vitest: Vitest): Awaitable<void>
This method is called when [Vitest](/api/advanced/vitest) was initiated or started, but before the tests were filtered.

::: info
Internally this method is called inside [`vitest.start`](/api/advanced/vitest#start), [`vitest.init`](/api/advanced/vitest#init) or [`vitest.mergeReports`](/api/advanced/vitest#mergereports). If you are using programmatic API, make sure to call either one depending on your needs before calling [`vitest.runTestSpecifications`](/api/advanced/vitest#runtestspecifications), for example. Built-in CLI will always run methods in correct order.
Internally this method is called inside [`vitest.start`](/api/advanced/vitest#start), [`vitest.standalone`](/api/advanced/vitest#standalone) or [`vitest.mergeReports`](/api/advanced/vitest#mergereports). If you are using programmatic API, make sure to call either one depending on your needs before calling [`vitest.runTestSpecifications`](/api/advanced/vitest#runtestspecifications), for example. Built-in CLI will always run methods in correct order.
:::

Note that you can also get access to `vitest` instance from test cases, suites and test modules via a [`project`](/api/advanced/test-project) property, but it might also be useful to store a reference to `vitest` in this method.
Expand Down
10 changes: 6 additions & 4 deletions docs/api/advanced/vitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,17 +233,19 @@ function start(filters?: string[]): Promise<TestRunResult>
Initialize reporters, the coverage provider, and run tests. This method accepts string filters to match the test files - these are the same filters that [CLI supports](/guide/filtering#cli).

::: warning
This method should not be called if [`vitest.init()`](#init) is also invoked. Use [`runTestSpecifications`](#runtestspecifications) or [`rerunTestSpecifications`](#reruntestspecifications) instead if you need to run tests after Vitest was initialised.
This method should not be called if [`vitest.standalone()`](#standalone) is also invoked. Use [`runTestSpecifications`](#runtestspecifications) or [`rerunTestSpecifications`](#reruntestspecifications) instead if you need to run tests after Vitest was initialised.
:::

This method is called automatically by [`startVitest`](/guide/advanced/tests) if `config.mergeReports` and `config.standalone` are not set.

## init
## standalone <Version type="experimental">4.1.1</Version> {#standalone}

```ts
function init(): Promise<void>
function standalone(): Promise<void>
```

- **Alias**: `init` <Deprecated />

Initialize reporters and the coverage provider. This method doesn't run any tests. If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.

Internally, this method is called only if [`--standalone`](/guide/cli#standalone) flag is enabled.
Expand Down Expand Up @@ -545,7 +547,7 @@ If there is a test run happening, returns a promise that will resolve when the t
function createCoverageProvider(): Promise<CoverageProvider | null>
```

Creates a coverage provider if `coverage` is enabled in the config. This is done automatically if you are running tests with [`start`](#start) or [`init`](#init) methods.
Creates a coverage provider if `coverage` is enabled in the config. This is done automatically if you are running tests with [`start`](#start) or [`standalone`](#standalone) methods.

::: warning
This method will also clean all previous reports if [`coverage.clean`](/config/coverage#coverage-clean) is not set to `false`.
Expand Down
2 changes: 1 addition & 1 deletion docs/api/expect.md
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ test('calls mock1 after mock2', () => {
})
```

## toHaveBeenCalledExactlyOnceWit
## toHaveBeenCalledExactlyOnceWith

- **Type**: `(...args: any[]) => Awaitable<void>`

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/cli-generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,7 @@ Use `bundle` to bundle the config with esbuild or `runner` (experimental) to pro

- **CLI:** `--standalone`

Start Vitest without running tests. Tests will be running only on change. This option is ignored when CLI file filters are passed. (default: `false`)
Start Vitest without running tests. Tests will be running only on change. If browser mode is enabled, the UI will be opened automatically. This option is ignored when CLI file filters are passed. (default: `false`)

### listTags

Expand Down
4 changes: 2 additions & 2 deletions packages/vitest/src/node/cli/cli-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export async function startVitest(

ctx.onAfterSetServer(() => {
if (ctx.config.standalone) {
ctx.init()
ctx.standalone()
}
else {
ctx.start(cliFilters)
Expand All @@ -111,7 +111,7 @@ export async function startVitest(
await ctx.mergeReports()
}
else if (ctx.config.standalone) {
await ctx.init()
await ctx.standalone()
}
else {
await ctx.start(cliFilters)
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ export const cliOptionsConfig: VitestCLIOptions = {
},
standalone: {
description:
'Start Vitest without running tests. Tests will be running only on change. This option is ignored when CLI file filters are passed. (default: `false`)',
'Start Vitest without running tests. Tests will be running only on change. If browser mode is enabled, the UI will be opened automatically. This option is ignored when CLI file filters are passed. (default: `false`)',
},
mergeReports: {
description:
Expand Down
12 changes: 11 additions & 1 deletion packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,11 +794,19 @@ export class Vitest {
})
}

/**
* @deprecated use `standalone()` instead
*/
init(): Promise<void> {
this.logger.deprecate('`vitest.init()` is deprecated. Use `vitest.standalone()` instead.')
return this.standalone()
}

/**
* Initialize reporters and the coverage provider. This method doesn't run any tests.
* If the `--watch` flag is provided, Vitest will still run changed tests even if this method was not called.
*/
async init(): Promise<void> {
async standalone(): Promise<void> {
await this._traces.$('vitest.init', async () => {
try {
await this.initCoverageProvider()
Expand All @@ -811,6 +819,8 @@ export class Vitest {
// populate test files cache so watch mode can trigger a file rerun
await this.globTestSpecifications()

await Promise.all(this.projects.map(project => project._standalone()))

if (this.config.watch) {
await this.report('onWatcherStart')
}
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export class Logger {
}

if (this.ctx.config.standalone) {
this.log(c.yellow(`\nVitest is running in standalone mode. Edit a test file to rerun tests.`))
this.log(c.yellow(`\nVitest is running in standalone mode. Edit a test file to rerun tests.\n`))
}
else {
this.log()
Expand Down
36 changes: 6 additions & 30 deletions packages/vitest/src/node/pools/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,8 @@ export function createBrowserPool(vitest: Vitest): ProcessPool {

debug?.('creating pool for project %s', project.name)

const resolvedUrls = project.browser!.vite.resolvedUrls
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0]

if (!origin) {
throw new Error(
`Can't find browser origin URL for project "${project.name}"`,
)
}

const pool: BrowserPool = new BrowserPool(project, {
maxWorkers: getThreadsCount(project),
origin,
})
projectPools.set(project, pool)
vitest.onCancel(() => {
Expand Down Expand Up @@ -198,7 +188,7 @@ class BrowserPool {
private _promise: DeferPromise<void> | undefined
private _providedContext: string | undefined

private readySessions = new Set<string>()
private readySessions: Set<string>

private _traces: Traces
private _otel: {
Expand All @@ -210,7 +200,6 @@ class BrowserPool {
private project: TestProject,
private options: {
maxWorkers: number
origin: string
},
) {
this._traces = project.vitest._traces
Expand All @@ -219,6 +208,7 @@ class BrowserPool {
'vitest.project': project.name,
'vitest.browser.provider': this.project.browser!.provider.name,
})
this.readySessions = project._browserReadySessions
}

public cancel(): void {
Expand Down Expand Up @@ -296,24 +286,10 @@ class BrowserPool {
}

private async openPage(sessionId: string, options: { parallel: boolean }): Promise<void> {
const sessionPromise = this.project.vitest._browserSessions.createSession(
sessionId,
this.project,
this,
)
const browser = this.project.browser!
const url = new URL('/__vitest_test__/', this.options.origin)
url.searchParams.set('sessionId', sessionId)
const otelCarrier = this._traces.getContextCarrier()
if (otelCarrier) {
url.searchParams.set('otelCarrier', JSON.stringify(otelCarrier))
}
const pagePromise = browser.provider.openPage(
sessionId,
url.toString(),
options,
)
await Promise.all([sessionPromise, pagePromise])
await this.project._openBrowserPage(sessionId, {
reject: error => this.reject(error),
parallel: options.parallel,
})
}

private getOrchestrator(sessionId: string) {
Expand Down
62 changes: 62 additions & 0 deletions packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
TestProjectInlineConfiguration,
UserConfig,
} from './types/config'
import crypto from 'node:crypto'
import { promises as fs, readFileSync } from 'node:fs'
import { rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
Expand Down Expand Up @@ -70,6 +71,7 @@ export class TestProject {
/** @internal */ _fetcher!: VitestFetchFunction
/** @internal */ _serializedDefines?: string
/** @internal */ testFilesList: string[] | null = null
/** @internal */ _browserReadySessions = new Set<string>()

private runner!: ModuleRunner

Expand Down Expand Up @@ -604,6 +606,66 @@ export class TestProject {
]
}

/** @internal */
public async _openBrowserPage(sessionId: string, pool: {
reject: (error: Error) => void
parallel?: boolean
}): Promise<void> {
if (!this.browser) {
throw new Error(`browser is not initialized`)
}

const resolvedUrls = this.browser.vite.resolvedUrls
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0]
if (!origin) {
throw new Error(
`Can't find browser origin URL for project "${this.name}"`,
)
}

const url = new URL('/__vitest_test__/', origin)
url.searchParams.set('sessionId', sessionId)
const otelCarrier = this.vitest._traces.getContextCarrier()
if (otelCarrier) {
url.searchParams.set('otelCarrier', JSON.stringify(otelCarrier))
}
this.vitest._browserSessions.sessionIds.add(sessionId)
const sessionPromise = this.vitest._browserSessions.createSession(
sessionId,
this,
pool,
)
const pagePromise = this.browser.provider.openPage(
sessionId,
url.toString(),
{ parallel: pool.parallel ?? false },
)
await Promise.all([
sessionPromise,
pagePromise,
])
}

/** @internal */
public async _standalone(): Promise<void> {
if (!this.isBrowserEnabled()) {
return
}

await this._initBrowserProvider()
if (!this.browser) {
return
}

const sessionId = crypto.randomUUID()
await this._openBrowserPage(sessionId, {
reject: (error) => {
this.vitest.state.catchError(error, 'Browser Error')
},
})
this._browserReadySessions.add(sessionId)
}

private _serializeOverriddenConfig(): SerializedConfig {
// TODO: serialize the config _once_ or when needed
const config = serializeConfig(this)
Expand Down
Loading