-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
webdriver.ts
136 lines (112 loc) · 3.58 KB
/
webdriver.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import type {
BrowserProvider,
BrowserProviderInitializationOptions,
WorkspaceProject,
} from 'vitest/node'
import type { RemoteOptions } from 'webdriverio'
const webdriverBrowsers = ['firefox', 'chrome', 'edge', 'safari'] as const
type WebdriverBrowser = (typeof webdriverBrowsers)[number]
interface WebdriverProviderOptions
extends BrowserProviderInitializationOptions {
browser: WebdriverBrowser
}
export class WebdriverBrowserProvider implements BrowserProvider {
public name = 'webdriverio' as const
public supportsParallelism: boolean = false
public browser: WebdriverIO.Browser | null = null
private browserName!: WebdriverBrowser
private ctx!: WorkspaceProject
private options?: RemoteOptions
getSupportedBrowsers() {
return webdriverBrowsers
}
async initialize(
ctx: WorkspaceProject,
{ browser, options }: WebdriverProviderOptions,
) {
this.ctx = ctx
this.browserName = browser
this.options = options as RemoteOptions
}
async beforeCommand() {
const page = this.browser!
const iframe = await page.findElement(
'css selector',
'iframe[data-vitest]',
)
await page.switchToFrame(iframe)
}
async afterCommand() {
await this.browser!.switchToParentFrame()
}
getCommandsContext() {
return {
browser: this.browser,
}
}
async openBrowser() {
if (this.browser) {
return this.browser
}
const options = this.ctx.config.browser
if (this.browserName === 'safari') {
if (options.headless) {
throw new Error(
'You\'ve enabled headless mode for Safari but it doesn\'t currently support it.',
)
}
}
const { remote } = await import('webdriverio')
// TODO: close everything, if browser is closed from the outside
this.browser = await remote({
...this.options,
logLevel: 'error',
capabilities: this.buildCapabilities(),
})
return this.browser
}
private buildCapabilities() {
const capabilities: RemoteOptions['capabilities'] = {
...this.options?.capabilities,
browserName: this.browserName,
}
const headlessMap = {
chrome: ['goog:chromeOptions', ['headless', 'disable-gpu']],
firefox: ['moz:firefoxOptions', ['-headless']],
edge: ['ms:edgeOptions', ['--headless']],
} as const
const options = this.ctx.config.browser
const browser = this.browserName
if (browser !== 'safari' && options.headless) {
const [key, args] = headlessMap[browser]
const currentValues = (this.options?.capabilities as any)?.[key] || {}
const newArgs = [...(currentValues.args || []), ...args]
capabilities[key] = { ...currentValues, args: newArgs as any }
}
// start Vitest UI maximized only on supported browsers
if (options.ui && (browser === 'chrome' || browser === 'edge')) {
const key = browser === 'chrome'
? 'goog:chromeOptions'
: 'ms:edgeOptions'
const args = capabilities[key]?.args || []
if (!args.includes('--start-maximized') && !args.includes('--start-fullscreen')) {
args.push('--start-maximized')
}
capabilities[key] ??= {}
capabilities[key]!.args = args
}
return capabilities
}
async openPage(_contextId: string, url: string) {
const browserInstance = await this.openBrowser()
await browserInstance.url(url)
}
async close() {
await Promise.all([
this.browser?.sessionId ? this.browser?.deleteSession?.() : null,
])
// TODO: right now process can only exit with timeout, if we use browser
// needs investigating
process.exit()
}
}