selenium-webdriver 4.16.0 → 4.18.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/CHANGES.md +253 -196
- package/LICENSE +1 -1
- package/NOTICE +1 -1
- package/bidi/addInterceptParameters.js +86 -0
- package/bidi/browsingContext.js +167 -38
- package/bidi/browsingContextInspector.js +13 -40
- package/bidi/evaluateResult.js +4 -10
- package/bidi/filterBy.js +2 -6
- package/bidi/index.js +31 -29
- package/bidi/input.js +97 -0
- package/bidi/interceptPhase.js +24 -0
- package/bidi/logInspector.js +15 -20
- package/bidi/network.js +178 -0
- package/bidi/networkInspector.js +12 -2
- package/bidi/networkTypes.js +22 -49
- package/bidi/protocolType.js +4 -9
- package/bidi/protocolValue.js +48 -17
- package/bidi/realmInfo.js +3 -10
- package/bidi/scriptManager.js +60 -48
- package/bidi/scriptTypes.js +58 -0
- package/bidi/urlPattern.js +58 -0
- package/bin/linux/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/windows/selenium-manager.exe +0 -0
- package/chrome.js +2 -14
- package/chromium.js +28 -143
- package/common/driverFinder.js +1 -1
- package/common/seleniumManager.js +5 -12
- package/devtools/CDPConnection.js +1 -3
- package/edge.js +1 -3
- package/example/chrome_android.js +2 -5
- package/example/chrome_mobile_emulation.js +2 -4
- package/example/google_search.js +1 -3
- package/example/headless.js +4 -10
- package/example/logging.js +3 -9
- package/firefox.js +37 -111
- package/http/index.js +7 -10
- package/ie.js +5 -15
- package/index.js +10 -32
- package/io/exec.js +1 -2
- package/io/index.js +3 -3
- package/io/zip.js +8 -30
- package/lib/atoms/find-elements.js +1 -1
- package/lib/atoms/get-attribute.js +6 -100
- package/lib/by.js +2 -9
- package/lib/capabilities.js +8 -7
- package/lib/command.js +4 -0
- package/lib/error.js +2 -9
- package/lib/http.js +37 -130
- package/lib/input.js +22 -34
- package/lib/logging.js +3 -11
- package/lib/promise.js +2 -7
- package/lib/select.js +3 -9
- package/lib/until.js +28 -49
- package/lib/util.js +1 -4
- package/lib/virtual_authenticator.js +4 -22
- package/lib/webdriver.js +146 -269
- package/lib/webelement.js +1 -5
- package/net/index.js +1 -4
- package/package.json +2 -1
- package/remote/index.js +9 -24
- package/remote/util.js +6 -19
- package/safari.js +3 -8
- package/testing/index.js +6 -11
- package/example/firefox_channels.js +0 -84
package/LICENSE
CHANGED
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
same "printed page" as the copyright notice for easier
|
|
188
188
|
identification within third-party archives.
|
|
189
189
|
|
|
190
|
-
Copyright
|
|
190
|
+
Copyright 2024 Software Freedom Conservancy (SFC)
|
|
191
191
|
|
|
192
192
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
193
|
you may not use this file except in compliance with the License.
|
package/NOTICE
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Copyright 2011-
|
|
1
|
+
Copyright 2011-2024 Software Freedom Conservancy
|
|
2
2
|
Copyright 2004-2011 Selenium committers
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
2
|
+
// or more contributor license agreements. See the NOTICE file
|
|
3
|
+
// distributed with this work for additional information
|
|
4
|
+
// regarding copyright ownership. The SFC licenses this file
|
|
5
|
+
// to you under the Apache License, Version 2.0 (the
|
|
6
|
+
// "License"); you may not use this file except in compliance
|
|
7
|
+
// with the License. You may obtain a copy of the License at
|
|
8
|
+
//
|
|
9
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
//
|
|
11
|
+
// Unless required by applicable law or agreed to in writing,
|
|
12
|
+
// software distributed under the License is distributed on an
|
|
13
|
+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
// KIND, either express or implied. See the License for the
|
|
15
|
+
// specific language governing permissions and limitations
|
|
16
|
+
// under the License.
|
|
17
|
+
|
|
18
|
+
const {UrlPattern} = require("./urlPattern");
|
|
19
|
+
|
|
20
|
+
class AddInterceptParameters {
|
|
21
|
+
#phases = []
|
|
22
|
+
#urlPatterns = []
|
|
23
|
+
|
|
24
|
+
constructor(phases) {
|
|
25
|
+
if (phases instanceof Array) {
|
|
26
|
+
phases.forEach(phase => this.#phases.push(phase))
|
|
27
|
+
} else {
|
|
28
|
+
this.#phases.push(phases)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
urlPattern(pattern)
|
|
33
|
+
{
|
|
34
|
+
if (!pattern instanceof UrlPattern) {
|
|
35
|
+
throw new Error(`Pattern must be an instance of UrlPattern. Received: '${pattern})'`)
|
|
36
|
+
}
|
|
37
|
+
this.#urlPatterns.push(Object.fromEntries(pattern.asMap()))
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
urlPatterns(patterns)
|
|
42
|
+
{
|
|
43
|
+
patterns.forEach(pattern => {
|
|
44
|
+
if (!pattern instanceof UrlPattern) {
|
|
45
|
+
throw new Error(`Pattern must be an instance of UrlPattern. Received:'${pattern}'`)
|
|
46
|
+
}
|
|
47
|
+
this.#urlPatterns.push(Object.fromEntries(pattern.asMap()))
|
|
48
|
+
})
|
|
49
|
+
return this
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
urlStringPattern(pattern)
|
|
53
|
+
{
|
|
54
|
+
if (!pattern instanceof String) {
|
|
55
|
+
throw new Error(`Pattern must be an instance of String. Received:'${pattern}'`)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.#urlPatterns.push({'type': 'string', 'pattern': pattern})
|
|
59
|
+
return this
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
urlStringPatterns(patterns)
|
|
63
|
+
{
|
|
64
|
+
patterns.forEach(pattern => {
|
|
65
|
+
if (!pattern instanceof String) {
|
|
66
|
+
throw new Error(`Pattern must be an instance of String. Received:'${pattern}'`)
|
|
67
|
+
}
|
|
68
|
+
this.#urlPatterns.push({'type': 'string', 'pattern': pattern})
|
|
69
|
+
})
|
|
70
|
+
return this
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
asMap()
|
|
75
|
+
{
|
|
76
|
+
const map = new Map()
|
|
77
|
+
map.set('phases', this.#phases)
|
|
78
|
+
if (this.#urlPatterns.length > 0) {
|
|
79
|
+
map.set('urlPatterns', this.#urlPatterns)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return map
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {AddInterceptParameters}
|
package/bidi/browsingContext.js
CHANGED
|
@@ -17,6 +17,55 @@
|
|
|
17
17
|
|
|
18
18
|
const { InvalidArgumentError, NoSuchFrameError } = require('../lib/error')
|
|
19
19
|
const { BrowsingContextInfo } = require('./browsingContextTypes')
|
|
20
|
+
const { SerializationOptions, ReferenceValue, RemoteValue } = require('./protocolValue')
|
|
21
|
+
const { WebElement } = require('../lib/webdriver')
|
|
22
|
+
|
|
23
|
+
class Locator {
|
|
24
|
+
static Type = Object.freeze({
|
|
25
|
+
CSS: 'css',
|
|
26
|
+
INNER_TEXT: 'innerText',
|
|
27
|
+
XPATH: 'xpath',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
#type
|
|
31
|
+
#value
|
|
32
|
+
#ignoreCase
|
|
33
|
+
#matchType
|
|
34
|
+
#maxDepth
|
|
35
|
+
|
|
36
|
+
constructor(type, value, ignoreCase = undefined, matchType = undefined, maxDepth = undefined) {
|
|
37
|
+
this.#type = type
|
|
38
|
+
this.#value = value
|
|
39
|
+
this.#ignoreCase = ignoreCase
|
|
40
|
+
this.#matchType = matchType
|
|
41
|
+
this.#maxDepth = maxDepth
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static css(value) {
|
|
45
|
+
return new Locator(Locator.Type.CSS, value)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static xpath(value) {
|
|
49
|
+
return new Locator(Locator.Type.XPATH, value)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static innerText(value, ignoreCase = undefined, matchType = undefined, maxDepth = undefined) {
|
|
53
|
+
return new Locator(Locator.Type.INNER_TEXT, value, ignoreCase, matchType, maxDepth)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
toMap() {
|
|
57
|
+
const map = new Map()
|
|
58
|
+
|
|
59
|
+
map.set('type', this.#type.toString())
|
|
60
|
+
map.set('value', this.#value)
|
|
61
|
+
map.set('ignoreCase', this.#ignoreCase)
|
|
62
|
+
map.set('matchType', this.#matchType)
|
|
63
|
+
map.set('maxDepth', this.#maxDepth)
|
|
64
|
+
|
|
65
|
+
return map
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
20
69
|
class BrowsingContext {
|
|
21
70
|
constructor(driver) {
|
|
22
71
|
this._driver = driver
|
|
@@ -65,13 +114,8 @@ class BrowsingContext {
|
|
|
65
114
|
* @returns NavigateResult object
|
|
66
115
|
*/
|
|
67
116
|
async navigate(url, readinessState = undefined) {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
!['none', 'interactive', 'complete'].includes(readinessState)
|
|
71
|
-
) {
|
|
72
|
-
throw Error(
|
|
73
|
-
`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`
|
|
74
|
-
)
|
|
117
|
+
if (readinessState !== undefined && !['none', 'interactive', 'complete'].includes(readinessState)) {
|
|
118
|
+
throw Error(`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`)
|
|
75
119
|
}
|
|
76
120
|
|
|
77
121
|
const params = {
|
|
@@ -84,10 +128,7 @@ class BrowsingContext {
|
|
|
84
128
|
}
|
|
85
129
|
const navigateResult = (await this.bidi.send(params))['result']
|
|
86
130
|
|
|
87
|
-
return new NavigateResult(
|
|
88
|
-
navigateResult['url'],
|
|
89
|
-
navigateResult['navigation']
|
|
90
|
-
)
|
|
131
|
+
return new NavigateResult(navigateResult['url'], navigateResult['navigation'])
|
|
91
132
|
}
|
|
92
133
|
|
|
93
134
|
/**
|
|
@@ -109,12 +150,7 @@ class BrowsingContext {
|
|
|
109
150
|
}
|
|
110
151
|
|
|
111
152
|
result = result['result']['contexts'][0]
|
|
112
|
-
return new BrowsingContextInfo(
|
|
113
|
-
result['context'],
|
|
114
|
-
result['url'],
|
|
115
|
-
result['children'],
|
|
116
|
-
result['parent']
|
|
117
|
-
)
|
|
153
|
+
return new BrowsingContextInfo(result['context'], result['url'], result['children'], result['parent'])
|
|
118
154
|
}
|
|
119
155
|
|
|
120
156
|
/**
|
|
@@ -186,7 +222,7 @@ class BrowsingContext {
|
|
|
186
222
|
params: {
|
|
187
223
|
context: this._id,
|
|
188
224
|
clip: {
|
|
189
|
-
type: '
|
|
225
|
+
type: 'box',
|
|
190
226
|
x: x,
|
|
191
227
|
y: y,
|
|
192
228
|
width: width,
|
|
@@ -195,16 +231,15 @@ class BrowsingContext {
|
|
|
195
231
|
},
|
|
196
232
|
}
|
|
197
233
|
|
|
234
|
+
console.log(JSON.stringify(params))
|
|
235
|
+
|
|
198
236
|
const response = await this.bidi.send(params)
|
|
237
|
+
console.log(JSON.stringify(response))
|
|
199
238
|
this.checkErrorInScreenshot(response)
|
|
200
239
|
return response['result']['data']
|
|
201
240
|
}
|
|
202
241
|
|
|
203
|
-
async captureElementScreenshot(
|
|
204
|
-
sharedId,
|
|
205
|
-
handle = undefined,
|
|
206
|
-
scrollIntoView = undefined
|
|
207
|
-
) {
|
|
242
|
+
async captureElementScreenshot(sharedId, handle = undefined, scrollIntoView = undefined) {
|
|
208
243
|
let params = {
|
|
209
244
|
method: 'browsingContext.captureScreenshot',
|
|
210
245
|
params: {
|
|
@@ -270,13 +305,8 @@ class BrowsingContext {
|
|
|
270
305
|
}
|
|
271
306
|
|
|
272
307
|
async reload(ignoreCache = undefined, readinessState = undefined) {
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
!['none', 'interactive', 'complete'].includes(readinessState)
|
|
276
|
-
) {
|
|
277
|
-
throw Error(
|
|
278
|
-
`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`
|
|
279
|
-
)
|
|
308
|
+
if (readinessState !== undefined && !['none', 'interactive', 'complete'].includes(readinessState)) {
|
|
309
|
+
throw Error(`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`)
|
|
280
310
|
}
|
|
281
311
|
|
|
282
312
|
const params = {
|
|
@@ -289,10 +319,7 @@ class BrowsingContext {
|
|
|
289
319
|
}
|
|
290
320
|
const navigateResult = (await this.bidi.send(params))['result']
|
|
291
321
|
|
|
292
|
-
return new NavigateResult(
|
|
293
|
-
navigateResult['url'],
|
|
294
|
-
navigateResult['navigation']
|
|
295
|
-
)
|
|
322
|
+
return new NavigateResult(navigateResult['url'], navigateResult['navigation'])
|
|
296
323
|
}
|
|
297
324
|
|
|
298
325
|
async setViewport(width, height, devicePixelRatio = undefined) {
|
|
@@ -309,6 +336,110 @@ class BrowsingContext {
|
|
|
309
336
|
throw Error(result['error'])
|
|
310
337
|
}
|
|
311
338
|
}
|
|
339
|
+
|
|
340
|
+
async traverseHistory(delta) {
|
|
341
|
+
const params = {
|
|
342
|
+
method: 'browsingContext.traverseHistory',
|
|
343
|
+
params: {
|
|
344
|
+
context: this._id,
|
|
345
|
+
delta: delta,
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
await this.bidi.send(params)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async forward() {
|
|
352
|
+
await this.traverseHistory(1)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async back() {
|
|
356
|
+
await this.traverseHistory(-1)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async locateNodes(
|
|
360
|
+
locator,
|
|
361
|
+
maxNodeCount = undefined,
|
|
362
|
+
ownership = undefined,
|
|
363
|
+
sandbox = undefined,
|
|
364
|
+
serializationOptions = undefined,
|
|
365
|
+
startNodes = undefined,
|
|
366
|
+
) {
|
|
367
|
+
if (!(locator instanceof Locator)) {
|
|
368
|
+
throw Error(`Pass in a Locator object. Received: ${locator}`)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (serializationOptions !== undefined && !(serializationOptions instanceof SerializationOptions)) {
|
|
372
|
+
throw Error(`Pass in SerializationOptions object. Received: ${serializationOptions} `)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (ownership !== undefined && !['root', 'none'].includes(ownership)) {
|
|
376
|
+
throw Error(`Valid types are 'root' and 'none. Received: ${ownership}`)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (startNodes !== undefined && !Array.isArray(startNodes)) {
|
|
380
|
+
throw Error(`Pass in an array of ReferenceValue objects. Received: ${startNodes}`)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (startNodes !== undefined && Array.isArray(startNodes)) {
|
|
384
|
+
startNodes.forEach((node) => {
|
|
385
|
+
if (!(node instanceof ReferenceValue)) {
|
|
386
|
+
throw Error(`Pass in a ReferenceValue object. Received: ${node}`)
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const params = {
|
|
392
|
+
method: 'browsingContext.locateNodes',
|
|
393
|
+
params: {
|
|
394
|
+
context: this._id,
|
|
395
|
+
locator: Object.fromEntries(locator.toMap()),
|
|
396
|
+
maxNodeCount: maxNodeCount,
|
|
397
|
+
ownership: ownership,
|
|
398
|
+
sandbox: sandbox,
|
|
399
|
+
serializationOptions: serializationOptions,
|
|
400
|
+
startNodes: startNodes,
|
|
401
|
+
},
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
let response = await this.bidi.send(params)
|
|
405
|
+
if ('error' in response) {
|
|
406
|
+
throw Error(response['error'])
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const nodes = response.result.nodes
|
|
410
|
+
const remoteValues = []
|
|
411
|
+
|
|
412
|
+
nodes.forEach((node) => {
|
|
413
|
+
remoteValues.push(new RemoteValue(node))
|
|
414
|
+
})
|
|
415
|
+
return remoteValues
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async locateNode(
|
|
419
|
+
locator,
|
|
420
|
+
ownership = undefined,
|
|
421
|
+
sandbox = undefined,
|
|
422
|
+
serializationOptions = undefined,
|
|
423
|
+
startNodes = undefined,
|
|
424
|
+
) {
|
|
425
|
+
const elements = await this.locateNodes(locator, 1, ownership, sandbox, serializationOptions, startNodes)
|
|
426
|
+
return elements[0]
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async locateElement(locator) {
|
|
430
|
+
const elements = await this.locateNodes(locator, 1)
|
|
431
|
+
return new WebElement(this._driver, elements[0].sharedId)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async locateElements(locator) {
|
|
435
|
+
const elements = await this.locateNodes(locator)
|
|
436
|
+
|
|
437
|
+
let webElements = []
|
|
438
|
+
elements.forEach((element) => {
|
|
439
|
+
webElements.push(new WebElement(this._driver, element.sharedId))
|
|
440
|
+
})
|
|
441
|
+
return webElements
|
|
442
|
+
}
|
|
312
443
|
}
|
|
313
444
|
|
|
314
445
|
class NavigateResult {
|
|
@@ -344,10 +475,7 @@ class PrintResult {
|
|
|
344
475
|
* @param referenceContext To get a browsing context for this reference if passed
|
|
345
476
|
* @returns {Promise<BrowsingContext>}
|
|
346
477
|
*/
|
|
347
|
-
async function getBrowsingContextInstance(
|
|
348
|
-
driver,
|
|
349
|
-
{ browsingContextId, type, referenceContext }
|
|
350
|
-
) {
|
|
478
|
+
async function getBrowsingContextInstance(driver, { browsingContextId, type, referenceContext }) {
|
|
351
479
|
let instance = new BrowsingContext(driver)
|
|
352
480
|
await instance.init({ browsingContextId, type, referenceContext })
|
|
353
481
|
return instance
|
|
@@ -358,3 +486,4 @@ async function getBrowsingContextInstance(
|
|
|
358
486
|
* @type {function(*, {*,*,*}): Promise<BrowsingContext>}
|
|
359
487
|
*/
|
|
360
488
|
module.exports = getBrowsingContextInstance
|
|
489
|
+
module.exports.Locator = Locator
|
|
@@ -15,10 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
-
const {
|
|
19
|
-
BrowsingContextInfo,
|
|
20
|
-
NavigationInfo,
|
|
21
|
-
} = require('./browsingContextTypes')
|
|
18
|
+
const { BrowsingContextInfo, NavigationInfo } = require('./browsingContextTypes')
|
|
22
19
|
|
|
23
20
|
class BrowsingContextInspector {
|
|
24
21
|
constructor(driver, browsingContextIds) {
|
|
@@ -31,45 +28,31 @@ class BrowsingContextInspector {
|
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
async onBrowsingContextCreated(callback) {
|
|
34
|
-
await this.subscribeAndHandleEvent(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
await this.subscribeAndHandleEvent('browsingContext.contextCreated', callback)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async onBrowsingContextDestroyed(callback) {
|
|
35
|
+
await this.subscribeAndHandleEvent('browsingContext.contextDestroyed', callback)
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
async onNavigationStarted(callback) {
|
|
41
|
-
await this.subscribeAndHandleEvent(
|
|
42
|
-
'browsingContext.navigationStarted',
|
|
43
|
-
callback
|
|
44
|
-
)
|
|
39
|
+
await this.subscribeAndHandleEvent('browsingContext.navigationStarted', callback)
|
|
45
40
|
}
|
|
46
41
|
|
|
47
42
|
async onFragmentNavigated(callback) {
|
|
48
|
-
await this.subscribeAndHandleEvent(
|
|
49
|
-
'browsingContext.fragmentNavigated',
|
|
50
|
-
callback
|
|
51
|
-
)
|
|
43
|
+
await this.subscribeAndHandleEvent('browsingContext.fragmentNavigated', callback)
|
|
52
44
|
}
|
|
53
45
|
|
|
54
46
|
async onUserPromptClosed(callback) {
|
|
55
|
-
await this.subscribeAndHandleEvent(
|
|
56
|
-
'browsingContext.userPromptClosed',
|
|
57
|
-
callback
|
|
58
|
-
)
|
|
47
|
+
await this.subscribeAndHandleEvent('browsingContext.userPromptClosed', callback)
|
|
59
48
|
}
|
|
60
49
|
|
|
61
50
|
async onUserPromptOpened(callback) {
|
|
62
|
-
await this.subscribeAndHandleEvent(
|
|
63
|
-
'browsingContext.userPromptOpened',
|
|
64
|
-
callback
|
|
65
|
-
)
|
|
51
|
+
await this.subscribeAndHandleEvent('browsingContext.userPromptOpened', callback)
|
|
66
52
|
}
|
|
67
53
|
|
|
68
54
|
async onDomContentLoaded(callback) {
|
|
69
|
-
await this.subscribeAndHandleEvent(
|
|
70
|
-
'browsingContext.domContentLoaded',
|
|
71
|
-
callback
|
|
72
|
-
)
|
|
55
|
+
await this.subscribeAndHandleEvent('browsingContext.domContentLoaded', callback)
|
|
73
56
|
}
|
|
74
57
|
|
|
75
58
|
async onBrowsingContextLoaded(callback) {
|
|
@@ -92,21 +75,11 @@ class BrowsingContextInspector {
|
|
|
92
75
|
if (params) {
|
|
93
76
|
let response = null
|
|
94
77
|
if ('navigation' in params) {
|
|
95
|
-
response = new NavigationInfo(
|
|
96
|
-
params.context,
|
|
97
|
-
params.navigation,
|
|
98
|
-
params.timestamp,
|
|
99
|
-
params.url
|
|
100
|
-
)
|
|
78
|
+
response = new NavigationInfo(params.context, params.navigation, params.timestamp, params.url)
|
|
101
79
|
} else if ('accepted' in params) {
|
|
102
80
|
/* Needs to be updated when browsers implement other events */
|
|
103
81
|
} else {
|
|
104
|
-
response = new BrowsingContextInfo(
|
|
105
|
-
params.context,
|
|
106
|
-
params.url,
|
|
107
|
-
params.children,
|
|
108
|
-
params.parent
|
|
109
|
-
)
|
|
82
|
+
response = new BrowsingContextInfo(params.context, params.url, params.children, params.parent)
|
|
110
83
|
}
|
|
111
84
|
callback(response)
|
|
112
85
|
}
|
package/bidi/evaluateResult.js
CHANGED
|
@@ -38,16 +38,10 @@ class EvaluateResultException {
|
|
|
38
38
|
|
|
39
39
|
class ExceptionDetails {
|
|
40
40
|
constructor(exceptionDetails) {
|
|
41
|
-
this.columnNumber =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.exception =
|
|
46
|
-
'exception' in exceptionDetails ? exceptionDetails['exception'] : null
|
|
47
|
-
this.lineNumber =
|
|
48
|
-
'lineNumber' in exceptionDetails ? exceptionDetails['lineNumber'] : null
|
|
49
|
-
this.stackTrace =
|
|
50
|
-
'stackTrace' in exceptionDetails ? exceptionDetails['stackTrace'] : null
|
|
41
|
+
this.columnNumber = 'columnNumber' in exceptionDetails ? exceptionDetails['columnNumber'] : null
|
|
42
|
+
this.exception = 'exception' in exceptionDetails ? exceptionDetails['exception'] : null
|
|
43
|
+
this.lineNumber = 'lineNumber' in exceptionDetails ? exceptionDetails['lineNumber'] : null
|
|
44
|
+
this.stackTrace = 'stackTrace' in exceptionDetails ? exceptionDetails['stackTrace'] : null
|
|
51
45
|
this.text = 'text' in exceptionDetails ? exceptionDetails['text'] : null
|
|
52
46
|
}
|
|
53
47
|
}
|
package/bidi/filterBy.js
CHANGED
|
@@ -21,13 +21,9 @@ class FilterBy {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
static logLevel(level) {
|
|
24
|
-
if (
|
|
25
|
-
level === undefined ||
|
|
26
|
-
(level != undefined &&
|
|
27
|
-
!['debug', 'error', 'info', 'warning'].includes(level))
|
|
28
|
-
) {
|
|
24
|
+
if (level === undefined || (level != undefined && !['debug', 'error', 'info', 'warning'].includes(level))) {
|
|
29
25
|
throw Error(
|
|
30
|
-
`Please pass valid log level. Valid log levels are 'debug', 'error', 'info' and 'warning'. Received: ${level}
|
|
26
|
+
`Please pass valid log level. Valid log levels are 'debug', 'error', 'info' and 'warning'. Received: ${level}`,
|
|
31
27
|
)
|
|
32
28
|
}
|
|
33
29
|
|
package/bidi/index.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
+
// eslint-disable-next-line node/no-missing-require
|
|
18
19
|
const { EventEmitter } = require('node:events')
|
|
19
20
|
const WebSocket = require('ws')
|
|
20
21
|
|
|
@@ -22,7 +23,7 @@ const RESPONSE_TIMEOUT = 1000 * 30
|
|
|
22
23
|
|
|
23
24
|
class Index extends EventEmitter {
|
|
24
25
|
id = 0
|
|
25
|
-
|
|
26
|
+
connected = false
|
|
26
27
|
events = []
|
|
27
28
|
browsingContexts = []
|
|
28
29
|
|
|
@@ -30,12 +31,12 @@ class Index extends EventEmitter {
|
|
|
30
31
|
* Create a new websocket connection
|
|
31
32
|
* @param _webSocketUrl
|
|
32
33
|
*/
|
|
33
|
-
constructor
|
|
34
|
+
constructor(_webSocketUrl) {
|
|
34
35
|
super()
|
|
35
|
-
this.
|
|
36
|
+
this.connected = false
|
|
36
37
|
this._ws = new WebSocket(_webSocketUrl)
|
|
37
38
|
this._ws.on('open', () => {
|
|
38
|
-
this.
|
|
39
|
+
this.connected = true
|
|
39
40
|
})
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -43,9 +44,9 @@ class Index extends EventEmitter {
|
|
|
43
44
|
* Resolve connection
|
|
44
45
|
* @returns {Promise<unknown>}
|
|
45
46
|
*/
|
|
46
|
-
async waitForConnection
|
|
47
|
+
async waitForConnection() {
|
|
47
48
|
return new Promise((resolve) => {
|
|
48
|
-
if (this.
|
|
49
|
+
if (this.connected) {
|
|
49
50
|
resolve()
|
|
50
51
|
} else {
|
|
51
52
|
this._ws.once('open', () => {
|
|
@@ -58,15 +59,15 @@ class Index extends EventEmitter {
|
|
|
58
59
|
/**
|
|
59
60
|
* @returns {WebSocket}
|
|
60
61
|
*/
|
|
61
|
-
get socket
|
|
62
|
+
get socket() {
|
|
62
63
|
return this._ws
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* @returns {boolean|*}
|
|
67
68
|
*/
|
|
68
|
-
get isConnected
|
|
69
|
-
return this.
|
|
69
|
+
get isConnected() {
|
|
70
|
+
return this.connected
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
/**
|
|
@@ -74,8 +75,8 @@ class Index extends EventEmitter {
|
|
|
74
75
|
* @param params
|
|
75
76
|
* @returns {Promise<unknown>}
|
|
76
77
|
*/
|
|
77
|
-
async send
|
|
78
|
-
if (!this.
|
|
78
|
+
async send(params) {
|
|
79
|
+
if (!this.connected) {
|
|
79
80
|
await this.waitForConnection()
|
|
80
81
|
}
|
|
81
82
|
|
|
@@ -98,6 +99,7 @@ class Index extends EventEmitter {
|
|
|
98
99
|
resolve(payload)
|
|
99
100
|
}
|
|
100
101
|
} catch (err) {
|
|
102
|
+
// eslint-disable-next-line no-undef
|
|
101
103
|
log.error(`Failed parse message: ${err.message}`)
|
|
102
104
|
}
|
|
103
105
|
}
|
|
@@ -112,8 +114,8 @@ class Index extends EventEmitter {
|
|
|
112
114
|
* @param browsingContexts
|
|
113
115
|
* @returns {Promise<void>}
|
|
114
116
|
*/
|
|
115
|
-
async subscribe
|
|
116
|
-
function toArray
|
|
117
|
+
async subscribe(events, browsingContexts) {
|
|
118
|
+
function toArray(arg) {
|
|
117
119
|
if (arg === undefined) {
|
|
118
120
|
return []
|
|
119
121
|
}
|
|
@@ -125,16 +127,15 @@ class Index extends EventEmitter {
|
|
|
125
127
|
const contextsArray = toArray(browsingContexts)
|
|
126
128
|
|
|
127
129
|
const params = {
|
|
128
|
-
method: 'session.subscribe',
|
|
130
|
+
method: 'session.subscribe',
|
|
131
|
+
params: {},
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
if (eventsArray.length && eventsArray.some(
|
|
132
|
-
event => typeof event !== 'string')) {
|
|
134
|
+
if (eventsArray.length && eventsArray.some((event) => typeof event !== 'string')) {
|
|
133
135
|
throw new TypeError('events should be string or string array')
|
|
134
136
|
}
|
|
135
137
|
|
|
136
|
-
if (contextsArray.length && contextsArray.some(
|
|
137
|
-
context => typeof context !== 'string')) {
|
|
138
|
+
if (contextsArray.length && contextsArray.some((context) => typeof context !== 'string')) {
|
|
138
139
|
throw new TypeError('browsingContexts should be string or string array')
|
|
139
140
|
}
|
|
140
141
|
|
|
@@ -155,24 +156,24 @@ class Index extends EventEmitter {
|
|
|
155
156
|
* @param browsingContexts
|
|
156
157
|
* @returns {Promise<void>}
|
|
157
158
|
*/
|
|
158
|
-
async unsubscribe
|
|
159
|
+
async unsubscribe(events, browsingContexts) {
|
|
159
160
|
if (typeof events === 'string') {
|
|
160
|
-
this.events = this.events.filter(event => event !== events)
|
|
161
|
+
this.events = this.events.filter((event) => event !== events)
|
|
161
162
|
} else if (Array.isArray(events)) {
|
|
162
|
-
this.events = this.events.filter(event => !events.includes(event))
|
|
163
|
+
this.events = this.events.filter((event) => !events.includes(event))
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
if (typeof browsingContexts === 'string') {
|
|
166
167
|
this.browsingContexts.pop()
|
|
167
168
|
} else if (Array.isArray(browsingContexts)) {
|
|
168
|
-
this.browsingContexts =
|
|
169
|
-
this.browsingContexts.filter(id => !browsingContexts.includes(id))
|
|
169
|
+
this.browsingContexts = this.browsingContexts.filter((id) => !browsingContexts.includes(id))
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
const params = {
|
|
173
|
-
method: 'session.unsubscribe',
|
|
173
|
+
method: 'session.unsubscribe',
|
|
174
|
+
params: {
|
|
174
175
|
events: this.events,
|
|
175
|
-
}
|
|
176
|
+
},
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
if (this.browsingContexts.length > 0) {
|
|
@@ -186,9 +187,10 @@ class Index extends EventEmitter {
|
|
|
186
187
|
* Get Bidi Status
|
|
187
188
|
* @returns {Promise<*>}
|
|
188
189
|
*/
|
|
189
|
-
get status
|
|
190
|
+
get status() {
|
|
190
191
|
return this.send({
|
|
191
|
-
method: 'session.status',
|
|
192
|
+
method: 'session.status',
|
|
193
|
+
params: {},
|
|
192
194
|
})
|
|
193
195
|
}
|
|
194
196
|
|
|
@@ -196,7 +198,7 @@ class Index extends EventEmitter {
|
|
|
196
198
|
* Close ws connection.
|
|
197
199
|
* @returns {Promise<unknown>}
|
|
198
200
|
*/
|
|
199
|
-
close
|
|
201
|
+
close() {
|
|
200
202
|
const closeWebSocket = (callback) => {
|
|
201
203
|
// don't close if it's already closed
|
|
202
204
|
if (this._ws.readyState === 3) {
|
|
@@ -211,7 +213,7 @@ class Index extends EventEmitter {
|
|
|
211
213
|
this._ws.close()
|
|
212
214
|
}
|
|
213
215
|
}
|
|
214
|
-
return new Promise((fulfill,
|
|
216
|
+
return new Promise((fulfill, _) => {
|
|
215
217
|
closeWebSocket(fulfill)
|
|
216
218
|
})
|
|
217
219
|
}
|