Skip to content

Commit 417bdb4

Browse files
authored
fix(browser): init browsers eagerly when tests are running (#6876)
1 parent 32be0af commit 417bdb4

File tree

13 files changed

+83
-65
lines changed

13 files changed

+83
-65
lines changed

Diff for: docs/guide/browser/index.md

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ export default defineConfig({
107107

108108
::: info
109109
Vitest assigns port `63315` to avoid conflicts with the development server, allowing you to run both in parallel. You can change that with the [`browser.api`](/config/#browser-api) option.
110+
111+
Since Vitest 2.1.5, CLI no longer prints the Vite URL automcatically. You can press "b" to print the URL when running in watch mode.
110112
:::
111113

112114
If you have not used Vite before, make sure you have your framework's plugin installed and specified in the config. Some frameworks might require extra configuration to work - check their Vite related documentation to be sure.

Diff for: packages/browser/src/node/pool.ts

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export function createBrowserPool(ctx: Vitest): ProcessPool {
131131
if (isCancelled) {
132132
break
133133
}
134+
await project.initBrowserProvider()
134135

135136
await executeTests(method, project, files)
136137
}

Diff for: packages/browser/src/node/providers/preview.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { BrowserProvider, WorkspaceProject } from 'vitest/node'
33
export class PreviewBrowserProvider implements BrowserProvider {
44
public name = 'preview' as const
55
public supportsParallelism: boolean = false
6-
private ctx!: WorkspaceProject
6+
private project!: WorkspaceProject
77
private open = false
88

99
getSupportedBrowsers() {
@@ -19,25 +19,26 @@ export class PreviewBrowserProvider implements BrowserProvider {
1919
return {}
2020
}
2121

22-
async initialize(ctx: WorkspaceProject) {
23-
this.ctx = ctx
22+
async initialize(project: WorkspaceProject) {
23+
this.project = project
2424
this.open = false
25-
if (ctx.config.browser.headless) {
25+
if (project.config.browser.headless) {
2626
throw new Error(
2727
'You\'ve enabled headless mode for "preview" provider but it doesn\'t support it. Use "playwright" or "webdriverio" instead: https://vitest.dev/guide/browser/#configuration',
2828
)
2929
}
30+
project.ctx.logger.printBrowserBanner(project)
3031
}
3132

3233
async openPage(_contextId: string, url: string) {
3334
this.open = true
34-
if (!this.ctx.browser) {
35+
if (!this.project.browser) {
3536
throw new Error('Browser is not initialized')
3637
}
37-
const options = this.ctx.browser.vite.config.server
38+
const options = this.project.browser.vite.config.server
3839
const _open = options.open
3940
options.open = url
40-
this.ctx.browser.vite.openBrowser()
41+
this.project.browser.vite.openBrowser()
4142
options.open = _open
4243
}
4344

Diff for: packages/vitest/src/node/core.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,6 @@ export class Vitest {
303303
return this.coverageProvider
304304
}
305305

306-
private async initBrowserProviders() {
307-
return Promise.all(this.projects.map(w => w.initBrowserProvider()))
308-
}
309-
310306
async mergeReports() {
311307
if (this.reporters.some(r => r instanceof BlobReporter)) {
312308
throw new Error('Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first.')
@@ -369,8 +365,6 @@ export class Vitest {
369365
async collect(filters?: string[]) {
370366
this._onClose = []
371367

372-
await this.initBrowserProviders()
373-
374368
const files = await this.filterTestsBySource(
375369
await this.globTestFiles(filters),
376370
)
@@ -402,7 +396,6 @@ export class Vitest {
402396
try {
403397
await this.initCoverageProvider()
404398
await this.coverageProvider?.clean(this.config.coverage.clean)
405-
await this.initBrowserProviders()
406399
}
407400
finally {
408401
await this.report('onInit', this)
@@ -445,7 +438,6 @@ export class Vitest {
445438
try {
446439
await this.initCoverageProvider()
447440
await this.coverageProvider?.clean(this.config.coverage.clean)
448-
await this.initBrowserProviders()
449441
}
450442
finally {
451443
await this.report('onInit', this)
@@ -693,6 +685,10 @@ export class Vitest {
693685
await Promise.all(this._onCancelListeners.splice(0).map(listener => listener(reason)))
694686
}
695687

688+
async initBrowserServers() {
689+
await Promise.all(this.projects.map(p => p.initBrowserServer()))
690+
}
691+
696692
async rerunFiles(files: string[] = this.state.getFilepaths(), trigger?: string, allTestsRun = true) {
697693
if (this.filenamePattern) {
698694
const filteredFiles = await this.globTestFiles([this.filenamePattern])

Diff for: packages/vitest/src/node/logger.ts

+25-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { createLogUpdate } from 'log-update'
1212
import c from 'tinyrainbow'
1313
import { highlightCode } from '../utils/colors'
1414
import { printError } from './error'
15-
import { divider, withLabel } from './reporters/renderers/utils'
15+
import { divider, formatProjectName, withLabel } from './reporters/renderers/utils'
1616
import { RandomSequencer } from './sequencers/RandomSequencer'
1717

1818
export interface ErrorOptions {
@@ -217,21 +217,6 @@ export class Logger {
217217
this.log(PAD + c.gray(`Running tests with seed "${this.ctx.config.sequence.seed}"`))
218218
}
219219

220-
this.ctx.projects.forEach((project) => {
221-
if (!project.browser) {
222-
return
223-
}
224-
const name = project.getName()
225-
const output = project.isCore() ? '' : ` [${name}]`
226-
227-
const resolvedUrls = project.browser.vite.resolvedUrls
228-
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0]
229-
const provider = project.browser.provider.name
230-
const providerString = provider === 'preview' ? '' : ` by ${provider}`
231-
232-
this.log(PAD + c.dim(c.green(`${output} Browser runner started${providerString} at ${new URL('/', origin)}`)))
233-
})
234-
235220
if (this.ctx.config.ui) {
236221
const host = this.ctx.config.api?.host || 'localhost'
237222
const port = this.ctx.server.config.server.port
@@ -260,6 +245,30 @@ export class Logger {
260245
}
261246
}
262247

248+
printBrowserBanner(project: WorkspaceProject) {
249+
if (!project.browser) {
250+
return
251+
}
252+
253+
const resolvedUrls = project.browser.vite.resolvedUrls
254+
const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0]
255+
if (!origin) {
256+
return
257+
}
258+
259+
const name = project.getName()
260+
const output = project.isCore()
261+
? ''
262+
: formatProjectName(name)
263+
const provider = project.browser.provider.name
264+
const providerString = provider === 'preview' ? '' : ` by ${c.reset(c.bold(provider))}`
265+
this.log(
266+
c.dim(
267+
`${output}Browser runner started${providerString} ${c.dim('at')} ${c.blue(new URL('/', origin))}\n`,
268+
),
269+
)
270+
}
271+
263272
printUnhandledErrors(errors: unknown[]) {
264273
const errorMessage = c.red(
265274
c.bold(

Diff for: packages/vitest/src/node/stdin.ts

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const keys = [
1818
['p', 'filter by a filename'],
1919
['t', 'filter by a test name regex pattern'],
2020
['w', 'filter by a project name'],
21+
['b', 'start the browser server if not started yet'],
2122
['q', 'quit'],
2223
]
2324
const cancelKeys = ['space', 'c', 'h', ...keys.map(key => key[0]).flat()]
@@ -120,6 +121,14 @@ export function registerConsoleShortcuts(
120121
if (name === 'p') {
121122
return inputFilePattern()
122123
}
124+
if (name === 'b') {
125+
await ctx.initBrowserServers()
126+
ctx.projects.forEach((project) => {
127+
ctx.logger.log()
128+
ctx.logger.printBrowserBanner(project)
129+
})
130+
return null
131+
}
123132
}
124133

125134
async function keypressHandler(str: string, key: any) {

Diff for: packages/vitest/src/node/workspace.ts

+8-10
Original file line numberDiff line numberDiff line change
@@ -358,16 +358,15 @@ export class WorkspaceProject {
358358
return testFiles
359359
}
360360

361-
async initBrowserServer(configFile: string | undefined) {
362-
if (!this.isBrowserEnabled()) {
361+
async initBrowserServer() {
362+
if (!this.isBrowserEnabled() || this.browser) {
363363
return
364364
}
365365
await this.ctx.packageInstaller.ensureInstalled('@vitest/browser', this.config.root, this.ctx.version)
366366
const { createBrowserServer, distRoot } = await import('@vitest/browser')
367-
await this.browser?.close()
368367
const browser = await createBrowserServer(
369368
this,
370-
configFile,
369+
this.server.config.configFile,
371370
[
372371
...MocksPlugins({
373372
filter(id) {
@@ -408,9 +407,7 @@ export class WorkspaceProject {
408407
}
409408

410409
static async createCoreProject(ctx: Vitest) {
411-
const project = WorkspaceProject.createBasicProject(ctx)
412-
await project.initBrowserServer(ctx.server.config.configFile)
413-
return project
410+
return WorkspaceProject.createBasicProject(ctx)
414411
}
415412

416413
async setServer(options: UserConfig, server: ViteDevServer) {
@@ -449,8 +446,6 @@ export class WorkspaceProject {
449446
return node.resolveId(id, importer)
450447
},
451448
})
452-
453-
await this.initBrowserServer(this.server.config.configFile)
454449
}
455450

456451
isBrowserEnabled(): boolean {
@@ -495,9 +490,12 @@ export class WorkspaceProject {
495490
}
496491

497492
async initBrowserProvider() {
498-
if (!this.isBrowserEnabled()) {
493+
if (!this.isBrowserEnabled() || this.browser?.provider) {
499494
return
500495
}
496+
if (!this.browser) {
497+
await this.initBrowserServer()
498+
}
501499
await this.browser?.initBrowserProvider()
502500
}
503501
}

Diff for: test/browser/specs/runner.test.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { readFile } from 'node:fs/promises'
22
import { beforeAll, describe, expect, onTestFailed, test } from 'vitest'
3-
import { defaultBrowserPort } from 'vitest/config'
4-
import { browser, provider, runBrowserTests } from './utils'
3+
import { browser, runBrowserTests } from './utils'
54

65
describe('running browser tests', async () => {
76
let stderr: string
@@ -29,8 +28,6 @@ describe('running browser tests', async () => {
2928
console.error(stderr)
3029
})
3130

32-
expect(stdout).toContain(`Browser runner started by ${provider} at http://localhost:${defaultBrowserPort}/`)
33-
3431
expect(browserResultJson.testResults).toHaveLength(19)
3532
expect(passedTests).toHaveLength(17)
3633
expect(failedTests).toHaveLength(2)

Diff for: test/browser/specs/server-url.test.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
import { afterEach, expect, test } from 'vitest'
2-
import { provider, runBrowserTests } from './utils'
2+
import { runBrowserTests } from './utils'
33

44
afterEach(() => {
55
delete process.env.TEST_HTTPS
66
})
77

88
test('server-url http', async () => {
9-
const { stdout, stderr } = await runBrowserTests({
9+
const { stderr, ctx } = await runBrowserTests({
1010
root: './fixtures/server-url',
11+
watch: true, // otherwise the browser is closed before we can get the url
1112
})
13+
const url = ctx?.projects[0].browser?.vite.resolvedUrls?.local[0]
1214
expect(stderr).toBe('')
13-
expect(stdout).toContain(`Browser runner started by ${provider} at http://localhost:51133/`)
15+
expect(url).toBe('http://localhost:51133/')
1416
})
1517

1618
test('server-url https', async () => {
1719
process.env.TEST_HTTPS = '1'
18-
const { stdout, stderr } = await runBrowserTests({
20+
const { stdout, stderr, ctx } = await runBrowserTests({
1921
root: './fixtures/server-url',
22+
watch: true, // otherwise the browser is closed before we can get the url
2023
})
2124
expect(stderr).toBe('')
22-
expect(stdout).toContain(`Browser runner started by ${provider} at https://localhost:51122/`)
25+
const url = ctx?.projects[0].browser?.vite.resolvedUrls?.local[0]
26+
expect(url).toBe('https://localhost:51122/')
2327
expect(stdout).toContain('Test Files 1 passed')
2428
})

Diff for: test/cli/fixtures/browser-multiple/basic.test.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { test } from 'vitest';
2+
3+
test('passes')

Diff for: test/cli/fixtures/browser-multiple/vitest.workspace.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ export default defineWorkspace([
66
cacheDir: resolve(import.meta.dirname, 'basic-1'),
77
test: {
88
name: 'basic-1',
9-
include: ['none'],
9+
dir: import.meta.dirname,
10+
include: ['./basic.test.js'],
1011
browser: {
1112
enabled: true,
1213
name: 'chromium',
@@ -19,7 +20,8 @@ export default defineWorkspace([
1920
cacheDir: resolve(import.meta.dirname, 'basic-2'),
2021
test: {
2122
name: 'basic-2',
22-
include: ['none'],
23+
dir: import.meta.dirname,
24+
include: ['./basic.test.js'],
2325
browser: {
2426
enabled: true,
2527
name: 'chromium',

Diff for: test/cli/test/browser-multiple.test.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ it('automatically assigns the port', async () => {
88
const workspace = resolve(import.meta.dirname, '../fixtures/browser-multiple/vitest.workspace.ts')
99
const spy = vi.spyOn(console, 'log')
1010
onTestFinished(() => spy.mockRestore())
11-
const { stderr, stdout } = await runVitest({
11+
const { stderr, ctx } = await runVitest({
1212
root,
1313
workspace,
1414
dir: root,
15-
watch: false,
15+
watch: true,
1616
})
17+
const urls = ctx?.projects.map(p => p.browser?.vite.resolvedUrls?.local[0])
1718

1819
expect(spy).not.toHaveBeenCalled()
1920
expect(stderr).not.toContain('is in use, trying another one...')
20-
expect(stdout).toContain('Browser runner started by playwright at http://localhost:63315/')
21-
expect(stdout).toContain('Browser runner started by playwright at http://localhost:63316/')
21+
expect(urls).toContain('http://localhost:63315/')
22+
expect(urls).toContain('http://localhost:63316/')
2223
})

Diff for: test/config/test/browser-html.test.ts

+4-9
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@ import { runVitest } from '../../test-utils'
55
const root = resolve(import.meta.dirname, '../fixtures/browser-custom-html')
66

77
test('throws an error with non-existing path', async () => {
8-
const { stderr, thrown } = await runVitest({
8+
const { stderr } = await runVitest({
99
root,
1010
config: './vitest.config.non-existing.ts',
1111
}, [], 'test', {}, { fails: true })
12-
expect(thrown).toBe(true)
1312
expect(stderr).toContain(`Tester HTML file "${resolve(root, './some-non-existing-path')}" doesn't exist.`)
1413
})
1514

1615
test('throws an error and exits if there is an error in the html file hook', async () => {
17-
const { stderr, stdout, exitCode } = await runVitest({
16+
const { stderr, exitCode } = await runVitest({
1817
root,
1918
config: './vitest.config.error-hook.ts',
2019
})
21-
expect(stderr).toContain('expected error in transformIndexHtml')
22-
// error happens when browser is opened
23-
expect(stdout).toContain('Browser runner started by playwright')
20+
expect(stderr).toContain('Error: expected error in transformIndexHtml')
21+
expect(stderr).toContain('[vite] Internal server error: expected error in transformIndexHtml')
2422
expect(exitCode).toBe(1)
2523
})
2624

@@ -31,7 +29,6 @@ test('allows correct custom html', async () => {
3129
reporters: ['basic'],
3230
})
3331
expect(stderr).toBe('')
34-
expect(stdout).toContain('Browser runner started by playwright')
3532
expect(stdout).toContain('✓ browser-basic.test.ts')
3633
expect(exitCode).toBe(0)
3734
})
@@ -43,7 +40,6 @@ test('allows custom transformIndexHtml with custom html file', async () => {
4340
reporters: ['basic'],
4441
})
4542
expect(stderr).toBe('')
46-
expect(stdout).toContain('Browser runner started by playwright')
4743
expect(stdout).toContain('✓ browser-custom.test.ts')
4844
expect(exitCode).toBe(0)
4945
})
@@ -55,7 +51,6 @@ test('allows custom transformIndexHtml without custom html file', async () => {
5551
reporters: ['basic'],
5652
})
5753
expect(stderr).toBe('')
58-
expect(stdout).toContain('Browser runner started by playwright')
5954
expect(stdout).toContain('✓ browser-custom.test.ts')
6055
expect(exitCode).toBe(0)
6156
})

0 commit comments

Comments
 (0)