Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148import type { StackTraceParserOptions } from '@vitest/utils/source-map'import type { ViteDevServer } from 'vite'import type { ParsedStack, SerializedConfig, TestError } from 'vitest'import type { BrowserCommands } from 'vitest/browser'import type { BrowserCommand, BrowserCommandContext, BrowserProvider, ProjectBrowser as IProjectBrowser, ResolvedConfig, TestProject, Vitest,} from 'vitest/node'import type { ParentBrowserProject } from './projectParent'import { existsSync } from 'node:fs'import { readFile } from 'node:fs/promises'import { resolve } from 'pathe'import { distRoot } from './constants'import { BrowserServerState } from './state'import { getBrowserProvider } from './utils'
export class ProjectBrowser implements IProjectBrowser { public testerHtml: Promise<string> | string public testerFilepath: string // the tester template is read once per server, so the transformed HTML // is stable too — computing it for every iframe request pays the whole // transformIndexHtml plugin pipeline each time public testerHtmlTransformed: Promise<string> | undefined
public provider!: BrowserProvider public vitest: Vitest public vite: ViteDevServer public config: ResolvedConfig
public state: BrowserServerState = new BrowserServerState()
constructor( public parent: ParentBrowserProject, public project: TestProject, public base: string, ) { this.vitest = project.vitest this.config = project.config this.vite = parent.vite
// instances can override testerHtmlPath const testerHtmlPath = project.config.browser.testerHtmlPath ? resolve(project.config.root, project.config.browser.testerHtmlPath) : resolve(distRoot, 'client/tester/tester.html') // TODO: when config resolution is rewritten, project and parentProject should be created before the vite server is started if (!existsSync(testerHtmlPath)) { throw new Error(`Tester HTML file "${testerHtmlPath}" doesn't exist.`) } this.testerFilepath = testerHtmlPath this.testerHtml = readFile( this.testerFilepath, 'utf8', ).then(html => (this.testerHtml = html)) }
private commands = {} as Record<string, BrowserCommand<any, any>>
public registerCommand<K extends keyof BrowserCommands>( name: K, cb: BrowserCommand< Parameters<BrowserCommands[K]>, ReturnType<BrowserCommands[K]> >, ): void { if (!/^[a-z_$][\w$]*$/i.test(name)) { throw new Error( `Invalid command name "${name}". Only alphanumeric characters, $ and _ are allowed.`, ) } this.commands[name] = cb }
public triggerCommand = (<K extends keyof BrowserCommand>( name: K, context: BrowserCommandContext, ...args: Parameters<BrowserCommands[K]> ): ReturnType<BrowserCommands[K]> => { if (name in this.commands) { return this.commands[name](context, ...args) } if (name in this.parent.commands) { return this.parent.commands[name](context, ...args) } throw new Error(`Provider ${this.provider.name} does not support command "${name}".`) }) as any
wrapSerializedConfig(): SerializedConfig { const config = wrapConfig(this.project.serializedConfig) config.env ??= {} config.env.VITEST_BROWSER_DEBUG = process.env.VITEST_BROWSER_DEBUG || '' return config }
async initBrowserProvider(project: TestProject): Promise<void> { if (this.provider) { return } this.provider = await getBrowserProvider(project.config.browser, project) if (this.provider.initScripts) { this.parent.initScripts = this.provider.initScripts // make sure the script can be imported const allow = this.parent.vite.config.server.fs.allow this.provider.initScripts.forEach((script) => { if (!allow.includes(script)) { allow.push(script) } }) } }
public parseErrorStacktrace( e: TestError, options: StackTraceParserOptions = {}, ): ParsedStack[] { return this.parent.parseErrorStacktrace(e, options) }
public parseStacktrace( trace: string, options: StackTraceParserOptions = {}, ): ParsedStack[] { return this.parent.parseStacktrace(trace, options) }
async close(): Promise<void> { await this.vite.close() }}
function wrapConfig(config: SerializedConfig): SerializedConfig { config = { ...config }
// workaround RegExp serialization config.testNamePattern &&= config.testNamePattern.toString() as any as RegExp
// workaround RegExp serialization if (typeof config.retry === 'object') { config.retry.condition &&= config.retry.condition.toString() as any as RegExp }
return config}