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