Skip to content

Commit 38adc86

Browse files
authored
feat(browser): support --inspect option in webdriverio (#8613)
1 parent 0d0e5cd commit 38adc86

File tree

9 files changed

+305
-55
lines changed

9 files changed

+305
-55
lines changed

packages/browser/src/node/pool.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ class BrowserPool {
356356
}
357357

358358
const provider = this.project.browser!.provider
359+
const browser = this.project.config.browser.name
360+
361+
if (shouldIgnoreDebugger(provider.name, browser)) {
362+
debug?.('[$s] ignoring debugger in %s browser because it is not supported', sessionId, browser)
363+
return
364+
}
359365

360366
if (!provider.getCDPSession) {
361367
throw new Error('Unable to set breakpoint, CDP not supported')
@@ -370,3 +376,10 @@ class BrowserPool {
370376
})
371377
}
372378
}
379+
380+
function shouldIgnoreDebugger(provider: string, browser: string) {
381+
if (provider === 'webdriverio') {
382+
return browser !== 'chrome' && browser !== 'edge'
383+
}
384+
return browser !== 'chromium'
385+
}

packages/browser/src/node/providers/playwright.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
112112
}
113113
const promises = []
114114
for (const [trace, contextId] of this.pendingTraces.entries()) {
115-
promises.push(() => {
115+
promises.push((() => {
116116
const context = this.contexts.get(contextId)
117117
return context?.tracing.stopChunk({ path: trace })
118-
})
118+
})())
119119
}
120120
return Promise.allSettled(promises)
121121
})
@@ -162,10 +162,11 @@ export class PlaywrightBrowserProvider implements BrowserProvider {
162162
launchOptions.tracesDir = options.trace?.tracesDir
163163
}
164164

165-
if (this.project.config.inspector.enabled) {
165+
const inspector = this.project.vitest.config.inspector
166+
if (inspector.enabled) {
166167
// NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
167-
const port = this.project.config.inspector.port || 9229
168-
const host = this.project.config.inspector.host || '127.0.0.1'
168+
const port = inspector.port || 9229
169+
const host = inspector.host || '127.0.0.1'
169170

170171
launchOptions.args ||= []
171172
launchOptions.args.push(`--remote-debugging-port=${port}`)

packages/browser/src/node/providers/webdriverio.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { Capabilities } from '@wdio/types'
66
import type {
77
BrowserProvider,
88
BrowserProviderOption,
9+
CDPSession,
910
TestProject,
1011
} from 'vitest/node'
1112
import type { ClickOptions, DragAndDropOptions, remote } from 'webdriverio'
@@ -191,6 +192,26 @@ export class WebdriverBrowserProvider implements BrowserProvider {
191192
capabilities[key]!.args = args
192193
}
193194

195+
const inspector = this.project.vitest.config.inspector
196+
if (inspector.enabled && (browser === 'chrome' || browser === 'edge')) {
197+
const key = browser === 'chrome'
198+
? 'goog:chromeOptions'
199+
: 'ms:edgeOptions'
200+
const args = capabilities[key]?.args || []
201+
202+
// NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector
203+
const port = inspector.port || 9229
204+
const host = inspector.host || '127.0.0.1'
205+
206+
args.push(`--remote-debugging-port=${port}`)
207+
args.push(`--remote-debugging-address=${host}`)
208+
209+
this.project.vitest.logger.log(`Debugger listening on ws://${host}:${port}`)
210+
211+
capabilities[key] ??= {}
212+
capabilities[key]!.args = args
213+
}
214+
194215
return capabilities
195216
}
196217

@@ -226,6 +247,28 @@ export class WebdriverBrowserProvider implements BrowserProvider {
226247
browser.sessionId = undefined as unknown as string
227248
this.browser = null
228249
}
250+
251+
async getCDPSession(_sessionId: string): Promise<CDPSession> {
252+
return {
253+
send: (method: string, params: any) => {
254+
if (!this.browser) {
255+
throw new Error(`The environment was torn down.`)
256+
}
257+
return this.browser.sendCommandAndGetResult(method, params ?? {}).catch((error) => {
258+
return Promise.reject(new Error(`Failed to execute "${method}" command.`, { cause: error }))
259+
})
260+
},
261+
on: () => {
262+
throw new Error(`webdriverio provider doesn't support cdp.on()`)
263+
},
264+
once: () => {
265+
throw new Error(`webdriverio provider doesn't support cdp.once()`)
266+
},
267+
off: () => {
268+
throw new Error(`webdriverio provider doesn't support cdp.off()`)
269+
},
270+
}
271+
}
229272
}
230273

231274
declare module 'vitest/node' {

packages/vitest/src/node/config/resolveConfig.ts

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,11 @@ export function resolveConfig(
271271
}
272272
}
273273

274-
const playwrightChromiumOnly = isPlaywrightChromiumOnly(vitest, resolved)
274+
const containsChromium = hasBrowserChromium(vitest, resolved)
275+
const hasOnlyChromium = hasOnlyBrowserChromium(vitest, resolved)
275276

276-
// Browser-mode "Playwright + Chromium" only features:
277-
if (browser.enabled && !playwrightChromiumOnly) {
277+
// Browser-mode "Chromium" only features:
278+
if (browser.enabled && (!containsChromium || !hasOnlyChromium)) {
278279
const browserConfig = `
279280
{
280281
browser: {
@@ -286,18 +287,23 @@ export function resolveConfig(
286287
}
287288
`.trim()
288289

290+
const preferredProvider = (!browser.provider?.name || browser.provider.name === 'preview')
291+
? 'playwright'
292+
: browser.provider.name
293+
const preferredBrowser = preferredProvider === 'playwright' ? 'chromium' : 'chrome'
289294
const correctExample = `
290295
{
291296
browser: {
292-
provider: playwright(),
297+
provider: ${preferredProvider}(),
293298
instances: [
294-
{ browser: 'chromium' }
299+
{ browser: '${preferredBrowser}' }
295300
],
296301
},
297302
}
298303
`.trim()
299304

300-
if (resolved.coverage.enabled && resolved.coverage.provider === 'v8') {
305+
// requires all projects to be chromium
306+
if (!hasOnlyChromium && resolved.coverage.enabled && resolved.coverage.provider === 'v8') {
301307
const coverageExample = `
302308
{
303309
coverage: {
@@ -313,7 +319,8 @@ export function resolveConfig(
313319
)
314320
}
315321

316-
if (resolved.inspect || resolved.inspectBrk) {
322+
// ignores non-chromium browsers when there is at least one chromium project
323+
if (!containsChromium && (resolved.inspect || resolved.inspectBrk)) {
317324
const inspectOption = `--inspect${resolved.inspectBrk ? '-brk' : ''}`
318325

319326
throw new Error(
@@ -846,26 +853,51 @@ export function resolveCoverageReporters(configReporters: NonNullable<BaseCovera
846853
return resolvedReporters
847854
}
848855

849-
function isPlaywrightChromiumOnly(vitest: Vitest, config: ResolvedConfig) {
856+
function isChromiumName(provider: string, name: string) {
857+
if (provider === 'playwright') {
858+
return name === 'chromium'
859+
}
860+
return name === 'chrome' || name === 'edge'
861+
}
862+
863+
function hasBrowserChromium(vitest: Vitest, config: ResolvedConfig) {
850864
const browser = config.browser
851-
if (!browser || !browser.provider || browser.provider.name !== 'playwright' || !browser.enabled) {
865+
if (!browser || !browser.provider || browser.provider.name === 'preview' || !browser.enabled) {
852866
return false
853867
}
854868
if (browser.name) {
855-
return browser.name === 'chromium'
869+
return isChromiumName(browser.provider.name, browser.name)
856870
}
857871
if (!browser.instances) {
858872
return false
859873
}
860-
for (const instance of browser.instances) {
874+
return browser.instances.some((instance) => {
861875
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser)
862876
// browser config is filtered out
863877
if (!vitest.matchesProjectFilter(name)) {
864-
continue
865-
}
866-
if (instance.browser !== 'chromium') {
867878
return false
868879
}
880+
return isChromiumName(browser.provider!.name, instance.browser)
881+
})
882+
}
883+
884+
function hasOnlyBrowserChromium(vitest: Vitest, config: ResolvedConfig) {
885+
const browser = config.browser
886+
if (!browser || !browser.provider || browser.provider.name === 'preview' || !browser.enabled) {
887+
return false
869888
}
870-
return true
889+
if (browser.name) {
890+
return isChromiumName(browser.provider.name, browser.name)
891+
}
892+
if (!browser.instances) {
893+
return false
894+
}
895+
return browser.instances.every((instance) => {
896+
const name = instance.name || (config.name ? `${config.name} (${instance.browser})` : instance.browser)
897+
// browser config is filtered out
898+
if (!vitest.matchesProjectFilter(name)) {
899+
return true // ignore this project
900+
}
901+
return isChromiumName(browser.provider!.name, instance.browser)
902+
})
871903
}

test/browser/fixtures/inspect/vitest.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { playwright } from '@vitest/browser/providers/playwright';
1+
import { provider } from '../../settings'
22
import { defineConfig } from 'vitest/config';
33

44
export default defineConfig({
@@ -7,8 +7,10 @@ export default defineConfig({
77
watch: false,
88
browser: {
99
enabled: true,
10-
provider: playwright(),
11-
instances: [{ browser: "chromium" }],
10+
provider,
11+
instances: [
12+
{ browser: provider.name === 'webdriverio' ? "chrome" : "chromium" },
13+
],
1214
headless: true,
1315
},
1416
},

test/browser/fixtures/inspect/vitest.config.with-workspace.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { playwright } from '@vitest/browser/providers/playwright';
21
import { defineConfig } from "vitest/config";
2+
import { provider } from '../../settings'
33

44
export default defineConfig({
55
server: { port: 5199 },
@@ -11,10 +11,12 @@ export default defineConfig({
1111
test: {
1212
name: "Browser in workspace",
1313
browser: {
14-
provider: playwright(),
14+
provider,
1515
enabled: true,
1616
headless: true,
17-
instances: [{ browser: "chromium" }]
17+
instances: [
18+
{ browser: provider.name === 'webdriverio' ? "chrome" : "chromium" },
19+
],
1820
},
1921
},
2022
},

test/browser/specs/inspect.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import { runVitestCli } from '../../test-utils'
66

77
type Message = Partial<InspectorNotification<any>>
88

9-
const IS_PLAYWRIGHT = process.env.PROVIDER === 'playwright'
109
const REMOTE_DEBUG_URL = '127.0.0.1:9123'
1110

12-
test.runIf(IS_PLAYWRIGHT || !process.env.CI).each(['', 'with workspace'])('--inspect-brk stops at test file %s', async (isWorkspace) => {
11+
test.each(['', 'with workspace'])('--inspect-brk stops at test file %s', async (isWorkspace) => {
1312
const options = ['--root', 'fixtures/inspect', '--no-file-parallelism', '--inspect-brk', REMOTE_DEBUG_URL]
1413

1514
if (isWorkspace) {

0 commit comments

Comments
 (0)