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.
Files changed (65) hide show
  1. package/CHANGES.md +253 -196
  2. package/LICENSE +1 -1
  3. package/NOTICE +1 -1
  4. package/bidi/addInterceptParameters.js +86 -0
  5. package/bidi/browsingContext.js +167 -38
  6. package/bidi/browsingContextInspector.js +13 -40
  7. package/bidi/evaluateResult.js +4 -10
  8. package/bidi/filterBy.js +2 -6
  9. package/bidi/index.js +31 -29
  10. package/bidi/input.js +97 -0
  11. package/bidi/interceptPhase.js +24 -0
  12. package/bidi/logInspector.js +15 -20
  13. package/bidi/network.js +178 -0
  14. package/bidi/networkInspector.js +12 -2
  15. package/bidi/networkTypes.js +22 -49
  16. package/bidi/protocolType.js +4 -9
  17. package/bidi/protocolValue.js +48 -17
  18. package/bidi/realmInfo.js +3 -10
  19. package/bidi/scriptManager.js +60 -48
  20. package/bidi/scriptTypes.js +58 -0
  21. package/bidi/urlPattern.js +58 -0
  22. package/bin/linux/selenium-manager +0 -0
  23. package/bin/macos/selenium-manager +0 -0
  24. package/bin/windows/selenium-manager.exe +0 -0
  25. package/chrome.js +2 -14
  26. package/chromium.js +28 -143
  27. package/common/driverFinder.js +1 -1
  28. package/common/seleniumManager.js +5 -12
  29. package/devtools/CDPConnection.js +1 -3
  30. package/edge.js +1 -3
  31. package/example/chrome_android.js +2 -5
  32. package/example/chrome_mobile_emulation.js +2 -4
  33. package/example/google_search.js +1 -3
  34. package/example/headless.js +4 -10
  35. package/example/logging.js +3 -9
  36. package/firefox.js +37 -111
  37. package/http/index.js +7 -10
  38. package/ie.js +5 -15
  39. package/index.js +10 -32
  40. package/io/exec.js +1 -2
  41. package/io/index.js +3 -3
  42. package/io/zip.js +8 -30
  43. package/lib/atoms/find-elements.js +1 -1
  44. package/lib/atoms/get-attribute.js +6 -100
  45. package/lib/by.js +2 -9
  46. package/lib/capabilities.js +8 -7
  47. package/lib/command.js +4 -0
  48. package/lib/error.js +2 -9
  49. package/lib/http.js +37 -130
  50. package/lib/input.js +22 -34
  51. package/lib/logging.js +3 -11
  52. package/lib/promise.js +2 -7
  53. package/lib/select.js +3 -9
  54. package/lib/until.js +28 -49
  55. package/lib/util.js +1 -4
  56. package/lib/virtual_authenticator.js +4 -22
  57. package/lib/webdriver.js +146 -269
  58. package/lib/webelement.js +1 -5
  59. package/net/index.js +1 -4
  60. package/package.json +2 -1
  61. package/remote/index.js +9 -24
  62. package/remote/util.js +6 -19
  63. package/safari.js +3 -8
  64. package/testing/index.js +6 -11
  65. 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 2023 Software Freedom Conservancy (SFC)
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-2023 Software Freedom Conservancy
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}
@@ -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
- readinessState !== undefined &&
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: 'viewport',
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
- readinessState !== undefined &&
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
- 'browsingContext.contextCreated',
36
- callback
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
  }
@@ -38,16 +38,10 @@ class EvaluateResultException {
38
38
 
39
39
  class ExceptionDetails {
40
40
  constructor(exceptionDetails) {
41
- this.columnNumber =
42
- 'columnNumber' in exceptionDetails
43
- ? exceptionDetails['columnNumber']
44
- : null
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
- isConnected = false
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 (_webSocketUrl) {
34
+ constructor(_webSocketUrl) {
34
35
  super()
35
- this.isConnected = false
36
+ this.connected = false
36
37
  this._ws = new WebSocket(_webSocketUrl)
37
38
  this._ws.on('open', () => {
38
- this.isConnected = true
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.isConnected) {
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.isConnected
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 (params) {
78
- if (!this.isConnected) {
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 (events, browsingContexts) {
116
- function toArray (arg) {
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', params: {},
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 (events, browsingContexts) {
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', params: {
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', params: {}
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, reject) => {
216
+ return new Promise((fulfill, _) => {
215
217
  closeWebSocket(fulfill)
216
218
  })
217
219
  }