selenium-webdriver 4.17.0 → 4.18.1
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 +240 -196
- package/bidi/addInterceptParameters.js +86 -0
- package/bidi/browsingContext.js +144 -37
- 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 +1 -4
- package/bidi/interceptPhase.js +24 -0
- package/bidi/logInspector.js +15 -20
- package/bidi/network.js +178 -0
- package/bidi/networkInspector.js +8 -2
- package/bidi/networkTypes.js +22 -49
- package/bidi/protocolType.js +3 -9
- package/bidi/protocolValue.js +6 -25
- package/bidi/realmInfo.js +2 -10
- package/bidi/scriptManager.js +20 -59
- 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 +1 -8
- package/chromium.js +27 -109
- package/common/driverFinder.js +1 -1
- package/common/seleniumManager.js +9 -18
- 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 +55 -109
- package/http/index.js +7 -10
- package/ie.js +5 -15
- package/index.js +7 -29
- package/io/exec.js +1 -2
- package/io/index.js +3 -3
- package/io/zip.js +8 -30
- package/lib/by.js +2 -9
- package/lib/capabilities.js +3 -9
- package/lib/command.js +3 -3
- package/lib/error.js +2 -9
- package/lib/http.js +34 -131
- package/lib/input.js +10 -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 +118 -297
- 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
|
@@ -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
|
/**
|
|
@@ -203,11 +239,7 @@ class BrowsingContext {
|
|
|
203
239
|
return response['result']['data']
|
|
204
240
|
}
|
|
205
241
|
|
|
206
|
-
async captureElementScreenshot(
|
|
207
|
-
sharedId,
|
|
208
|
-
handle = undefined,
|
|
209
|
-
scrollIntoView = undefined
|
|
210
|
-
) {
|
|
242
|
+
async captureElementScreenshot(sharedId, handle = undefined, scrollIntoView = undefined) {
|
|
211
243
|
let params = {
|
|
212
244
|
method: 'browsingContext.captureScreenshot',
|
|
213
245
|
params: {
|
|
@@ -273,13 +305,8 @@ class BrowsingContext {
|
|
|
273
305
|
}
|
|
274
306
|
|
|
275
307
|
async reload(ignoreCache = undefined, readinessState = undefined) {
|
|
276
|
-
if (
|
|
277
|
-
|
|
278
|
-
!['none', 'interactive', 'complete'].includes(readinessState)
|
|
279
|
-
) {
|
|
280
|
-
throw Error(
|
|
281
|
-
`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`
|
|
282
|
-
)
|
|
308
|
+
if (readinessState !== undefined && !['none', 'interactive', 'complete'].includes(readinessState)) {
|
|
309
|
+
throw Error(`Valid readiness states are 'none', 'interactive' & 'complete'. Received: ${readinessState}`)
|
|
283
310
|
}
|
|
284
311
|
|
|
285
312
|
const params = {
|
|
@@ -292,10 +319,7 @@ class BrowsingContext {
|
|
|
292
319
|
}
|
|
293
320
|
const navigateResult = (await this.bidi.send(params))['result']
|
|
294
321
|
|
|
295
|
-
return new NavigateResult(
|
|
296
|
-
navigateResult['url'],
|
|
297
|
-
navigateResult['navigation']
|
|
298
|
-
)
|
|
322
|
+
return new NavigateResult(navigateResult['url'], navigateResult['navigation'])
|
|
299
323
|
}
|
|
300
324
|
|
|
301
325
|
async setViewport(width, height, devicePixelRatio = undefined) {
|
|
@@ -331,6 +355,91 @@ class BrowsingContext {
|
|
|
331
355
|
async back() {
|
|
332
356
|
await this.traverseHistory(-1)
|
|
333
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
|
+
}
|
|
334
443
|
}
|
|
335
444
|
|
|
336
445
|
class NavigateResult {
|
|
@@ -366,10 +475,7 @@ class PrintResult {
|
|
|
366
475
|
* @param referenceContext To get a browsing context for this reference if passed
|
|
367
476
|
* @returns {Promise<BrowsingContext>}
|
|
368
477
|
*/
|
|
369
|
-
async function getBrowsingContextInstance(
|
|
370
|
-
driver,
|
|
371
|
-
{ browsingContextId, type, referenceContext }
|
|
372
|
-
) {
|
|
478
|
+
async function getBrowsingContextInstance(driver, { browsingContextId, type, referenceContext }) {
|
|
373
479
|
let instance = new BrowsingContext(driver)
|
|
374
480
|
await instance.init({ browsingContextId, type, referenceContext })
|
|
375
481
|
return instance
|
|
@@ -380,3 +486,4 @@ async function getBrowsingContextInstance(
|
|
|
380
486
|
* @type {function(*, {*,*,*}): Promise<BrowsingContext>}
|
|
381
487
|
*/
|
|
382
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
|
}
|
package/bidi/input.js
CHANGED
|
@@ -67,10 +67,7 @@ async function updateActions(actions) {
|
|
|
67
67
|
|
|
68
68
|
if (action.type === 'pointer' || action.type === 'wheel') {
|
|
69
69
|
for (const sequence of sequenceList) {
|
|
70
|
-
if (
|
|
71
|
-
(sequence.type === 'pointerMove' || sequence.type === 'scroll') &&
|
|
72
|
-
sequence.origin instanceof WebElement
|
|
73
|
-
) {
|
|
70
|
+
if ((sequence.type === 'pointerMove' || sequence.type === 'scroll') && sequence.origin instanceof WebElement) {
|
|
74
71
|
const element = sequence.origin
|
|
75
72
|
const elementId = await element.getId()
|
|
76
73
|
sequence.origin = {
|
|
@@ -0,0 +1,24 @@
|
|
|
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 InterceptPhase = {
|
|
19
|
+
BEFORE_REQUEST_SENT: 'beforeRequestSent',
|
|
20
|
+
RESPONSE_STARTED: 'responseStarted',
|
|
21
|
+
AUTH_REQUIRED: 'authRequired',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {InterceptPhase}
|