webdriver 9.0.0-alpha.78 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +3 -3
  2. package/build/bidi/core.d.ts +6 -1
  3. package/build/bidi/core.d.ts.map +1 -1
  4. package/build/bidi/handler.d.ts +49 -0
  5. package/build/bidi/handler.d.ts.map +1 -1
  6. package/build/bidi/localTypes.d.ts +134 -47
  7. package/build/bidi/localTypes.d.ts.map +1 -1
  8. package/build/bidi/remoteTypes.d.ts +135 -28
  9. package/build/bidi/remoteTypes.d.ts.map +1 -1
  10. package/build/command.d.ts.map +1 -1
  11. package/build/constants.d.ts +2 -1
  12. package/build/constants.d.ts.map +1 -1
  13. package/build/index.cjs +233 -0
  14. package/build/index.d.cts +2 -0
  15. package/build/index.d.cts.map +1 -0
  16. package/build/index.d.ts +2 -2
  17. package/build/index.d.ts.map +1 -1
  18. package/build/index.js +1615 -141
  19. package/build/request/index.d.ts +1 -2
  20. package/build/request/index.d.ts.map +1 -1
  21. package/build/request/request.d.ts +0 -1
  22. package/build/request/request.d.ts.map +1 -1
  23. package/build/types.d.ts +9 -7
  24. package/build/types.d.ts.map +1 -1
  25. package/build/utils.d.ts +4 -6
  26. package/build/utils.d.ts.map +1 -1
  27. package/package.json +15 -18
  28. package/build/bidi/core.js +0 -73
  29. package/build/bidi/handler.js +0 -446
  30. package/build/bidi/localTypes.js +0 -15
  31. package/build/bidi/remoteTypes.js +0 -15
  32. package/build/bidi/socket.js +0 -49
  33. package/build/cjs/index.d.ts +0 -2
  34. package/build/cjs/index.d.ts.map +0 -1
  35. package/build/cjs/index.js +0 -40
  36. package/build/cjs/package.json +0 -5
  37. package/build/command.js +0 -140
  38. package/build/constants.js +0 -146
  39. package/build/request/index.js +0 -215
  40. package/build/request/request.js +0 -38
  41. package/build/types.js +0 -1
  42. package/build/utils.js +0 -384
  43. /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/index.js CHANGED
@@ -1,151 +1,1625 @@
1
- import logger from '@wdio/logger';
2
- import { webdriverMonad, sessionEnvironmentDetector, startWebDriver } from '@wdio/utils';
3
- import { validateConfig } from '@wdio/config';
4
- import { deepmerge } from 'deepmerge-ts';
5
- import command from './command.js';
6
- import { DEFAULTS } from './constants.js';
7
- import { startWebDriverSession, getPrototype, getEnvironmentVars, setupDirectConnect, initiateBidi, parseBidiMessage } from './utils.js';
8
- const log = logger('webdriver');
9
- export default class WebDriver {
10
- static async newSession(options, modifier, userPrototype = {}, customCommandWrapper) {
11
- const envLogLevel = process.env.WDIO_LOG_LEVEL;
12
- options.logLevel = envLogLevel ?? options.logLevel;
13
- const params = validateConfig(DEFAULTS, options);
14
- if (params.logLevel && (!options.logLevels || !options.logLevels.webdriver)) {
15
- logger.setLevel('webdriver', params.logLevel);
16
- }
17
- log.info('Initiate new session using the WebDriver protocol');
18
- const driverProcess = await startWebDriver(params);
19
- const requestedCapabilities = { ...params.capabilities };
20
- const { sessionId, capabilities } = await startWebDriverSession(params);
21
- const environment = sessionEnvironmentDetector({ capabilities, requestedCapabilities });
22
- const environmentPrototype = getEnvironmentVars(environment);
23
- const protocolCommands = getPrototype(environment);
24
- /**
25
- * attach driver process to instance capabilities so we can kill the driver process
26
- * even after attaching to this session
27
- */
28
- if (driverProcess?.pid) {
29
- capabilities['wdio:driverPID'] = driverProcess.pid;
30
- }
31
- /**
32
- * initiate WebDriver Bidi
33
- */
34
- const bidiPrototype = {};
35
- if (capabilities.webSocketUrl) {
36
- log.info(`Register BiDi handler for session with id ${sessionId}`);
37
- Object.assign(bidiPrototype, initiateBidi(capabilities.webSocketUrl, options.strictSSL));
38
- }
39
- const monad = webdriverMonad({ ...params, requestedCapabilities }, modifier, {
40
- ...protocolCommands,
41
- ...environmentPrototype,
42
- ...userPrototype,
43
- ...bidiPrototype
44
- });
45
- const client = monad(sessionId, customCommandWrapper);
46
- /**
47
- * parse and propagate all Bidi events to the browser instance
48
- */
49
- if (capabilities.webSocketUrl) {
50
- // make sure the Bidi connection is established before returning
51
- await client._bidiHandler.connect();
52
- client._bidiHandler?.socket.on('message', parseBidiMessage.bind(client));
53
- }
54
- /**
55
- * if the server responded with direct connect information, update the
56
- * client options to speak directly to the appium host instead of a load
57
- * balancer (see https://github.com/appium/python-client#direct-connect-urls
58
- * for example). But only do this if the user has enabled this
59
- * behavior in the first place.
60
- */
61
- if (params.enableDirectConnect) {
62
- setupDirectConnect(client);
63
- }
64
- return client;
1
+ // src/index.ts
2
+ import logger5 from "@wdio/logger";
3
+ import { webdriverMonad, sessionEnvironmentDetector, startWebDriver } from "@wdio/utils";
4
+ import { validateConfig } from "@wdio/config";
5
+
6
+ // src/command.ts
7
+ import logger4 from "@wdio/logger";
8
+ import { commandCallStructure, isValidParameter, getArgumentType } from "@wdio/utils";
9
+ import {
10
+ WebDriverBidiProtocol as WebDriverBidiProtocol2
11
+ } from "@wdio/protocols";
12
+
13
+ // src/request/request.ts
14
+ import { performance } from "node:perf_hooks";
15
+ import dns from "node:dns";
16
+
17
+ // src/request/index.ts
18
+ import path from "node:path";
19
+ import { EventEmitter } from "node:events";
20
+ import { WebDriverProtocol as WebDriverProtocol2 } from "@wdio/protocols";
21
+ import { URL } from "node:url";
22
+ import logger3 from "@wdio/logger";
23
+ import { transformCommandLogResult as transformCommandLogResult2 } from "@wdio/utils";
24
+
25
+ // src/utils.ts
26
+ import { deepmergeCustom } from "deepmerge-ts";
27
+ import logger2 from "@wdio/logger";
28
+ import {
29
+ WebDriverProtocol,
30
+ MJsonWProtocol,
31
+ AppiumProtocol,
32
+ ChromiumProtocol,
33
+ SauceLabsProtocol,
34
+ SeleniumProtocol,
35
+ GeckoProtocol,
36
+ WebDriverBidiProtocol
37
+ } from "@wdio/protocols";
38
+ import { transformCommandLogResult } from "@wdio/utils";
39
+ import { CAPABILITY_KEYS } from "@wdio/protocols";
40
+
41
+ // src/bidi/core.ts
42
+ import logger from "@wdio/logger";
43
+
44
+ // src/bidi/socket.ts
45
+ var BrowserSocket = class {
46
+ #callbacks = /* @__PURE__ */ new Set();
47
+ #ws;
48
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
49
+ constructor(wsUrl, opts) {
50
+ this.#ws = new globalThis.WebSocket(wsUrl);
51
+ this.#ws.onmessage = this.handleMessage.bind(this);
52
+ }
53
+ handleMessage(event) {
54
+ for (const callback of this.#callbacks) {
55
+ callback(event.data);
56
+ }
57
+ }
58
+ send(data) {
59
+ this.#ws.send(data);
60
+ }
61
+ on(event, callback) {
62
+ if (event === "open") {
63
+ this.#ws.onopen = callback;
64
+ } else if (event === "close") {
65
+ this.#ws.onclose = callback;
66
+ } else if (event === "error") {
67
+ this.#ws.onerror = callback;
68
+ } else {
69
+ this.#callbacks.add(callback);
70
+ }
71
+ return this;
72
+ }
73
+ off(event, callback) {
74
+ this.#callbacks.delete(callback);
75
+ return this;
76
+ }
77
+ close() {
78
+ this.#ws.close();
79
+ }
80
+ };
81
+ var socket_default = globalThis.window ? BrowserSocket : (await import("ws")).default;
82
+
83
+ // src/bidi/core.ts
84
+ var log = logger("webdriver");
85
+ var RESPONSE_TIMEOUT = 1e3 * 60;
86
+ var BidiCore = class {
87
+ constructor(_webSocketUrl, opts) {
88
+ this._webSocketUrl = _webSocketUrl;
89
+ log.info(`Connect to webSocketUrl ${this._webSocketUrl}`);
90
+ this.#ws = new socket_default(this._webSocketUrl, opts);
91
+ this.#ws.on("message", this.#handleResponse.bind(this));
92
+ }
93
+ #id = 0;
94
+ #ws;
95
+ #isConnected = false;
96
+ #pendingCommands = /* @__PURE__ */ new Map();
97
+ async connect() {
98
+ if (process.env.VITEST_WORKER_ID && this._webSocketUrl === "ws://webdriver.io") {
99
+ return;
100
+ }
101
+ return new Promise((resolve) => this.#ws.on("open", () => {
102
+ log.info("Connected session to Bidi protocol");
103
+ this.#isConnected = true;
104
+ resolve();
105
+ }));
106
+ }
107
+ get socket() {
108
+ return this.#ws;
109
+ }
110
+ get isConnected() {
111
+ return this.#isConnected;
112
+ }
113
+ /**
114
+ * for testing purposes only
115
+ * @internal
116
+ */
117
+ get __handleResponse() {
118
+ return this.#handleResponse.bind(this);
119
+ }
120
+ #handleResponse(data) {
121
+ try {
122
+ const payload = JSON.parse(data.toString());
123
+ if (!payload.id) {
124
+ return;
125
+ }
126
+ log.debug("BIDI RESULT", data.toString());
127
+ const resolve = this.#pendingCommands.get(payload.id);
128
+ if (!resolve) {
129
+ log.error(`Couldn't resolve command with id ${payload.id}`);
130
+ return;
131
+ }
132
+ this.#pendingCommands.delete(payload.id);
133
+ resolve(payload);
134
+ } catch (err) {
135
+ const error = err instanceof Error ? err : new Error(`Failed parse message: ${String(err)}`);
136
+ log.error(`Failed parse message: ${error.message}`);
137
+ }
138
+ }
139
+ async send(params) {
140
+ const id = this.sendAsync(params);
141
+ const failError = new Error(`WebDriver Bidi command "${params.method}" failed`);
142
+ const payload = await new Promise((resolve, reject) => {
143
+ const t = setTimeout(() => {
144
+ reject(new Error(`Command ${params.method} with id ${id} (with the following parameter: ${JSON.stringify(params.params)}) timed out`));
145
+ this.#pendingCommands.delete(id);
146
+ }, RESPONSE_TIMEOUT);
147
+ this.#pendingCommands.set(id, (payload2) => {
148
+ clearTimeout(t);
149
+ resolve(payload2);
150
+ });
151
+ });
152
+ if (payload.error) {
153
+ failError.message += ` with error: ${payload.error} - ${payload.message}`;
154
+ if (payload.stacktrace) {
155
+ const driverStack = payload.stacktrace.split("\n").filter(Boolean).map((line) => ` at ${line}`).join("\n");
156
+ failError.stack += `
157
+
158
+ Driver Stack:
159
+ ${driverStack}`;
160
+ }
161
+ throw failError;
162
+ }
163
+ return payload;
164
+ }
165
+ sendAsync(params) {
166
+ if (!this.#isConnected) {
167
+ throw new Error("No connection to WebDriver Bidi was established");
65
168
  }
169
+ log.info("BIDI COMMAND", ...parseBidiCommand(params));
170
+ const id = ++this.#id;
171
+ this.#ws.send(JSON.stringify({ id, ...params }));
172
+ return id;
173
+ }
174
+ };
175
+ function parseBidiCommand(params) {
176
+ const commandName = params.method;
177
+ if (commandName === "script.addPreloadScript") {
178
+ const param = params.params;
179
+ const logString = `{ functionDeclaration: <PreloadScript[${new TextEncoder().encode(param.functionDeclaration).length} bytes]>, contexts: ${JSON.stringify(param.contexts)} }`;
180
+ return [commandName, logString];
181
+ } else if (commandName === "script.callFunction") {
182
+ const param = params.params;
183
+ const logString = JSON.stringify({
184
+ ...param,
185
+ functionDeclaration: `<Function[${new TextEncoder().encode(param.functionDeclaration).length} bytes]>`
186
+ });
187
+ return [commandName, logString];
188
+ }
189
+ return [commandName, JSON.stringify(params.params)];
190
+ }
191
+
192
+ // src/bidi/handler.ts
193
+ var BidiHandler = class extends BidiCore {
194
+ /**
195
+ * WebDriver Bidi command to send command method "session.status" with parameters.
196
+ * @url https://w3c.github.io/webdriver-bidi/#command-session-status
197
+ * @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-session-status | command parameter}
198
+ * @returns `Promise<local.SessionStatusResult>`
199
+ **/
200
+ async sessionStatus(params) {
201
+ const result = await this.send({
202
+ method: "session.status",
203
+ params
204
+ });
205
+ return result.result;
206
+ }
207
+ /**
208
+ * WebDriver Bidi command to send command method "session.new" with parameters.
209
+ * @url https://w3c.github.io/webdriver-bidi/#command-session-new
210
+ * @param params `remote.SessionNewParameters` {@link https://w3c.github.io/webdriver-bidi/#command-session-new | command parameter}
211
+ * @returns `Promise<local.SessionNewResult>`
212
+ **/
213
+ async sessionNew(params) {
214
+ const result = await this.send({
215
+ method: "session.new",
216
+ params
217
+ });
218
+ return result.result;
219
+ }
220
+ /**
221
+ * WebDriver Bidi command to send command method "session.end" with parameters.
222
+ * @url https://w3c.github.io/webdriver-bidi/#command-session-end
223
+ * @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-session-end | command parameter}
224
+ * @returns `Promise<local.EmptyResult>`
225
+ **/
226
+ async sessionEnd(params) {
227
+ const result = await this.send({
228
+ method: "session.end",
229
+ params
230
+ });
231
+ return result.result;
232
+ }
233
+ /**
234
+ * WebDriver Bidi command to send command method "session.subscribe" with parameters.
235
+ * @url https://w3c.github.io/webdriver-bidi/#command-session-subscribe
236
+ * @param params `remote.SessionSubscriptionRequest` {@link https://w3c.github.io/webdriver-bidi/#command-session-subscribe | command parameter}
237
+ * @returns `Promise<local.EmptyResult>`
238
+ **/
239
+ async sessionSubscribe(params) {
240
+ const result = await this.send({
241
+ method: "session.subscribe",
242
+ params
243
+ });
244
+ return result.result;
245
+ }
246
+ /**
247
+ * WebDriver Bidi command to send command method "session.unsubscribe" with parameters.
248
+ * @url https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe
249
+ * @param params `remote.SessionSubscriptionRequest` {@link https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe | command parameter}
250
+ * @returns `Promise<local.EmptyResult>`
251
+ **/
252
+ async sessionUnsubscribe(params) {
253
+ const result = await this.send({
254
+ method: "session.unsubscribe",
255
+ params
256
+ });
257
+ return result.result;
258
+ }
259
+ /**
260
+ * WebDriver Bidi command to send command method "browser.close" with parameters.
261
+ * @url https://w3c.github.io/webdriver-bidi/#command-browser-close
262
+ * @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-close | command parameter}
263
+ * @returns `Promise<local.EmptyResult>`
264
+ **/
265
+ async browserClose(params) {
266
+ const result = await this.send({
267
+ method: "browser.close",
268
+ params
269
+ });
270
+ return result.result;
271
+ }
272
+ /**
273
+ * WebDriver Bidi command to send command method "browser.createUserContext" with parameters.
274
+ * @url https://w3c.github.io/webdriver-bidi/#command-browser-createUserContext
275
+ * @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-createUserContext | command parameter}
276
+ * @returns `Promise<local.BrowserCreateUserContextResult>`
277
+ **/
278
+ async browserCreateUserContext(params) {
279
+ const result = await this.send({
280
+ method: "browser.createUserContext",
281
+ params
282
+ });
283
+ return result.result;
284
+ }
285
+ /**
286
+ * WebDriver Bidi command to send command method "browser.getUserContexts" with parameters.
287
+ * @url https://w3c.github.io/webdriver-bidi/#command-browser-getUserContexts
288
+ * @param params `remote.EmptyParams` {@link https://w3c.github.io/webdriver-bidi/#command-browser-getUserContexts | command parameter}
289
+ * @returns `Promise<local.BrowserGetUserContextsResult>`
290
+ **/
291
+ async browserGetUserContexts(params) {
292
+ const result = await this.send({
293
+ method: "browser.getUserContexts",
294
+ params
295
+ });
296
+ return result.result;
297
+ }
298
+ /**
299
+ * WebDriver Bidi command to send command method "browser.removeUserContext" with parameters.
300
+ * @url https://w3c.github.io/webdriver-bidi/#command-browser-removeUserContext
301
+ * @param params `remote.BrowserRemoveUserContextParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browser-removeUserContext | command parameter}
302
+ * @returns `Promise<local.EmptyResult>`
303
+ **/
304
+ async browserRemoveUserContext(params) {
305
+ const result = await this.send({
306
+ method: "browser.removeUserContext",
307
+ params
308
+ });
309
+ return result.result;
310
+ }
311
+ /**
312
+ * WebDriver Bidi command to send command method "browsingContext.activate" with parameters.
313
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-activate
314
+ * @param params `remote.BrowsingContextActivateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-activate | command parameter}
315
+ * @returns `Promise<local.EmptyResult>`
316
+ **/
317
+ async browsingContextActivate(params) {
318
+ const result = await this.send({
319
+ method: "browsingContext.activate",
320
+ params
321
+ });
322
+ return result.result;
323
+ }
324
+ /**
325
+ * WebDriver Bidi command to send command method "browsingContext.captureScreenshot" with parameters.
326
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-captureScreenshot
327
+ * @param params `remote.BrowsingContextCaptureScreenshotParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-captureScreenshot | command parameter}
328
+ * @returns `Promise<local.BrowsingContextCaptureScreenshotResult>`
329
+ **/
330
+ async browsingContextCaptureScreenshot(params) {
331
+ const result = await this.send({
332
+ method: "browsingContext.captureScreenshot",
333
+ params
334
+ });
335
+ return result.result;
336
+ }
337
+ /**
338
+ * WebDriver Bidi command to send command method "browsingContext.close" with parameters.
339
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-close
340
+ * @param params `remote.BrowsingContextCloseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-close | command parameter}
341
+ * @returns `Promise<local.EmptyResult>`
342
+ **/
343
+ async browsingContextClose(params) {
344
+ const result = await this.send({
345
+ method: "browsingContext.close",
346
+ params
347
+ });
348
+ return result.result;
349
+ }
350
+ /**
351
+ * WebDriver Bidi command to send command method "browsingContext.create" with parameters.
352
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-create
353
+ * @param params `remote.BrowsingContextCreateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-create | command parameter}
354
+ * @returns `Promise<local.BrowsingContextCreateResult>`
355
+ **/
356
+ async browsingContextCreate(params) {
357
+ const result = await this.send({
358
+ method: "browsingContext.create",
359
+ params
360
+ });
361
+ return result.result;
362
+ }
363
+ /**
364
+ * WebDriver Bidi command to send command method "browsingContext.getTree" with parameters.
365
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-getTree
366
+ * @param params `remote.BrowsingContextGetTreeParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-getTree | command parameter}
367
+ * @returns `Promise<local.BrowsingContextGetTreeResult>`
368
+ **/
369
+ async browsingContextGetTree(params) {
370
+ const result = await this.send({
371
+ method: "browsingContext.getTree",
372
+ params
373
+ });
374
+ return result.result;
375
+ }
376
+ /**
377
+ * WebDriver Bidi command to send command method "browsingContext.handleUserPrompt" with parameters.
378
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-handleUserPrompt
379
+ * @param params `remote.BrowsingContextHandleUserPromptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-handleUserPrompt | command parameter}
380
+ * @returns `Promise<local.EmptyResult>`
381
+ **/
382
+ async browsingContextHandleUserPrompt(params) {
383
+ const result = await this.send({
384
+ method: "browsingContext.handleUserPrompt",
385
+ params
386
+ });
387
+ return result.result;
388
+ }
389
+ /**
390
+ * WebDriver Bidi command to send command method "browsingContext.locateNodes" with parameters.
391
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-locateNodes
392
+ * @param params `remote.BrowsingContextLocateNodesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-locateNodes | command parameter}
393
+ * @returns `Promise<local.BrowsingContextLocateNodesResult>`
394
+ **/
395
+ async browsingContextLocateNodes(params) {
396
+ const result = await this.send({
397
+ method: "browsingContext.locateNodes",
398
+ params
399
+ });
400
+ return result.result;
401
+ }
402
+ /**
403
+ * WebDriver Bidi command to send command method "browsingContext.navigate" with parameters.
404
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-navigate
405
+ * @param params `remote.BrowsingContextNavigateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-navigate | command parameter}
406
+ * @returns `Promise<local.BrowsingContextNavigateResult>`
407
+ **/
408
+ async browsingContextNavigate(params) {
409
+ const result = await this.send({
410
+ method: "browsingContext.navigate",
411
+ params
412
+ });
413
+ return result.result;
414
+ }
415
+ /**
416
+ * WebDriver Bidi command to send command method "browsingContext.print" with parameters.
417
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-print
418
+ * @param params `remote.BrowsingContextPrintParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-print | command parameter}
419
+ * @returns `Promise<local.BrowsingContextPrintResult>`
420
+ **/
421
+ async browsingContextPrint(params) {
422
+ const result = await this.send({
423
+ method: "browsingContext.print",
424
+ params
425
+ });
426
+ return result.result;
427
+ }
428
+ /**
429
+ * WebDriver Bidi command to send command method "browsingContext.reload" with parameters.
430
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-reload
431
+ * @param params `remote.BrowsingContextReloadParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-reload | command parameter}
432
+ * @returns `Promise<local.EmptyResult>`
433
+ **/
434
+ async browsingContextReload(params) {
435
+ const result = await this.send({
436
+ method: "browsingContext.reload",
437
+ params
438
+ });
439
+ return result.result;
440
+ }
441
+ /**
442
+ * WebDriver Bidi command to send command method "browsingContext.setViewport" with parameters.
443
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-setViewport
444
+ * @param params `remote.BrowsingContextSetViewportParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-setViewport | command parameter}
445
+ * @returns `Promise<local.EmptyResult>`
446
+ **/
447
+ async browsingContextSetViewport(params) {
448
+ const result = await this.send({
449
+ method: "browsingContext.setViewport",
450
+ params
451
+ });
452
+ return result.result;
453
+ }
454
+ /**
455
+ * WebDriver Bidi command to send command method "browsingContext.traverseHistory" with parameters.
456
+ * @url https://w3c.github.io/webdriver-bidi/#command-browsingContext-traverseHistory
457
+ * @param params `remote.BrowsingContextTraverseHistoryParameters` {@link https://w3c.github.io/webdriver-bidi/#command-browsingContext-traverseHistory | command parameter}
458
+ * @returns `Promise<local.BrowsingContextTraverseHistoryResult>`
459
+ **/
460
+ async browsingContextTraverseHistory(params) {
461
+ const result = await this.send({
462
+ method: "browsingContext.traverseHistory",
463
+ params
464
+ });
465
+ return result.result;
466
+ }
467
+ /**
468
+ * WebDriver Bidi command to send command method "network.addIntercept" with parameters.
469
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-addIntercept
470
+ * @param params `remote.NetworkAddInterceptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-addIntercept | command parameter}
471
+ * @returns `Promise<local.NetworkAddInterceptResult>`
472
+ **/
473
+ async networkAddIntercept(params) {
474
+ const result = await this.send({
475
+ method: "network.addIntercept",
476
+ params
477
+ });
478
+ return result.result;
479
+ }
480
+ /**
481
+ * WebDriver Bidi command to send command method "network.continueRequest" with parameters.
482
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-continueRequest
483
+ * @param params `remote.NetworkContinueRequestParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueRequest | command parameter}
484
+ * @returns `Promise<local.EmptyResult>`
485
+ **/
486
+ async networkContinueRequest(params) {
487
+ const result = await this.send({
488
+ method: "network.continueRequest",
489
+ params
490
+ });
491
+ return result.result;
492
+ }
493
+ /**
494
+ * WebDriver Bidi command to send command method "network.continueResponse" with parameters.
495
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-continueResponse
496
+ * @param params `remote.NetworkContinueResponseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueResponse | command parameter}
497
+ * @returns `Promise<local.EmptyResult>`
498
+ **/
499
+ async networkContinueResponse(params) {
500
+ const result = await this.send({
501
+ method: "network.continueResponse",
502
+ params
503
+ });
504
+ return result.result;
505
+ }
506
+ /**
507
+ * WebDriver Bidi command to send command method "network.continueWithAuth" with parameters.
508
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-continueWithAuth
509
+ * @param params `remote.NetworkContinueWithAuthParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-continueWithAuth | command parameter}
510
+ * @returns `Promise<local.EmptyResult>`
511
+ **/
512
+ async networkContinueWithAuth(params) {
513
+ const result = await this.send({
514
+ method: "network.continueWithAuth",
515
+ params
516
+ });
517
+ return result.result;
518
+ }
519
+ /**
520
+ * WebDriver Bidi command to send command method "network.failRequest" with parameters.
521
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-failRequest
522
+ * @param params `remote.NetworkFailRequestParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-failRequest | command parameter}
523
+ * @returns `Promise<local.EmptyResult>`
524
+ **/
525
+ async networkFailRequest(params) {
526
+ const result = await this.send({
527
+ method: "network.failRequest",
528
+ params
529
+ });
530
+ return result.result;
531
+ }
532
+ /**
533
+ * WebDriver Bidi command to send command method "network.provideResponse" with parameters.
534
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-provideResponse
535
+ * @param params `remote.NetworkProvideResponseParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-provideResponse | command parameter}
536
+ * @returns `Promise<local.EmptyResult>`
537
+ **/
538
+ async networkProvideResponse(params) {
539
+ const result = await this.send({
540
+ method: "network.provideResponse",
541
+ params
542
+ });
543
+ return result.result;
544
+ }
545
+ /**
546
+ * WebDriver Bidi command to send command method "network.removeIntercept" with parameters.
547
+ * @url https://w3c.github.io/webdriver-bidi/#command-network-removeIntercept
548
+ * @param params `remote.NetworkRemoveInterceptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-network-removeIntercept | command parameter}
549
+ * @returns `Promise<local.EmptyResult>`
550
+ **/
551
+ async networkRemoveIntercept(params) {
552
+ const result = await this.send({
553
+ method: "network.removeIntercept",
554
+ params
555
+ });
556
+ return result.result;
557
+ }
558
+ /**
559
+ * WebDriver Bidi command to send command method "script.addPreloadScript" with parameters.
560
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-addPreloadScript
561
+ * @param params `remote.ScriptAddPreloadScriptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-addPreloadScript | command parameter}
562
+ * @returns `Promise<local.ScriptAddPreloadScriptResult>`
563
+ **/
564
+ async scriptAddPreloadScript(params) {
565
+ const result = await this.send({
566
+ method: "script.addPreloadScript",
567
+ params
568
+ });
569
+ return result.result;
570
+ }
571
+ /**
572
+ * WebDriver Bidi command to send command method "script.disown" with parameters.
573
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-disown
574
+ * @param params `remote.ScriptDisownParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-disown | command parameter}
575
+ * @returns `Promise<local.EmptyResult>`
576
+ **/
577
+ async scriptDisown(params) {
578
+ const result = await this.send({
579
+ method: "script.disown",
580
+ params
581
+ });
582
+ return result.result;
583
+ }
584
+ /**
585
+ * WebDriver Bidi command to send command method "script.callFunction" with parameters.
586
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-callFunction
587
+ * @param params `remote.ScriptCallFunctionParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-callFunction | command parameter}
588
+ * @returns `Promise<local.EmptyResult>`
589
+ **/
590
+ async scriptCallFunction(params) {
591
+ const result = await this.send({
592
+ method: "script.callFunction",
593
+ params
594
+ });
595
+ return result.result;
596
+ }
597
+ /**
598
+ * WebDriver Bidi command to send command method "script.evaluate" with parameters.
599
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-evaluate
600
+ * @param params `remote.ScriptEvaluateParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-evaluate | command parameter}
601
+ * @returns `Promise<local.ScriptEvaluateResult>`
602
+ **/
603
+ async scriptEvaluate(params) {
604
+ const result = await this.send({
605
+ method: "script.evaluate",
606
+ params
607
+ });
608
+ return result.result;
609
+ }
610
+ /**
611
+ * WebDriver Bidi command to send command method "script.getRealms" with parameters.
612
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-getRealms
613
+ * @param params `remote.ScriptGetRealmsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-getRealms | command parameter}
614
+ * @returns `Promise<local.ScriptGetRealmsResult>`
615
+ **/
616
+ async scriptGetRealms(params) {
617
+ const result = await this.send({
618
+ method: "script.getRealms",
619
+ params
620
+ });
621
+ return result.result;
622
+ }
623
+ /**
624
+ * WebDriver Bidi command to send command method "script.removePreloadScript" with parameters.
625
+ * @url https://w3c.github.io/webdriver-bidi/#command-script-removePreloadScript
626
+ * @param params `remote.ScriptRemovePreloadScriptParameters` {@link https://w3c.github.io/webdriver-bidi/#command-script-removePreloadScript | command parameter}
627
+ * @returns `Promise<local.EmptyResult>`
628
+ **/
629
+ async scriptRemovePreloadScript(params) {
630
+ const result = await this.send({
631
+ method: "script.removePreloadScript",
632
+ params
633
+ });
634
+ return result.result;
635
+ }
636
+ /**
637
+ * WebDriver Bidi command to send command method "storage.getCookies" with parameters.
638
+ * @url https://w3c.github.io/webdriver-bidi/#command-storage-getCookies
639
+ * @param params `remote.StorageGetCookiesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-getCookies | command parameter}
640
+ * @returns `Promise<local.StorageGetCookiesResult>`
641
+ **/
642
+ async storageGetCookies(params) {
643
+ const result = await this.send({
644
+ method: "storage.getCookies",
645
+ params
646
+ });
647
+ return result.result;
648
+ }
649
+ /**
650
+ * WebDriver Bidi command to send command method "storage.setCookie" with parameters.
651
+ * @url https://w3c.github.io/webdriver-bidi/#command-storage-setCookie
652
+ * @param params `remote.StorageSetCookieParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-setCookie | command parameter}
653
+ * @returns `Promise<local.StorageSetCookieResult>`
654
+ **/
655
+ async storageSetCookie(params) {
656
+ const result = await this.send({
657
+ method: "storage.setCookie",
658
+ params
659
+ });
660
+ return result.result;
661
+ }
662
+ /**
663
+ * WebDriver Bidi command to send command method "storage.deleteCookies" with parameters.
664
+ * @url https://w3c.github.io/webdriver-bidi/#command-storage-deleteCookies
665
+ * @param params `remote.StorageDeleteCookiesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-storage-deleteCookies | command parameter}
666
+ * @returns `Promise<local.StorageDeleteCookiesResult>`
667
+ **/
668
+ async storageDeleteCookies(params) {
669
+ const result = await this.send({
670
+ method: "storage.deleteCookies",
671
+ params
672
+ });
673
+ return result.result;
674
+ }
675
+ /**
676
+ * WebDriver Bidi command to send command method "input.performActions" with parameters.
677
+ * @url https://w3c.github.io/webdriver-bidi/#command-input-performActions
678
+ * @param params `remote.InputPerformActionsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-performActions | command parameter}
679
+ * @returns `Promise<local.EmptyResult>`
680
+ **/
681
+ async inputPerformActions(params) {
682
+ const result = await this.send({
683
+ method: "input.performActions",
684
+ params
685
+ });
686
+ return result.result;
687
+ }
688
+ /**
689
+ * WebDriver Bidi command to send command method "input.releaseActions" with parameters.
690
+ * @url https://w3c.github.io/webdriver-bidi/#command-input-releaseActions
691
+ * @param params `remote.InputReleaseActionsParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-releaseActions | command parameter}
692
+ * @returns `Promise<local.EmptyResult>`
693
+ **/
694
+ async inputReleaseActions(params) {
695
+ const result = await this.send({
696
+ method: "input.releaseActions",
697
+ params
698
+ });
699
+ return result.result;
700
+ }
701
+ /**
702
+ * WebDriver Bidi command to send command method "input.setFiles" with parameters.
703
+ * @url https://w3c.github.io/webdriver-bidi/#command-input-setFiles
704
+ * @param params `remote.InputSetFilesParameters` {@link https://w3c.github.io/webdriver-bidi/#command-input-setFiles | command parameter}
705
+ * @returns `Promise<local.EmptyResult>`
706
+ **/
707
+ async inputSetFiles(params) {
708
+ const result = await this.send({
709
+ method: "input.setFiles",
710
+ params
711
+ });
712
+ return result.result;
713
+ }
714
+ };
715
+
716
+ // src/constants.ts
717
+ import os from "node:os";
718
+ var DEFAULTS = {
719
+ /**
720
+ * protocol of automation driver
721
+ */
722
+ protocol: {
723
+ type: "string",
724
+ default: "http",
725
+ match: /(http|https)/
726
+ },
727
+ /**
728
+ * hostname of automation driver
729
+ */
730
+ hostname: {
731
+ type: "string",
732
+ default: "localhost"
733
+ },
734
+ /**
735
+ * port of automation driver
736
+ */
737
+ port: {
738
+ type: "number"
739
+ },
740
+ /**
741
+ * path to WebDriver endpoints
742
+ */
743
+ path: {
744
+ type: "string",
745
+ validate: (path2) => {
746
+ if (!path2.startsWith("/")) {
747
+ throw new TypeError('The option "path" needs to start with a "/"');
748
+ }
749
+ return true;
750
+ },
751
+ default: "/"
752
+ },
753
+ /**
754
+ * A key-value store of query parameters to be added to every selenium request
755
+ */
756
+ queryParams: {
757
+ type: "object"
758
+ },
759
+ /**
760
+ * cloud user if applicable
761
+ */
762
+ user: {
763
+ type: "string"
764
+ },
765
+ /**
766
+ * access key to user
767
+ */
768
+ key: {
769
+ type: "string"
770
+ },
771
+ /**
772
+ * capability of WebDriver session
773
+ */
774
+ capabilities: {
775
+ type: "object",
776
+ required: true
777
+ },
778
+ /**
779
+ * Level of logging verbosity
780
+ */
781
+ logLevel: {
782
+ type: "string",
783
+ default: "info",
784
+ match: /(trace|debug|info|warn|error|silent)/
785
+ },
786
+ /**
787
+ * directory for log files
788
+ */
789
+ outputDir: {
790
+ type: "string"
791
+ },
792
+ /**
793
+ * Timeout for any WebDriver request to a driver or grid
794
+ */
795
+ connectionRetryTimeout: {
796
+ type: "number",
797
+ default: 12e4
798
+ },
799
+ /**
800
+ * Count of request retries to the Selenium server
801
+ */
802
+ connectionRetryCount: {
803
+ type: "number",
804
+ default: 3
805
+ },
806
+ /**
807
+ * Override default agent
808
+ */
809
+ logLevels: {
810
+ type: "object"
811
+ },
812
+ /**
813
+ * Pass custom headers
814
+ */
815
+ headers: {
816
+ type: "object"
817
+ },
818
+ /**
819
+ * Function transforming the request options before the request is made
820
+ */
821
+ transformRequest: {
822
+ type: "function",
823
+ default: (requestOptions) => requestOptions
824
+ },
825
+ /**
826
+ * Function transforming the response object after it is received
827
+ */
828
+ transformResponse: {
829
+ type: "function",
830
+ default: (response) => response
831
+ },
832
+ /**
833
+ * Appium direct connect options server (https://appiumpro.com/editions/86-connecting-directly-to-appium-hosts-in-distributed-environments)
834
+ * Whether to allow direct connect caps to adjust endpoint details (Appium only)
835
+ */
836
+ enableDirectConnect: {
837
+ type: "boolean",
838
+ default: true
839
+ },
840
+ /**
841
+ * Whether it requires SSL certificates to be valid in HTTP/s requests
842
+ * for an environment which cannot get process environment well.
843
+ */
844
+ strictSSL: {
845
+ type: "boolean",
846
+ default: true
847
+ },
848
+ /**
849
+ * The path to the root of the cache directory. This directory is used to store all drivers that are downloaded
850
+ * when attempting to start a session.
851
+ */
852
+ cacheDir: {
853
+ type: "string",
854
+ default: process.env.WEBDRIVER_CACHE_DIR || os.tmpdir()
855
+ }
856
+ };
857
+ var REG_EXPS = {
858
+ commandName: /.*\/session\/[0-9a-f-]+\/(.*)/,
859
+ execFn: /return \(([\s\S]*)\)\.apply\(null, arguments\)/
860
+ };
861
+ var ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf";
862
+ var SHADOW_ELEMENT_KEY = "shadow-6066-11e4-a52e-4f735466cecf";
863
+
864
+ // src/utils.ts
865
+ var log2 = logger2("webdriver");
866
+ var deepmerge = deepmergeCustom({ mergeArrays: false });
867
+ var BROWSER_DRIVER_ERRORS = [
868
+ "unknown command: wd/hub/session",
869
+ // chromedriver
870
+ "HTTP method not allowed",
871
+ // geckodriver
872
+ "'POST /wd/hub/session' was not found.",
873
+ // safaridriver
874
+ "Command not found"
875
+ // iedriver
876
+ ];
877
+ async function startWebDriverSession(params) {
878
+ if (params.capabilities) {
879
+ const extensionCaps = Object.keys(params.capabilities).filter((cap) => cap.includes(":"));
880
+ const invalidWebDriverCaps = Object.keys(params.capabilities).filter((cap) => !CAPABILITY_KEYS.includes(cap) && !cap.includes(":"));
881
+ if (extensionCaps.length && invalidWebDriverCaps.length) {
882
+ throw new Error(
883
+ `Invalid or unsupported WebDriver capabilities found ("${invalidWebDriverCaps.join('", "')}"). Ensure to only use valid W3C WebDriver capabilities (see https://w3c.github.io/webdriver/#capabilities).If you run your tests on a remote vendor, like Sauce Labs or BrowserStack, make sure that you put them into vendor specific capabilities, e.g. "sauce:options" or "bstack:options". Please reach out to your vendor support team if you have further questions.`
884
+ );
885
+ }
886
+ }
887
+ const [w3cCaps, jsonwpCaps] = params.capabilities && "alwaysMatch" in params.capabilities ? [params.capabilities, params.capabilities.alwaysMatch] : [{ alwaysMatch: params.capabilities, firstMatch: [{}] }, params.capabilities];
888
+ if (!w3cCaps.alwaysMatch["wdio:enforceWebDriverClassic"] && typeof w3cCaps.alwaysMatch.browserName === "string" && w3cCaps.alwaysMatch.browserName !== "safari") {
889
+ w3cCaps.alwaysMatch.webSocketUrl = true;
890
+ }
891
+ if (!jsonwpCaps["wdio:enforceWebDriverClassic"] && typeof jsonwpCaps.browserName === "string" && jsonwpCaps.browserName !== "safari") {
892
+ jsonwpCaps.webSocketUrl = true;
893
+ }
894
+ const sessionRequest = new FetchRequest(
895
+ "POST",
896
+ "/session",
897
+ {
898
+ capabilities: w3cCaps,
899
+ // W3C compliant
900
+ desiredCapabilities: jsonwpCaps
901
+ // JSONWP compliant
902
+ }
903
+ );
904
+ let response;
905
+ try {
906
+ response = await sessionRequest.makeRequest(params);
907
+ } catch (err) {
908
+ log2.error(err);
909
+ const message = getSessionError(err, params);
910
+ throw new Error("Failed to create session.\n" + message);
911
+ }
912
+ const sessionId = response.value.sessionId || response.sessionId;
913
+ params.capabilities = response.value.capabilities || response.value;
914
+ return { sessionId, capabilities: params.capabilities };
915
+ }
916
+ function isSuccessfulResponse(statusCode, body) {
917
+ if (!body || typeof body.value === "undefined") {
918
+ log2.debug("request failed due to missing body");
919
+ return false;
920
+ }
921
+ if (body.status === 7 && body.value && body.value.message && (body.value.message.toLowerCase().startsWith("no such element") || // Appium
922
+ body.value.message === "An element could not be located on the page using the given search parameters." || // Internet Explorer
923
+ body.value.message.toLowerCase().startsWith("unable to find element"))) {
924
+ return true;
925
+ }
926
+ if (body.status && body.status !== 0) {
927
+ log2.debug(`request failed due to status ${body.status}`);
928
+ return false;
929
+ }
930
+ const hasErrorResponse = body.value && (body.value.error || body.value.stackTrace || body.value.stacktrace);
931
+ if (statusCode === 200 && !hasErrorResponse) {
932
+ return true;
933
+ }
934
+ if (statusCode === 404 && body.value && body.value.error === "no such element") {
935
+ return true;
936
+ }
937
+ if (hasErrorResponse) {
938
+ log2.debug("request failed due to response error:", body.value.error);
939
+ return false;
940
+ }
941
+ return true;
942
+ }
943
+ function getPrototype({ isW3C, isChromium, isFirefox, isMobile, isSauce, isSeleniumStandalone }) {
944
+ const prototype = {};
945
+ const ProtocolCommands = deepmerge(
946
+ /**
947
+ * if mobile apply JSONWire and WebDriver protocol because
948
+ * some legacy JSONWire commands are still used in Appium
949
+ * (e.g. set/get geolocation)
950
+ */
951
+ isMobile ? deepmerge(AppiumProtocol, WebDriverProtocol) : WebDriverProtocol,
952
+ /**
953
+ * enable Bidi protocol for W3C sessions
954
+ */
955
+ isW3C ? WebDriverBidiProtocol : {},
956
+ /**
957
+ * only apply mobile protocol if session is actually for mobile
958
+ */
959
+ isMobile ? deepmerge(MJsonWProtocol, AppiumProtocol) : {},
960
+ /**
961
+ * only apply special Chromium commands if session is using Chrome or Edge
962
+ */
963
+ isChromium ? ChromiumProtocol : {},
964
+ /**
965
+ * only apply special Firefox commands if session is using Firefox
966
+ */
967
+ isFirefox ? GeckoProtocol : {},
66
968
  /**
67
- * allows user to attach to existing sessions
969
+ * only Sauce Labs specific vendor commands
68
970
  */
69
- static attachToSession(options, modifier, userPrototype = {}, commandWrapper) {
70
- if (!options || typeof options.sessionId !== 'string') {
71
- throw new Error('sessionId is required to attach to existing session');
971
+ isSauce ? SauceLabsProtocol : {},
972
+ /**
973
+ * only apply special commands when running tests using
974
+ * Selenium Grid or Selenium Standalone server
975
+ */
976
+ isSeleniumStandalone ? SeleniumProtocol : {},
977
+ {}
978
+ );
979
+ for (const [endpoint, methods] of Object.entries(ProtocolCommands)) {
980
+ for (const [method, commandData] of Object.entries(methods)) {
981
+ prototype[commandData.command] = { value: command_default(method, endpoint, commandData, isSeleniumStandalone) };
982
+ }
983
+ }
984
+ return prototype;
985
+ }
986
+ function getErrorFromResponseBody(body, requestOptions) {
987
+ if (!body) {
988
+ return new Error("Response has empty body");
989
+ }
990
+ if (typeof body === "string" && body.length) {
991
+ return new Error(body);
992
+ }
993
+ if (typeof body !== "object") {
994
+ return new Error("Unknown error");
995
+ }
996
+ return new CustomRequestError(body, requestOptions);
997
+ }
998
+ var CustomRequestError = class _CustomRequestError extends Error {
999
+ constructor(body, requestOptions) {
1000
+ const errorObj = body.value || body;
1001
+ let errorMessage = errorObj.message || errorObj.error || errorObj.class || "unknown error";
1002
+ if (typeof errorMessage === "string" && errorMessage.includes("invalid locator")) {
1003
+ errorMessage = `The selector "${requestOptions.value}" used with strategy "${requestOptions.using}" is invalid!`;
1004
+ }
1005
+ super(errorMessage);
1006
+ if (errorObj.error) {
1007
+ this.name = errorObj.error;
1008
+ } else if (errorMessage && errorMessage.includes("stale element reference")) {
1009
+ this.name = "stale element reference";
1010
+ } else {
1011
+ this.name = errorObj.name || "WebDriver Error";
1012
+ }
1013
+ Error.captureStackTrace(this, _CustomRequestError);
1014
+ }
1015
+ };
1016
+ function getEnvironmentVars({ isW3C, isMobile, isIOS, isAndroid, isFirefox, isSauce, isSeleniumStandalone, isBidi, isChromium }) {
1017
+ return {
1018
+ isW3C: { value: isW3C },
1019
+ isMobile: { value: isMobile },
1020
+ isIOS: { value: isIOS },
1021
+ isAndroid: { value: isAndroid },
1022
+ isFirefox: { value: isFirefox },
1023
+ isSauce: { value: isSauce },
1024
+ isSeleniumStandalone: { value: isSeleniumStandalone },
1025
+ isBidi: { value: isBidi },
1026
+ isChromium: { value: isChromium }
1027
+ };
1028
+ }
1029
+ function setupDirectConnect(client) {
1030
+ const capabilities = client.capabilities;
1031
+ const directConnectProtocol = capabilities["appium:directConnectProtocol"];
1032
+ const directConnectHost = capabilities["appium:directConnectHost"];
1033
+ const directConnectPath = capabilities["appium:directConnectPath"];
1034
+ const directConnectPort = capabilities["appium:directConnectPort"];
1035
+ if (directConnectProtocol && directConnectHost && directConnectPort && (directConnectPath || directConnectPath === "")) {
1036
+ log2.info(`Found direct connect information in new session response. Will connect to server at ${directConnectProtocol}://${directConnectHost}:${directConnectPort}${directConnectPath}`);
1037
+ client.options.protocol = directConnectProtocol;
1038
+ client.options.hostname = directConnectHost;
1039
+ client.options.port = directConnectPort;
1040
+ client.options.path = directConnectPath;
1041
+ }
1042
+ }
1043
+ var getSessionError = (err, params = {}) => {
1044
+ if (err.code === "ECONNREFUSED") {
1045
+ return `Unable to connect to "${params.protocol}://${params.hostname}:${params.port}${params.path}", make sure browser driver is running on that address.
1046
+ It seems like the service failed to start or is rejecting any connections.`;
1047
+ }
1048
+ if (err.message === "unhandled request") {
1049
+ return `The browser driver couldn't start the session. Make sure you have set the "path" correctly!`;
1050
+ }
1051
+ if (!err.message) {
1052
+ return "See wdio.* logs for more information.";
1053
+ }
1054
+ if (err.message.includes("Whoops! The URL specified routes to this help page.")) {
1055
+ return "It seems you are running a Selenium Standalone server and point to a wrong path. Please set `path: '/wd/hub'` in your wdio.conf.js!";
1056
+ }
1057
+ if (BROWSER_DRIVER_ERRORS.some((m) => err && err.message && err.message.includes(m))) {
1058
+ return "Make sure to set `path: '/'` in your wdio.conf.js!";
1059
+ }
1060
+ if (err.message.includes("Bad Request - Invalid Hostname") && err.message.includes("HTTP Error 400")) {
1061
+ return "Run edge driver on 127.0.0.1 instead of localhost, ex: --host=127.0.0.1, or set `hostname: 'localhost'` in your wdio.conf.js";
1062
+ }
1063
+ const w3cCapMessage = '\nMake sure to add vendor prefix like "goog:", "appium:", "moz:", etc to non W3C capabilities.\nSee more https://www.w3.org/TR/webdriver/#capabilities';
1064
+ if (err.message.includes("Illegal key values seen in w3c capabilities")) {
1065
+ return err.message + w3cCapMessage;
1066
+ }
1067
+ if (err.message === "Response has empty body") {
1068
+ return "Make sure to connect to valid hostname:port or the port is not in use.\nIf you use a grid server " + w3cCapMessage;
1069
+ }
1070
+ if (err.message.includes("failed serving request POST /wd/hub/session: Unauthorized") && params.hostname?.endsWith("saucelabs.com")) {
1071
+ return "Session request was not authorized because you either did provide a wrong access key or tried to run in a region that has not been enabled for your user. If have registered a free trial account it is connected to a specific region. Ensure this region is set in your configuration (https://webdriver.io/docs/options.html#region).";
1072
+ }
1073
+ return err.message;
1074
+ };
1075
+ function getTimeoutError(error, requestOptions, url) {
1076
+ const cmdName = getExecCmdName(url);
1077
+ const cmdArgs = getExecCmdArgs(requestOptions);
1078
+ const cmdInfoMsg = `when running "${cmdName}" with method "${requestOptions.method}"`;
1079
+ const cmdArgsMsg = cmdArgs ? ` and args ${cmdArgs}` : "";
1080
+ const timeoutErr = new Error(`${error.message} ${cmdInfoMsg}${cmdArgsMsg}`);
1081
+ return Object.assign(timeoutErr, error);
1082
+ }
1083
+ function getExecCmdName(url) {
1084
+ const { href } = url;
1085
+ const res = href.match(REG_EXPS.commandName) || [];
1086
+ return res[1] || href;
1087
+ }
1088
+ function getExecCmdArgs(requestOptions) {
1089
+ const { body: cmdJson } = requestOptions;
1090
+ if (typeof cmdJson !== "object") {
1091
+ return "";
1092
+ }
1093
+ const transformedRes = transformCommandLogResult(cmdJson);
1094
+ if (typeof transformedRes === "string") {
1095
+ return transformedRes;
1096
+ }
1097
+ if (typeof cmdJson.script === "string") {
1098
+ const scriptRes = cmdJson.script.match(REG_EXPS.execFn) || [];
1099
+ return `"${scriptRes[1] || cmdJson.script}"`;
1100
+ }
1101
+ return Object.keys(cmdJson).length ? `"${JSON.stringify(cmdJson)}"` : "";
1102
+ }
1103
+ function initiateBidi(socketUrl, strictSSL = true) {
1104
+ socketUrl = socketUrl.replace("localhost", "127.0.0.1");
1105
+ const bidiReqOpts = strictSSL ? {} : { rejectUnauthorized: false };
1106
+ const handler = new BidiHandler(socketUrl, bidiReqOpts);
1107
+ handler.connect().then(() => log2.info(`Connected to WebDriver Bidi interface at ${socketUrl}`));
1108
+ return {
1109
+ _bidiHandler: { value: handler },
1110
+ ...Object.values(WebDriverBidiProtocol).map((def) => def.socket).reduce((acc, cur) => {
1111
+ acc[cur.command] = {
1112
+ value: handler[cur.command]?.bind(handler)
1113
+ };
1114
+ return acc;
1115
+ }, {})
1116
+ };
1117
+ }
1118
+ function parseBidiMessage(data) {
1119
+ try {
1120
+ const payload = JSON.parse(data.toString());
1121
+ if (payload.type !== "event") {
1122
+ return;
1123
+ }
1124
+ this.emit(payload.method, payload.params);
1125
+ } catch (err) {
1126
+ log2.error(`Failed parse WebDriver Bidi message: ${err.message}`);
1127
+ }
1128
+ }
1129
+
1130
+ // package.json
1131
+ var package_default = {
1132
+ name: "webdriver",
1133
+ version: "9.0.0-alpha.0",
1134
+ description: "A Node.js bindings implementation for the W3C WebDriver and Mobile JSONWire Protocol",
1135
+ author: "Christian Bromann <mail@bromann.dev>",
1136
+ homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/webdriver",
1137
+ license: "MIT",
1138
+ main: "./build/index.cjs",
1139
+ type: "module",
1140
+ module: "./build/index.js",
1141
+ exports: {
1142
+ ".": {
1143
+ types: "./build/index.d.ts",
1144
+ import: "./build/index.js",
1145
+ requireSource: "./src/index.cts",
1146
+ require: "./build/index.cjs"
1147
+ }
1148
+ },
1149
+ types: "./build/index.d.ts",
1150
+ typeScriptVersion: "3.8.3",
1151
+ engines: {
1152
+ node: ">=18"
1153
+ },
1154
+ repository: {
1155
+ type: "git",
1156
+ url: "git://github.com/webdriverio/webdriverio.git",
1157
+ directory: "packages/webdriver"
1158
+ },
1159
+ keywords: [
1160
+ "webdriver"
1161
+ ],
1162
+ bugs: {
1163
+ url: "https://github.com/webdriverio/webdriverio/issues"
1164
+ },
1165
+ dependencies: {
1166
+ "@types/node": "^20.1.0",
1167
+ "@types/ws": "^8.5.3",
1168
+ "@wdio/config": "workspace:*",
1169
+ "@wdio/logger": "workspace:*",
1170
+ "@wdio/protocols": "workspace:*",
1171
+ "@wdio/types": "workspace:*",
1172
+ "@wdio/utils": "workspace:*",
1173
+ "deepmerge-ts": "^7.0.3",
1174
+ ws: "^8.8.0"
1175
+ }
1176
+ };
1177
+
1178
+ // src/request/index.ts
1179
+ var ERRORS_TO_EXCLUDE_FROM_RETRY = [
1180
+ "detached shadow root",
1181
+ "move target out of bounds"
1182
+ ];
1183
+ var RequestLibError = class extends Error {
1184
+ statusCode;
1185
+ body;
1186
+ code;
1187
+ };
1188
+ var COMMANDS_WITHOUT_RETRY = [
1189
+ findCommandPathByName("performActions")
1190
+ ];
1191
+ var DEFAULT_HEADERS = {
1192
+ "Content-Type": "application/json; charset=utf-8",
1193
+ "Connection": "keep-alive",
1194
+ "Accept": "application/json",
1195
+ "User-Agent": "webdriver/" + package_default.version
1196
+ };
1197
+ var log3 = logger3("webdriver");
1198
+ var WebDriverRequest = class extends EventEmitter {
1199
+ #requestTimeout;
1200
+ body;
1201
+ method;
1202
+ endpoint;
1203
+ isHubCommand;
1204
+ requiresSessionId;
1205
+ constructor(method, endpoint, body, isHubCommand = false) {
1206
+ super();
1207
+ this.body = body;
1208
+ this.method = method;
1209
+ this.endpoint = endpoint;
1210
+ this.isHubCommand = isHubCommand;
1211
+ this.requiresSessionId = Boolean(this.endpoint.match(/:sessionId/));
1212
+ }
1213
+ async makeRequest(options, sessionId) {
1214
+ const { url, requestOptions } = await this._createOptions(options, sessionId);
1215
+ let fullRequestOptions = Object.assign(
1216
+ { method: this.method },
1217
+ requestOptions
1218
+ );
1219
+ if (typeof options.transformRequest === "function") {
1220
+ fullRequestOptions = options.transformRequest(fullRequestOptions);
1221
+ }
1222
+ this.emit("request", fullRequestOptions);
1223
+ return this._request(url, fullRequestOptions, options.transformResponse, options.connectionRetryCount, 0);
1224
+ }
1225
+ async _createOptions(options, sessionId, isBrowser = false) {
1226
+ const controller = new AbortController();
1227
+ this.#requestTimeout = setTimeout(
1228
+ () => controller.abort(),
1229
+ options.connectionRetryTimeout || DEFAULTS.connectionRetryTimeout.default
1230
+ );
1231
+ const requestOptions = {
1232
+ signal: controller.signal
1233
+ };
1234
+ const requestHeaders = new Headers({
1235
+ ...DEFAULT_HEADERS,
1236
+ ...typeof options.headers === "object" ? options.headers : {}
1237
+ });
1238
+ const searchParams = isBrowser ? void 0 : typeof options.queryParams === "object" ? options.queryParams : void 0;
1239
+ if (this.body && (Object.keys(this.body).length || this.method === "POST")) {
1240
+ const contentLength = Buffer.byteLength(JSON.stringify(this.body), "utf8");
1241
+ requestOptions.body = this.body;
1242
+ requestHeaders.set("Content-Length", `${contentLength}`);
1243
+ }
1244
+ let endpoint = this.endpoint;
1245
+ if (this.requiresSessionId) {
1246
+ if (!sessionId) {
1247
+ throw new Error("A sessionId is required for this command");
1248
+ }
1249
+ endpoint = endpoint.replace(":sessionId", sessionId);
1250
+ }
1251
+ const url = new URL(`${options.protocol}://${options.hostname}:${options.port}${this.isHubCommand ? this.endpoint : path.join(options.path || "", endpoint)}`);
1252
+ if (searchParams) {
1253
+ url.search = new URLSearchParams(searchParams).toString();
1254
+ }
1255
+ if (this.endpoint === "/session" && options.user && options.key) {
1256
+ requestHeaders.set("Authorization", "Basic " + btoa(options.user + ":" + options.key));
1257
+ }
1258
+ requestOptions.headers = requestHeaders;
1259
+ return { url, requestOptions };
1260
+ }
1261
+ async _libRequest(url, options) {
1262
+ throw new Error("This function must be implemented");
1263
+ }
1264
+ _libPerformanceNow() {
1265
+ throw new Error("This function must be implemented");
1266
+ }
1267
+ async _request(url, fullRequestOptions, transformResponse, totalRetryCount = 0, retryCount = 0) {
1268
+ log3.info(`[${fullRequestOptions.method}] ${url.href}`);
1269
+ if (fullRequestOptions.body && Object.keys(fullRequestOptions.body).length) {
1270
+ log3.info("DATA", transformCommandLogResult2(fullRequestOptions.body));
1271
+ }
1272
+ const { ...requestLibOptions } = fullRequestOptions;
1273
+ const startTime = this._libPerformanceNow();
1274
+ let response = await this._libRequest(url, requestLibOptions).catch((err) => err);
1275
+ const durationMillisecond = this._libPerformanceNow() - startTime;
1276
+ if (this.#requestTimeout) {
1277
+ clearTimeout(this.#requestTimeout);
1278
+ }
1279
+ const retry = (error2, msg) => {
1280
+ if (retryCount >= totalRetryCount || error2.message.includes("invalid session id")) {
1281
+ log3.error(`Request failed with status ${response.statusCode} due to ${error2}`);
1282
+ this.emit("response", { error: error2 });
1283
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: false, error: error2, retryCount });
1284
+ throw error2;
1285
+ }
1286
+ ++retryCount;
1287
+ this.emit("retry", { error: error2, retryCount });
1288
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: false, error: error2, retryCount });
1289
+ log3.warn(msg);
1290
+ log3.info(`Retrying ${retryCount}/${totalRetryCount}`);
1291
+ return this._request(url, fullRequestOptions, transformResponse, totalRetryCount, retryCount);
1292
+ };
1293
+ if (response instanceof Error) {
1294
+ if (response.code === "ETIMEDOUT") {
1295
+ const error2 = getTimeoutError(response, fullRequestOptions, url);
1296
+ return retry(error2, 'Request timed out! Consider increasing the "connectionRetryTimeout" option.');
1297
+ }
1298
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: false, error: response, retryCount });
1299
+ throw response;
1300
+ }
1301
+ if (typeof transformResponse === "function") {
1302
+ response = transformResponse(response, fullRequestOptions);
1303
+ }
1304
+ const error = getErrorFromResponseBody(response.body, fullRequestOptions.body);
1305
+ if (error.message === "java.net.ConnectException: Connection refused: connect") {
1306
+ return retry(error, "Connection to Selenium Standalone server was refused.");
1307
+ }
1308
+ if (this.isHubCommand) {
1309
+ if (typeof response.body === "string" && response.body.startsWith("<!DOCTYPE html>")) {
1310
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: false, error, retryCount });
1311
+ return Promise.reject(new Error("Command can only be called to a Selenium Hub"));
1312
+ }
1313
+ return { value: response.body || null };
1314
+ }
1315
+ if (isSuccessfulResponse(response.statusCode, response.body)) {
1316
+ this.emit("response", { result: response.body });
1317
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: true, retryCount });
1318
+ return response.body;
1319
+ }
1320
+ if (error.name === "stale element reference") {
1321
+ log3.warn("Request encountered a stale element - terminating request");
1322
+ this.emit("response", { error });
1323
+ this.emit("performance", { request: fullRequestOptions, durationMillisecond, success: false, error, retryCount });
1324
+ throw error;
1325
+ }
1326
+ if (ERRORS_TO_EXCLUDE_FROM_RETRY.includes(error.name)) {
1327
+ throw error;
1328
+ }
1329
+ return retry(error, `Request failed with status ${response.statusCode} due to ${error.message}`);
1330
+ }
1331
+ };
1332
+ function findCommandPathByName(commandName) {
1333
+ const command = Object.entries(WebDriverProtocol2).find(
1334
+ ([, command2]) => Object.values(command2).find(
1335
+ (cmd) => cmd.command === commandName
1336
+ )
1337
+ );
1338
+ if (!command) {
1339
+ throw new Error(`Couldn't find command "${commandName}"`);
1340
+ }
1341
+ return command[0];
1342
+ }
1343
+
1344
+ // src/request/request.ts
1345
+ if ("process" in globalThis && globalThis.process.versions?.node) {
1346
+ dns.setDefaultResultOrder("ipv4first");
1347
+ }
1348
+ var FetchRequest = class extends WebDriverRequest {
1349
+ constructor(method, endpoint, body, isHubCommand = false) {
1350
+ super(method, endpoint, body, isHubCommand);
1351
+ }
1352
+ async _libRequest(url, opts) {
1353
+ try {
1354
+ const response = await fetch(url, {
1355
+ method: opts.method,
1356
+ body: JSON.stringify(opts.body),
1357
+ headers: opts.headers,
1358
+ signal: opts.signal
1359
+ });
1360
+ const resp = response.clone();
1361
+ return {
1362
+ statusCode: resp.status,
1363
+ body: await resp.json() ?? {}
1364
+ };
1365
+ } catch (err) {
1366
+ if (!(err instanceof Error)) {
1367
+ throw new RequestLibError(`Failed to fetch ${url.href}: ${err.message || err}`);
1368
+ }
1369
+ throw err;
1370
+ }
1371
+ }
1372
+ _libPerformanceNow() {
1373
+ return performance.now();
1374
+ }
1375
+ };
1376
+
1377
+ // src/command.ts
1378
+ var log4 = logger4("webdriver");
1379
+ var BIDI_COMMANDS = Object.values(WebDriverBidiProtocol2).map((def) => def.socket.command);
1380
+ function command_default(method, endpointUri, commandInfo, doubleEncodeVariables = false) {
1381
+ const { command, deprecated, ref, parameters, variables = [], isHubCommand = false } = commandInfo;
1382
+ return async function protocolCommand(...args) {
1383
+ const isBidiCommand = BIDI_COMMANDS.includes(command);
1384
+ let endpoint = endpointUri;
1385
+ const commandParams = [...variables.map((v) => Object.assign(v, {
1386
+ /**
1387
+ * url variables are:
1388
+ */
1389
+ required: true,
1390
+ // always required as they are part of the endpoint
1391
+ type: "string"
1392
+ // have to be always type of string
1393
+ })), ...parameters];
1394
+ const commandUsage = `${command}(${commandParams.map((p) => p.name).join(", ")})`;
1395
+ const moreInfo = `
1396
+
1397
+ For more info see ${ref}
1398
+ `;
1399
+ const body = {};
1400
+ if (typeof deprecated === "string") {
1401
+ log4.warn(deprecated.replace("This command", `The "${command}" command`));
1402
+ }
1403
+ if (isBidiCommand) {
1404
+ throw new Error(
1405
+ `Failed to execute WebDriver Bidi command "${command}" as no Bidi session was established. Make sure you enable it by setting "webSocketUrl: true" in your capabilities and verify that your environment and browser supports it.`
1406
+ );
1407
+ }
1408
+ const minAllowedParams = commandParams.filter((param) => param.required).length;
1409
+ if (args.length < minAllowedParams || args.length > commandParams.length) {
1410
+ const parameterDescription = commandParams.length ? `
1411
+
1412
+ Property Description:
1413
+ ${commandParams.map((p) => ` "${p.name}" (${p.type}): ${p.description}`).join("\n")}` : "";
1414
+ throw new Error(
1415
+ `Wrong parameters applied for ${command}
1416
+ Usage: ${commandUsage}` + parameterDescription + moreInfo
1417
+ );
1418
+ }
1419
+ for (const [it, arg] of Object.entries(args)) {
1420
+ if (isBidiCommand) {
1421
+ break;
1422
+ }
1423
+ const i = parseInt(it, 10);
1424
+ const commandParam = commandParams[i];
1425
+ if (!isValidParameter(arg, commandParam.type)) {
1426
+ if (typeof arg === "undefined" && !commandParam.required) {
1427
+ continue;
72
1428
  }
73
- // logLevel can be undefined in watch mode when SIGINT is called
74
- if (options.logLevel) {
75
- logger.setLevel('webdriver', options.logLevel);
1429
+ const actual = commandParam.type.endsWith("[]") ? `(${(Array.isArray(arg) ? arg : [arg]).map((a) => getArgumentType(a))})[]` : getArgumentType(arg);
1430
+ throw new Error(
1431
+ `Malformed type for "${commandParam.name}" parameter of command ${command}
1432
+ Expected: ${commandParam.type}
1433
+ Actual: ${actual}` + moreInfo
1434
+ );
1435
+ }
1436
+ if (i < variables.length) {
1437
+ const encodedArg = doubleEncodeVariables ? encodeURIComponent(encodeURIComponent(arg)) : encodeURIComponent(arg);
1438
+ endpoint = endpoint.replace(`:${commandParams[i].name}`, encodedArg);
1439
+ continue;
1440
+ }
1441
+ body[commandParams[i].name] = arg;
1442
+ }
1443
+ const request = new FetchRequest(method, endpoint, body, isHubCommand);
1444
+ request.on("performance", (...args2) => this.emit("request.performance", ...args2));
1445
+ this.emit("command", { command, method, endpoint, body });
1446
+ log4.info("COMMAND", commandCallStructure(command, args));
1447
+ return request.makeRequest(this.options, this.sessionId).then((result) => {
1448
+ if (typeof result.value !== "undefined") {
1449
+ let resultLog = result.value;
1450
+ if (/screenshot|recording/i.test(command) && typeof result.value === "string" && result.value.length > 64) {
1451
+ resultLog = `${result.value.slice(0, 61)}...`;
1452
+ } else if (command === "executeScript" && body.script && body.script.includes("(() => window.__wdioEvents__)")) {
1453
+ resultLog = `[${result.value.length} framework events captured]`;
76
1454
  }
77
- options.capabilities = options.capabilities || {};
78
- options.isW3C = options.isW3C === false ? false : true;
79
- options.protocol = options.protocol || DEFAULTS.protocol.default;
80
- options.hostname = options.hostname || DEFAULTS.hostname.default;
81
- options.port = options.port || DEFAULTS.port.default;
82
- options.path = options.path || DEFAULTS.path.default;
83
- const environment = sessionEnvironmentDetector({ capabilities: options.capabilities, requestedCapabilities: options.capabilities });
84
- options = Object.assign(environment, options);
85
- const environmentPrototype = getEnvironmentVars(options);
86
- const protocolCommands = getPrototype(options);
87
- /**
88
- * initiate WebDriver Bidi
89
- */
90
- const bidiPrototype = {};
91
- const webSocketUrl = 'alwaysMatch' in options.capabilities
92
- ? options.capabilities.alwaysMatch?.webSocketUrl
93
- : options.capabilities.webSocketUrl;
94
- if (webSocketUrl) {
95
- log.info(`Register BiDi handler for session with id ${options.sessionId}`);
96
- Object.assign(bidiPrototype, initiateBidi(webSocketUrl, options.strictSSL));
1455
+ log4.info("RESULT", resultLog);
1456
+ }
1457
+ this.emit("result", { command, method, endpoint, body, result });
1458
+ if (command === "deleteSession") {
1459
+ const shutdownDriver = body.deleteSessionOpts?.shutdownDriver !== false;
1460
+ if (shutdownDriver && "wdio:driverPID" in this.capabilities && this.capabilities["wdio:driverPID"]) {
1461
+ log4.info(`Kill driver process with PID ${this.capabilities["wdio:driverPID"]}`);
1462
+ const killedSuccessfully = process.kill(this.capabilities["wdio:driverPID"], "SIGKILL");
1463
+ if (!killedSuccessfully) {
1464
+ log4.warn("Failed to kill driver process, manually clean-up might be required");
1465
+ }
1466
+ setTimeout(() => {
1467
+ for (const handle of process._getActiveHandles()) {
1468
+ if (handle.servername && handle.servername.includes("edgedl.me")) {
1469
+ handle.destroy();
1470
+ }
1471
+ }
1472
+ }, 10);
97
1473
  }
98
- const prototype = { ...protocolCommands, ...environmentPrototype, ...userPrototype, ...bidiPrototype };
99
- const monad = webdriverMonad(options, modifier, prototype);
100
- const client = monad(options.sessionId, commandWrapper);
101
- /**
102
- * parse and propagate all Bidi events to the browser instance
103
- */
104
- if (webSocketUrl) {
105
- client._bidiSocket?.on('message', parseBidiMessage.bind(client));
1474
+ if (!process.env.WDIO_WORKER_ID) {
1475
+ logger4.clearLogger();
106
1476
  }
107
- return client;
1477
+ }
1478
+ return result.value;
1479
+ });
1480
+ };
1481
+ }
1482
+
1483
+ // src/bidi/localTypes.ts
1484
+ var localTypes_exports = {};
1485
+
1486
+ // src/bidi/remoteTypes.ts
1487
+ var remoteTypes_exports = {};
1488
+
1489
+ // src/index.ts
1490
+ var log5 = logger5("webdriver");
1491
+ var WebDriver = class _WebDriver {
1492
+ static async newSession(options, modifier, userPrototype = {}, customCommandWrapper) {
1493
+ const envLogLevel = process.env.WDIO_LOG_LEVEL;
1494
+ options.logLevel = envLogLevel ?? options.logLevel;
1495
+ const params = validateConfig(DEFAULTS, options);
1496
+ if (params.logLevel && (!options.logLevels || !options.logLevels.webdriver)) {
1497
+ logger5.setLevel("webdriver", params.logLevel);
108
1498
  }
109
- /**
110
- * Changes The instance session id and browser capabilities for the new session
111
- * directly into the passed in browser object
112
- *
113
- * @param {object} instance the object we get from a new browser session.
114
- * @returns {string} the new session id of the browser
115
- */
116
- static async reloadSession(instance, newCapabilities) {
117
- const capabilities = deepmerge(instance.requestedCapabilities, newCapabilities || {});
118
- const params = { ...instance.options, capabilities };
119
- let driverProcess;
120
- if (newCapabilities?.browserName) {
121
- delete params.port;
122
- delete params.hostname;
123
- driverProcess = await startWebDriver(params);
124
- }
125
- const { sessionId, capabilities: newSessionCapabilities } = await startWebDriverSession(params);
126
- /**
127
- * attach driver process to instance capabilities so we can kill the driver process
128
- * even after attaching to this session
129
- */
130
- if (driverProcess?.pid) {
131
- newSessionCapabilities['wdio:driverPID'] = driverProcess.pid;
132
- }
133
- instance.options.hostname = params.hostname;
134
- instance.options.port = params.port;
135
- instance.sessionId = sessionId;
136
- instance.capabilities = newSessionCapabilities;
137
- return sessionId;
1499
+ log5.info("Initiate new session using the WebDriver protocol");
1500
+ const driverProcess = await startWebDriver(params);
1501
+ const requestedCapabilities = { ...params.capabilities };
1502
+ const { sessionId, capabilities } = await startWebDriverSession(params);
1503
+ const environment = sessionEnvironmentDetector({ capabilities, requestedCapabilities });
1504
+ const environmentPrototype = getEnvironmentVars(environment);
1505
+ const protocolCommands = getPrototype(environment);
1506
+ if (driverProcess?.pid) {
1507
+ capabilities["wdio:driverPID"] = driverProcess.pid;
138
1508
  }
139
- static get WebDriver() {
140
- return WebDriver;
1509
+ const bidiPrototype = {};
1510
+ if (capabilities.webSocketUrl) {
1511
+ log5.info(`Register BiDi handler for session with id ${sessionId}`);
1512
+ Object.assign(bidiPrototype, initiateBidi(capabilities.webSocketUrl, options.strictSSL));
141
1513
  }
142
- }
143
- /**
144
- * Helper methods consumed by webdriverio package
145
- */
146
- export { getPrototype, DEFAULTS, command, getEnvironmentVars, initiateBidi, parseBidiMessage };
147
- export * from './types.js';
148
- export * from './constants.js';
149
- export * from './bidi/handler.js';
150
- export * as local from './bidi/localTypes.js';
151
- export * as remote from './bidi/remoteTypes.js';
1514
+ const monad = webdriverMonad(
1515
+ { ...params, requestedCapabilities },
1516
+ modifier,
1517
+ {
1518
+ ...protocolCommands,
1519
+ ...environmentPrototype,
1520
+ ...userPrototype,
1521
+ ...bidiPrototype
1522
+ }
1523
+ );
1524
+ const client = monad(sessionId, customCommandWrapper);
1525
+ if (capabilities.webSocketUrl) {
1526
+ await client._bidiHandler.connect();
1527
+ client._bidiHandler?.socket.on("message", parseBidiMessage.bind(client));
1528
+ }
1529
+ if (params.enableDirectConnect) {
1530
+ setupDirectConnect(client);
1531
+ }
1532
+ return client;
1533
+ }
1534
+ /**
1535
+ * allows user to attach to existing sessions
1536
+ */
1537
+ static attachToSession(options, modifier, userPrototype = {}, commandWrapper) {
1538
+ if (!options || typeof options.sessionId !== "string") {
1539
+ throw new Error("sessionId is required to attach to existing session");
1540
+ }
1541
+ if (options.logLevel) {
1542
+ logger5.setLevel("webdriver", options.logLevel);
1543
+ }
1544
+ options.capabilities = options.capabilities || {};
1545
+ options.isW3C = options.isW3C === false ? false : true;
1546
+ options.protocol = options.protocol || DEFAULTS.protocol.default;
1547
+ options.hostname = options.hostname || DEFAULTS.hostname.default;
1548
+ options.port = options.port || DEFAULTS.port.default;
1549
+ options.path = options.path || DEFAULTS.path.default;
1550
+ const environment = sessionEnvironmentDetector({ capabilities: options.capabilities, requestedCapabilities: options.capabilities });
1551
+ options = Object.assign(environment, options);
1552
+ const environmentPrototype = getEnvironmentVars(options);
1553
+ const protocolCommands = getPrototype(options);
1554
+ const bidiPrototype = {};
1555
+ const webSocketUrl = options.capabilities?.webSocketUrl;
1556
+ if (typeof webSocketUrl === "string") {
1557
+ log5.info(`Register BiDi handler for session with id ${options.sessionId}`);
1558
+ Object.assign(bidiPrototype, initiateBidi(webSocketUrl, options.strictSSL));
1559
+ }
1560
+ const prototype = { ...protocolCommands, ...environmentPrototype, ...userPrototype, ...bidiPrototype };
1561
+ const monad = webdriverMonad(options, modifier, prototype);
1562
+ const client = monad(options.sessionId, commandWrapper);
1563
+ if (webSocketUrl) {
1564
+ client._bidiHandler?.socket.on("message", parseBidiMessage.bind(client));
1565
+ }
1566
+ return client;
1567
+ }
1568
+ /**
1569
+ * Changes The instance session id and browser capabilities for the new session
1570
+ * directly into the passed in browser object
1571
+ *
1572
+ * @param {object} instance the object we get from a new browser session.
1573
+ * @returns {string} the new session id of the browser
1574
+ */
1575
+ static async reloadSession(instance, newCapabilities) {
1576
+ const capabilities = newCapabilities ? newCapabilities : Object.assign({}, instance.requestedCapabilities);
1577
+ let params = { ...instance.options, capabilities };
1578
+ for (const prop of ["protocol", "hostname", "port", "path", "queryParams", "user", "key"]) {
1579
+ if (prop in capabilities) {
1580
+ params = { ...params, [prop]: capabilities[prop] };
1581
+ delete capabilities[prop];
1582
+ }
1583
+ }
1584
+ let driverProcess;
1585
+ if (params.hostname === "localhost" && newCapabilities?.browserName) {
1586
+ delete params.port;
1587
+ delete params.hostname;
1588
+ driverProcess = await startWebDriver(params);
1589
+ }
1590
+ const { sessionId, capabilities: newSessionCapabilities } = await startWebDriverSession(params);
1591
+ if (driverProcess?.pid) {
1592
+ newSessionCapabilities["wdio:driverPID"] = driverProcess.pid;
1593
+ }
1594
+ for (const prop of ["protocol", "hostname", "port", "path", "queryParams", "user", "key"]) {
1595
+ if (prop in params) {
1596
+ instance.options[prop] = params[prop];
1597
+ }
1598
+ }
1599
+ for (const prop in instance.requestedCapabilities) {
1600
+ delete instance.requestedCapabilities[prop];
1601
+ }
1602
+ instance.sessionId = sessionId;
1603
+ instance.capabilities = newSessionCapabilities;
1604
+ Object.assign(instance.requestedCapabilities, capabilities);
1605
+ return sessionId;
1606
+ }
1607
+ static get WebDriver() {
1608
+ return _WebDriver;
1609
+ }
1610
+ };
1611
+ export {
1612
+ BidiHandler,
1613
+ DEFAULTS,
1614
+ ELEMENT_KEY,
1615
+ REG_EXPS,
1616
+ SHADOW_ELEMENT_KEY,
1617
+ command_default as command,
1618
+ WebDriver as default,
1619
+ getEnvironmentVars,
1620
+ getPrototype,
1621
+ initiateBidi,
1622
+ localTypes_exports as local,
1623
+ parseBidiMessage,
1624
+ remoteTypes_exports as remote
1625
+ };