selenium-webdriver 4.0.0-alpha.7 → 4.0.0-beta.3

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 (50) hide show
  1. package/CHANGES.md +56 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +2 -0
  4. package/README.md +2 -0
  5. package/chrome.js +69 -79
  6. package/chromium.js +231 -164
  7. package/{lib/atoms/make-atoms-module.js → devtools/CDPConnection.js} +15 -9
  8. package/edge.js +104 -146
  9. package/example/chrome_android.js +45 -0
  10. package/example/chrome_mobile_emulation.js +46 -0
  11. package/example/firefox_channels.js +84 -0
  12. package/example/google_search.js +50 -0
  13. package/example/google_search_test.js +70 -0
  14. package/example/headless.js +63 -0
  15. package/example/logging.js +64 -0
  16. package/firefox.js +199 -200
  17. package/http/index.js +128 -116
  18. package/http/util.js +56 -64
  19. package/ie.js +180 -104
  20. package/index.js +246 -199
  21. package/io/exec.js +35 -40
  22. package/io/index.js +146 -157
  23. package/io/zip.js +75 -66
  24. package/lib/atoms/find-elements.js +123 -0
  25. package/lib/atoms/get-attribute.js +75 -59
  26. package/lib/atoms/is-displayed.js +72 -72
  27. package/lib/atoms/mutation-listener.js +55 -0
  28. package/lib/by.js +192 -65
  29. package/lib/capabilities.js +76 -86
  30. package/lib/command.js +19 -35
  31. package/lib/error.js +134 -168
  32. package/lib/http.js +308 -232
  33. package/lib/input.js +192 -453
  34. package/lib/logging.js +126 -137
  35. package/lib/promise.js +53 -71
  36. package/lib/proxy.js +31 -41
  37. package/lib/session.js +12 -15
  38. package/lib/symbols.js +3 -4
  39. package/lib/until.js +162 -160
  40. package/lib/webdriver.js +1014 -549
  41. package/net/index.js +30 -36
  42. package/net/portprober.js +30 -143
  43. package/opera.js +406 -0
  44. package/package.json +15 -7
  45. package/proxy.js +2 -2
  46. package/remote/index.js +189 -187
  47. package/safari.js +40 -49
  48. package/testing/index.js +504 -0
  49. package/lib/README +0 -5
  50. package/lib/actions.js +0 -609
package/lib/webdriver.js CHANGED
@@ -19,33 +19,37 @@
19
19
  * @fileoverview The heart of the WebDriver JavaScript API.
20
20
  */
21
21
 
22
- 'use strict';
23
-
24
- const by = require('./by');
25
- const command = require('./command');
26
- const error = require('./error');
27
- const input = require('./input');
28
- const logging = require('./logging');
29
- const promise = require('./promise');
30
- const Symbols = require('./symbols');
31
- const {Capabilities} = require('./capabilities');
32
- const {Session} = require('./session');
33
-
22
+ 'use strict'
23
+
24
+ const by = require('./by')
25
+ const { RelativeBy } = require('./by')
26
+ const command = require('./command')
27
+ const error = require('./error')
28
+ const input = require('./input')
29
+ const logging = require('./logging')
30
+ const promise = require('./promise')
31
+ const Symbols = require('./symbols')
32
+ const cdpTargets = ['page', 'browser']
33
+ const cdp = require('../devtools/CDPConnection')
34
+ const WebSocket = require('ws')
35
+ const http = require('../http/index')
36
+ const fs = require('fs')
37
+ const { Capabilities } = require('./capabilities')
38
+ const path = require('path')
34
39
 
35
40
  // Capability names that are defined in the W3C spec.
36
41
  const W3C_CAPABILITY_NAMES = new Set([
37
- 'acceptInsecureCerts',
38
- 'browserName',
39
- 'browserVersion',
40
- 'platformName',
41
- 'pageLoadStrategy',
42
- 'proxy',
43
- 'setWindowRect',
44
- 'timeouts',
45
- 'strictFileInteractability',
46
- 'unhandledPromptBehavior',
47
- ]);
48
-
42
+ 'acceptInsecureCerts',
43
+ 'browserName',
44
+ 'browserVersion',
45
+ 'platformName',
46
+ 'pageLoadStrategy',
47
+ 'proxy',
48
+ 'setWindowRect',
49
+ 'timeouts',
50
+ 'strictFileInteractability',
51
+ 'unhandledPromptBehavior',
52
+ ])
49
53
 
50
54
  /**
51
55
  * Defines a condition for use with WebDriver's {@linkplain WebDriver#wait wait
@@ -62,19 +66,18 @@ class Condition {
62
66
  */
63
67
  constructor(message, fn) {
64
68
  /** @private {string} */
65
- this.description_ = 'Waiting ' + message;
69
+ this.description_ = 'Waiting ' + message
66
70
 
67
71
  /** @type {function(!WebDriver): OUT} */
68
- this.fn = fn;
72
+ this.fn = fn
69
73
  }
70
74
 
71
75
  /** @return {string} A description of this condition. */
72
76
  description() {
73
- return this.description_;
77
+ return this.description_
74
78
  }
75
79
  }
76
80
 
77
-
78
81
  /**
79
82
  * Defines a condition that will result in a {@link WebElement}.
80
83
  *
@@ -89,18 +92,16 @@ class WebElementCondition extends Condition {
89
92
  * loop.
90
93
  */
91
94
  constructor(message, fn) {
92
- super(message, fn);
95
+ super(message, fn)
93
96
  }
94
97
  }
95
98
 
96
-
97
99
  //////////////////////////////////////////////////////////////////////////////
98
100
  //
99
101
  // WebDriver
100
102
  //
101
103
  //////////////////////////////////////////////////////////////////////////////
102
104
 
103
-
104
105
  /**
105
106
  * Translates a command to its wire-protocol representation before passing it
106
107
  * to the given `executor` for execution.
@@ -109,14 +110,12 @@ class WebElementCondition extends Condition {
109
110
  * @return {!Promise} A promise that will resolve with the command response.
110
111
  */
111
112
  function executeCommand(executor, command) {
112
- return toWireValue(command.getParameters()).
113
- then(function(parameters) {
114
- command.setParameters(parameters);
115
- return executor.execute(command);
116
- });
113
+ return toWireValue(command.getParameters()).then(function (parameters) {
114
+ command.setParameters(parameters)
115
+ return executor.execute(command)
116
+ })
117
117
  }
118
118
 
119
-
120
119
  /**
121
120
  * Converts an object to its JSON representation in the WebDriver wire protocol.
122
121
  * When converting values of type object, the following steps will be taken:
@@ -136,64 +135,62 @@ function executeCommand(executor, command) {
136
135
  * representation.
137
136
  */
138
137
  async function toWireValue(obj) {
139
- let value = await Promise.resolve(obj);
138
+ let value = await Promise.resolve(obj)
140
139
  if (value === void 0 || value === null) {
141
- return value;
140
+ return value
142
141
  }
143
142
 
144
- if (typeof value === 'boolean'
145
- || typeof value === 'number'
146
- || typeof value === 'string') {
147
- return value;
143
+ if (
144
+ typeof value === 'boolean' ||
145
+ typeof value === 'number' ||
146
+ typeof value === 'string'
147
+ ) {
148
+ return value
148
149
  }
149
150
 
150
151
  if (Array.isArray(value)) {
151
- return convertKeys(value);
152
+ return convertKeys(value)
152
153
  }
153
154
 
154
155
  if (typeof value === 'function') {
155
- return '' + value;
156
+ return '' + value
156
157
  }
157
158
 
158
159
  if (typeof value[Symbols.serialize] === 'function') {
159
- return toWireValue(value[Symbols.serialize]());
160
+ return toWireValue(value[Symbols.serialize]())
160
161
  } else if (typeof value.toJSON === 'function') {
161
- return toWireValue(value.toJSON());
162
+ return toWireValue(value.toJSON())
162
163
  }
163
- return convertKeys(value);
164
+ return convertKeys(value)
164
165
  }
165
166
 
166
-
167
167
  async function convertKeys(obj) {
168
- const isArray = Array.isArray(obj);
169
- const numKeys = isArray ? obj.length : Object.keys(obj).length;
170
- const ret = isArray ? new Array(numKeys) : {};
168
+ const isArray = Array.isArray(obj)
169
+ const numKeys = isArray ? obj.length : Object.keys(obj).length
170
+ const ret = isArray ? new Array(numKeys) : {}
171
171
  if (!numKeys) {
172
- return ret;
172
+ return ret
173
173
  }
174
174
 
175
- let numResolved = 0;
176
-
177
175
  async function forEachKey(obj, fn) {
178
176
  if (Array.isArray(obj)) {
179
177
  for (let i = 0, n = obj.length; i < n; i++) {
180
- await fn(obj[i], i);
178
+ await fn(obj[i], i)
181
179
  }
182
180
  } else {
183
181
  for (let key in obj) {
184
- await fn(obj[key], key);
182
+ await fn(obj[key], key)
185
183
  }
186
184
  }
187
185
  }
188
186
 
189
- await forEachKey(obj, async function(value, key) {
190
- ret[key] = await toWireValue(value);
191
- });
187
+ await forEachKey(obj, async function (value, key) {
188
+ ret[key] = await toWireValue(value)
189
+ })
192
190
 
193
- return ret;
191
+ return ret
194
192
  }
195
193
 
196
-
197
194
  /**
198
195
  * Converts a value from its JSON representation according to the WebDriver wire
199
196
  * protocol. Any JSON object that defines a WebElement ID will be decoded to a
@@ -206,22 +203,32 @@ async function convertKeys(obj) {
206
203
  */
207
204
  function fromWireValue(driver, value) {
208
205
  if (Array.isArray(value)) {
209
- value = value.map(v => fromWireValue(driver, v));
206
+ value = value.map((v) => fromWireValue(driver, v))
210
207
  } else if (WebElement.isId(value)) {
211
- let id = WebElement.extractId(value);
212
- value = new WebElement(driver, id);
208
+ let id = WebElement.extractId(value)
209
+ value = new WebElement(driver, id)
213
210
  } else if (value && typeof value === 'object') {
214
- let result = {};
211
+ let result = {}
215
212
  for (let key in value) {
216
- if (value.hasOwnProperty(key)) {
217
- result[key] = fromWireValue(driver, value[key]);
213
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
214
+ result[key] = fromWireValue(driver, value[key])
218
215
  }
219
216
  }
220
- value = result;
217
+ value = result
221
218
  }
222
- return value;
219
+ return value
223
220
  }
224
221
 
222
+ /**
223
+ * Resolves a wait message from either a function or a string.
224
+ * @param {(string|Function)=} message An optional message to use if the wait times out.
225
+ * @return {string} The resolved message
226
+ */
227
+ function resolveWaitMessage(message) {
228
+ return message
229
+ ? `${typeof message === 'function' ? message() : message}\n`
230
+ : ''
231
+ }
225
232
 
226
233
  /**
227
234
  * Structural interface for a WebDriver client.
@@ -229,7 +236,6 @@ function fromWireValue(driver, value) {
229
236
  * @record
230
237
  */
231
238
  class IWebDriver {
232
-
233
239
  /**
234
240
  * Executes the provided {@link command.Command} using this driver's
235
241
  * {@link command.Executor}.
@@ -239,30 +245,30 @@ class IWebDriver {
239
245
  * result.
240
246
  * @template T
241
247
  */
242
- execute(command) {}
248
+ execute(command) { } // eslint-disable-line
243
249
 
244
250
  /**
245
251
  * Sets the {@linkplain input.FileDetector file detector} that should be
246
252
  * used with this instance.
247
253
  * @param {input.FileDetector} detector The detector to use or `null`.
248
254
  */
249
- setFileDetector(detector) {}
255
+ setFileDetector(detector) { } // eslint-disable-line
250
256
 
251
257
  /**
252
258
  * @return {!command.Executor} The command executor used by this instance.
253
259
  */
254
- getExecutor() {}
260
+ getExecutor() { }
255
261
 
256
262
  /**
257
263
  * @return {!Promise<!Session>} A promise for this client's session.
258
264
  */
259
- getSession() {}
265
+ getSession() { }
260
266
 
261
267
  /**
262
268
  * @return {!Promise<!Capabilities>} A promise that will resolve with
263
269
  * the this instance's capabilities.
264
270
  */
265
- getCapabilities() {}
271
+ getCapabilities() { }
266
272
 
267
273
  /**
268
274
  * Terminates the browser session. After calling quit, this instance will be
@@ -272,7 +278,7 @@ class IWebDriver {
272
278
  * @return {!Promise<void>} A promise that will be resolved when the
273
279
  * command has completed.
274
280
  */
275
- quit() {}
281
+ quit() { }
276
282
 
277
283
  /**
278
284
  * Creates a new action sequence using this driver. The sequence will not be
@@ -285,7 +291,7 @@ class IWebDriver {
285
291
  * for details).
286
292
  * @return {!input.Actions} A new action sequence for this instance.
287
293
  */
288
- actions(options) {}
294
+ actions(options) { } // eslint-disable-line
289
295
 
290
296
  /**
291
297
  * Executes a snippet of JavaScript in the context of the currently selected
@@ -323,7 +329,7 @@ class IWebDriver {
323
329
  * scripts return value.
324
330
  * @template T
325
331
  */
326
- executeScript(script, ...args) {}
332
+ executeScript(script, ...args) { } // eslint-disable-line
327
333
 
328
334
  /**
329
335
  * Executes a snippet of asynchronous JavaScript in the context of the
@@ -400,7 +406,7 @@ class IWebDriver {
400
406
  * value.
401
407
  * @template T
402
408
  */
403
- executeAsyncScript(script, ...args) {}
409
+ executeAsyncScript(script, ...args) { } // eslint-disable-line
404
410
 
405
411
  /**
406
412
  * Waits for a condition to evaluate to a "truthy" value. The condition may be
@@ -435,7 +441,7 @@ class IWebDriver {
435
441
  * evaluate as a condition.
436
442
  * @param {number=} timeout The duration in milliseconds, how long to wait
437
443
  * for the condition to be true.
438
- * @param {string=} message An optional message to use if the wait times out.
444
+ * @param {(string|Function)=} message An optional message to use if the wait times out.
439
445
  * @param {number=} pollTimeout The duration in milliseconds, how long to
440
446
  * wait between polling the condition.
441
447
  * @return {!(IThenable<T>|WebElementPromise)} A promise that will be
@@ -446,7 +452,12 @@ class IWebDriver {
446
452
  * @throws {TypeError} if the provided `condition` is not a valid type.
447
453
  * @template T
448
454
  */
449
- wait(condition, timeout = undefined, message = undefined, pollTimeout = undefined) {}
455
+ wait(
456
+ condition, // eslint-disable-line
457
+ timeout = undefined, // eslint-disable-line
458
+ message = undefined, // eslint-disable-line
459
+ pollTimeout = undefined // eslint-disable-line
460
+ ) { }
450
461
 
451
462
  /**
452
463
  * Makes the driver sleep for the given amount of time.
@@ -455,7 +466,7 @@ class IWebDriver {
455
466
  * @return {!Promise<void>} A promise that will be resolved when the sleep has
456
467
  * finished.
457
468
  */
458
- sleep(ms) {}
469
+ sleep(ms) { } // eslint-disable-line
459
470
 
460
471
  /**
461
472
  * Retrieves the current window handle.
@@ -463,7 +474,7 @@ class IWebDriver {
463
474
  * @return {!Promise<string>} A promise that will be resolved with the current
464
475
  * window handle.
465
476
  */
466
- getWindowHandle() {}
477
+ getWindowHandle() { }
467
478
 
468
479
  /**
469
480
  * Retrieves a list of all available window handles.
@@ -471,17 +482,17 @@ class IWebDriver {
471
482
  * @return {!Promise<!Array<string>>} A promise that will be resolved with an
472
483
  * array of window handles.
473
484
  */
474
- getAllWindowHandles() {}
485
+ getAllWindowHandles() { }
475
486
 
476
487
  /**
477
- * Retrieves the current page's source. The returned souce is a representation
488
+ * Retrieves the current page's source. The returned source is a representation
478
489
  * of the underlying DOM: do not expect it to be formatted or escaped in the
479
490
  * same way as the raw response sent from the web server.
480
491
  *
481
492
  * @return {!Promise<string>} A promise that will be resolved with the current
482
493
  * page source.
483
494
  */
484
- getPageSource() {}
495
+ getPageSource() { }
485
496
 
486
497
  /**
487
498
  * Closes the current window.
@@ -489,7 +500,7 @@ class IWebDriver {
489
500
  * @return {!Promise<void>} A promise that will be resolved when this command
490
501
  * has completed.
491
502
  */
492
- close() {}
503
+ close() { }
493
504
 
494
505
  /**
495
506
  * Navigates to the given URL.
@@ -498,7 +509,7 @@ class IWebDriver {
498
509
  * @return {!Promise<void>} A promise that will be resolved when the document
499
510
  * has finished loading.
500
511
  */
501
- get(url) {}
512
+ get(url) { } // eslint-disable-line
502
513
 
503
514
  /**
504
515
  * Retrieves the URL for the current page.
@@ -506,7 +517,7 @@ class IWebDriver {
506
517
  * @return {!Promise<string>} A promise that will be resolved with the
507
518
  * current URL.
508
519
  */
509
- getCurrentUrl() {}
520
+ getCurrentUrl() { }
510
521
 
511
522
  /**
512
523
  * Retrieves the current page title.
@@ -514,11 +525,11 @@ class IWebDriver {
514
525
  * @return {!Promise<string>} A promise that will be resolved with the current
515
526
  * page's title.
516
527
  */
517
- getTitle() {}
528
+ getTitle() { }
518
529
 
519
530
  /**
520
531
  * Locates an element on the page. If the element cannot be found, a
521
- * {@link error.NoSuchEementError} will be returned by the driver.
532
+ * {@link error.NoSuchElementError} will be returned by the driver.
522
533
  *
523
534
  * This function should not be used to test whether an element is present on
524
535
  * the page. Rather, you should use {@link #findElements}:
@@ -554,7 +565,7 @@ class IWebDriver {
554
565
  * commands against the located element. If the element is not found, the
555
566
  * element will be invalidated and all scheduled commands aborted.
556
567
  */
557
- findElement(locator) {}
568
+ findElement(locator) { } // eslint-disable-line
558
569
 
559
570
  /**
560
571
  * Search for multiple elements on the page. Refer to the documentation on
@@ -564,7 +575,7 @@ class IWebDriver {
564
575
  * @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
565
576
  * array of WebElements.
566
577
  */
567
- findElements(locator) {}
578
+ findElements(locator) { } // eslint-disable-line
568
579
 
569
580
  /**
570
581
  * Takes a screenshot of the current page. The driver makes a best effort to
@@ -578,25 +589,43 @@ class IWebDriver {
578
589
  * @return {!Promise<string>} A promise that will be resolved to the
579
590
  * screenshot as a base-64 encoded PNG.
580
591
  */
581
- takeScreenshot() {}
592
+ takeScreenshot() { }
582
593
 
583
594
  /**
584
595
  * @return {!Options} The options interface for this instance.
585
596
  */
586
- manage() {}
597
+ manage() { }
587
598
 
588
599
  /**
589
600
  * @return {!Navigation} The navigation interface for this instance.
590
601
  */
591
- navigate() {}
602
+ navigate() { }
592
603
 
593
604
  /**
594
605
  * @return {!TargetLocator} The target locator interface for this
595
606
  * instance.
596
607
  */
597
- switchTo() {}
598
- }
608
+ switchTo() { }
599
609
 
610
+ /**
611
+ *
612
+ * Takes a PDF of the current page. The driver makes a best effort to
613
+ * return a PDF based on the provided parameters.
614
+ *
615
+ * @param {{orientation: (string|undefined),
616
+ * scale: (number|undefined),
617
+ * background: (boolean|undefined)
618
+ * width: (number|undefined)
619
+ * height: (number|undefined)
620
+ * top: (number|undefined)
621
+ * bottom: (number|undefined)
622
+ * left: (number|undefined)
623
+ * right: (number|undefined)
624
+ * shrinkToFit: (boolean|undefined)
625
+ * pageRanges: (<Array>|undefined)}} options.
626
+ */
627
+ printPage(options) { } // eslint-disable-line
628
+ }
600
629
 
601
630
  /**
602
631
  * @param {!Capabilities} capabilities A capabilities object.
@@ -604,23 +633,23 @@ class IWebDriver {
604
633
  * capability names that are not valid W3C names.
605
634
  */
606
635
  function filterNonW3CCaps(capabilities) {
607
- let newCaps = new Capabilities(capabilities);
636
+ let newCaps = new Capabilities(capabilities)
608
637
  for (let k of newCaps.keys()) {
609
638
  // Any key containing a colon is a vendor-prefixed capability.
610
639
  if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
611
- newCaps.delete(k);
640
+ newCaps.delete(k)
612
641
  }
613
642
  }
614
- return newCaps;
643
+ return newCaps
615
644
  }
616
645
 
617
-
618
646
  /**
619
647
  * Each WebDriver instance provides automated control over a browser session.
620
648
  *
621
649
  * @implements {IWebDriver}
622
650
  */
623
651
  class WebDriver {
652
+
624
653
  /**
625
654
  * @param {!(./session.Session|IThenable<!./session.Session>)} session Either
626
655
  * a known session or a promise that will be resolved to a session.
@@ -631,21 +660,21 @@ class WebDriver {
631
660
  */
632
661
  constructor(session, executor, onQuit = undefined) {
633
662
  /** @private {!Promise<!Session>} */
634
- this.session_ = Promise.resolve(session);
663
+ this.session_ = Promise.resolve(session)
635
664
 
636
665
  // If session is a rejected promise, add a no-op rejection handler.
637
666
  // This effectively hides setup errors until users attempt to interact
638
667
  // with the session.
639
- this.session_.catch(function() {});
668
+ this.session_.catch(function () { })
640
669
 
641
670
  /** @private {!command.Executor} */
642
- this.executor_ = executor;
671
+ this.executor_ = executor
643
672
 
644
673
  /** @private {input.FileDetector} */
645
- this.fileDetector_ = null;
674
+ this.fileDetector_ = null
646
675
 
647
676
  /** @private @const {(function(this: void): ?|undefined)} */
648
- this.onQuit_ = onQuit;
677
+ this.onQuit_ = onQuit
649
678
  }
650
679
 
651
680
  /**
@@ -674,251 +703,285 @@ class WebDriver {
674
703
  * @return {!WebDriver} The driver for the newly created session.
675
704
  */
676
705
  static createSession(executor, capabilities, onQuit = undefined) {
677
- let cmd = new command.Command(command.Name.NEW_SESSION);
706
+ let cmd = new command.Command(command.Name.NEW_SESSION)
678
707
 
679
708
  // For OSS remote ends.
680
- cmd.setParameter('desiredCapabilities', capabilities);
709
+ cmd.setParameter('desiredCapabilities', capabilities)
681
710
  // For W3C remote ends.
682
711
  cmd.setParameter('capabilities', {
683
712
  alwaysMatch: filterNonW3CCaps(capabilities),
684
- });
713
+ })
685
714
 
686
- let session = executeCommand(executor, cmd);
715
+ let session = executeCommand(executor, cmd)
687
716
  if (typeof onQuit === 'function') {
688
- session = session.catch(err => {
689
- return Promise.resolve(onQuit.call(void 0)).then(_ => {throw err;});
690
- });
717
+ session = session.catch((err) => {
718
+ return Promise.resolve(onQuit.call(void 0)).then((_) => {
719
+ throw err
720
+ })
721
+ })
691
722
  }
692
- return new this(session, executor, onQuit);
723
+ return new this(session, executor, onQuit)
693
724
  }
694
725
 
695
726
  /** @override */
696
727
  async execute(command) {
697
- command.setParameter('sessionId', this.session_);
698
- let parameters = await toWireValue(command.getParameters());
699
- command.setParameters(parameters);
700
- let value = await this.executor_.execute(command);
701
- return fromWireValue(this, value);
728
+ command.setParameter('sessionId', this.session_)
729
+ let parameters = await toWireValue(command.getParameters())
730
+ command.setParameters(parameters)
731
+ let value = await this.executor_.execute(command)
732
+ return fromWireValue(this, value)
702
733
  }
703
734
 
704
735
  /** @override */
705
736
  setFileDetector(detector) {
706
- this.fileDetector_ = detector;
737
+ this.fileDetector_ = detector
707
738
  }
708
739
 
709
740
  /** @override */
710
741
  getExecutor() {
711
- return this.executor_;
742
+ return this.executor_
712
743
  }
713
744
 
714
745
  /** @override */
715
746
  getSession() {
716
- return this.session_;
747
+ return this.session_
717
748
  }
718
749
 
719
750
  /** @override */
720
751
  getCapabilities() {
721
- return this.session_.then(s => s.getCapabilities());
752
+ return this.session_.then((s) => s.getCapabilities())
722
753
  }
723
754
 
724
755
  /** @override */
725
756
  quit() {
726
- let result = this.execute(new command.Command(command.Name.QUIT));
757
+ let result = this.execute(new command.Command(command.Name.QUIT))
727
758
  // Delete our session ID when the quit command finishes; this will allow us
728
759
  // to throw an error when attempting to use a driver post-quit.
729
760
  return promise.finally(result, () => {
730
- this.session_ = Promise.reject(new error.NoSuchSessionError(
731
- 'This driver instance does not have a valid session ID ' +
732
- '(did you call WebDriver.quit()?) and may no longer be used.'));
761
+ this.session_ = Promise.reject(
762
+ new error.NoSuchSessionError(
763
+ 'This driver instance does not have a valid session ID ' +
764
+ '(did you call WebDriver.quit()?) and may no longer be used.'
765
+ )
766
+ )
733
767
 
734
768
  // Only want the session rejection to bubble if accessed.
735
- this.session_.catch(function() {});
769
+ this.session_.catch(function () { })
736
770
 
737
771
  if (this.onQuit_) {
738
- return this.onQuit_.call(void 0);
772
+ return this.onQuit_.call(void 0)
739
773
  }
740
- });
774
+ })
741
775
  }
742
776
 
743
777
  /** @override */
744
778
  actions(options) {
745
- return new input.Actions(this, options || undefined);
779
+ return new input.Actions(this, options || undefined)
746
780
  }
747
781
 
748
782
  /** @override */
749
783
  executeScript(script, ...args) {
750
784
  if (typeof script === 'function') {
751
- script = 'return (' + script + ').apply(null, arguments);';
785
+ script = 'return (' + script + ').apply(null, arguments);'
752
786
  }
753
- return this.execute(
754
- new command.Command(command.Name.EXECUTE_SCRIPT).
755
- setParameter('script', script).
756
- setParameter('args', args));
787
+ return this.execute(
788
+ new command.Command(command.Name.EXECUTE_SCRIPT)
789
+ .setParameter('script', script)
790
+ .setParameter('args', args)
791
+ )
757
792
  }
758
793
 
759
794
  /** @override */
760
795
  executeAsyncScript(script, ...args) {
761
796
  if (typeof script === 'function') {
762
- script = 'return (' + script + ').apply(null, arguments);';
797
+ script = 'return (' + script + ').apply(null, arguments);'
763
798
  }
764
799
  return this.execute(
765
- new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT).
766
- setParameter('script', script).
767
- setParameter('args', args));
800
+ new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
801
+ .setParameter('script', script)
802
+ .setParameter('args', args)
803
+ )
768
804
  }
769
805
 
770
806
  /** @override */
771
807
  wait(condition, timeout = 0, message = undefined, pollTimeout = 200) {
772
808
  if (typeof timeout !== 'number' || timeout < 0) {
773
- throw TypeError('timeout must be a number >= 0: ' + timeout);
809
+ throw TypeError('timeout must be a number >= 0: ' + timeout)
774
810
  }
775
811
 
776
812
  if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
777
- throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout);
813
+ throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
778
814
  }
779
815
 
780
816
  if (promise.isPromise(condition)) {
781
817
  return new Promise((resolve, reject) => {
782
818
  if (!timeout) {
783
- resolve(condition);
784
- return;
819
+ resolve(condition)
820
+ return
785
821
  }
786
822
 
787
- let start = Date.now();
788
- let timer = setTimeout(function() {
789
- timer = null;
790
- reject(
823
+ let start = Date.now()
824
+ let timer = setTimeout(function () {
825
+ timer = null
826
+ try {
827
+ let timeoutMessage = resolveWaitMessage(message)
828
+ reject(
791
829
  new error.TimeoutError(
792
- (message ? `${message}\n` : '')
793
- + 'Timed out waiting for promise to resolve after '
794
- + (Date.now() - start) + 'ms'));
795
- }, timeout);
796
- const clearTimer = () => timer && clearTimeout(timer);
797
-
798
- /** @type {!IThenable} */(condition).then(
799
- function(value) {
800
- clearTimer();
801
- resolve(value);
802
- },
803
- function(error) {
804
- clearTimer();
805
- reject(error);
806
- });
807
- });
830
+ `${timeoutMessage}Timed out waiting for promise to resolve after ${Date.now() - start
831
+ }ms`
832
+ )
833
+ )
834
+ } catch (ex) {
835
+ reject(
836
+ new error.TimeoutError(
837
+ `${ex.message
838
+ }\nTimed out waiting for promise to resolve after ${Date.now() - start
839
+ }ms`
840
+ )
841
+ )
842
+ }
843
+ }, timeout)
844
+ const clearTimer = () => timer && clearTimeout(timer)
845
+
846
+ /** @type {!IThenable} */ condition.then(
847
+ function (value) {
848
+ clearTimer()
849
+ resolve(value)
850
+ },
851
+ function (error) {
852
+ clearTimer()
853
+ reject(error)
854
+ }
855
+ )
856
+ })
808
857
  }
809
858
 
810
- let fn = /** @type {!Function} */(condition);
859
+ let fn = /** @type {!Function} */ (condition)
811
860
  if (condition instanceof Condition) {
812
- message = message || condition.description();
813
- fn = condition.fn;
861
+ message = message || condition.description()
862
+ fn = condition.fn
814
863
  }
815
864
 
816
865
  if (typeof fn !== 'function') {
817
866
  throw TypeError(
818
- 'Wait condition must be a promise-like object, function, or a '
819
- + 'Condition object');
867
+ 'Wait condition must be a promise-like object, function, or a ' +
868
+ 'Condition object'
869
+ )
820
870
  }
821
871
 
822
- const driver = this;
872
+ const driver = this
823
873
  function evaluateCondition() {
824
874
  return new Promise((resolve, reject) => {
825
875
  try {
826
- resolve(fn(driver));
876
+ resolve(fn(driver))
827
877
  } catch (ex) {
828
- reject(ex);
878
+ reject(ex)
829
879
  }
830
- });
880
+ })
831
881
  }
832
882
 
833
883
  let result = new Promise((resolve, reject) => {
834
- const startTime = Date.now();
884
+ const startTime = Date.now()
835
885
  const pollCondition = async () => {
836
- evaluateCondition().then(function(value) {
837
- const elapsed = Date.now() - startTime;
838
- if (!!value) {
839
- resolve(value);
886
+ evaluateCondition().then(function (value) {
887
+ const elapsed = Date.now() - startTime
888
+ if (value) {
889
+ resolve(value)
840
890
  } else if (timeout && elapsed >= timeout) {
841
- reject(
891
+ try {
892
+ let timeoutMessage = resolveWaitMessage(message)
893
+ reject(
894
+ new error.TimeoutError(
895
+ `${timeoutMessage}Wait timed out after ${elapsed}ms`
896
+ )
897
+ )
898
+ } catch (ex) {
899
+ reject(
842
900
  new error.TimeoutError(
843
- (message ? `${message}\n` : '')
844
- + `Wait timed out after ${elapsed}ms`));
901
+ `${ex.message}\nWait timed out after ${elapsed}ms`
902
+ )
903
+ )
904
+ }
845
905
  } else {
846
- setTimeout(pollCondition, pollTimeout);
906
+ setTimeout(pollCondition, pollTimeout)
847
907
  }
848
- }, reject);
849
- };
850
- pollCondition();
851
- });
908
+ }, reject)
909
+ }
910
+ pollCondition()
911
+ })
852
912
 
853
913
  if (condition instanceof WebElementCondition) {
854
- result = new WebElementPromise(this, result.then(function(value) {
855
- if (!(value instanceof WebElement)) {
856
- throw TypeError(
857
- 'WebElementCondition did not resolve to a WebElement: '
858
- + Object.prototype.toString.call(value));
859
- }
860
- return value;
861
- }));
914
+ result = new WebElementPromise(
915
+ this,
916
+ result.then(function (value) {
917
+ if (!(value instanceof WebElement)) {
918
+ throw TypeError(
919
+ 'WebElementCondition did not resolve to a WebElement: ' +
920
+ Object.prototype.toString.call(value)
921
+ )
922
+ }
923
+ return value
924
+ })
925
+ )
862
926
  }
863
- return result;
927
+ return result
864
928
  }
865
929
 
866
930
  /** @override */
867
931
  sleep(ms) {
868
- return new Promise(resolve => setTimeout(() => resolve(), ms));
932
+ return new Promise((resolve) => setTimeout(resolve, ms))
869
933
  }
870
934
 
871
935
  /** @override */
872
936
  getWindowHandle() {
873
937
  return this.execute(
874
- new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE));
938
+ new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE)
939
+ )
875
940
  }
876
941
 
877
942
  /** @override */
878
943
  getAllWindowHandles() {
879
- return this.execute(
880
- new command.Command(command.Name.GET_WINDOW_HANDLES));
944
+ return this.execute(new command.Command(command.Name.GET_WINDOW_HANDLES))
881
945
  }
882
946
 
883
947
  /** @override */
884
948
  getPageSource() {
885
- return this.execute(
886
- new command.Command(command.Name.GET_PAGE_SOURCE));
949
+ return this.execute(new command.Command(command.Name.GET_PAGE_SOURCE))
887
950
  }
888
951
 
889
952
  /** @override */
890
953
  close() {
891
- return this.execute(new command.Command(command.Name.CLOSE));
954
+ return this.execute(new command.Command(command.Name.CLOSE))
892
955
  }
893
956
 
894
957
  /** @override */
895
958
  get(url) {
896
- return this.navigate().to(url);
959
+ return this.navigate().to(url)
897
960
  }
898
961
 
899
962
  /** @override */
900
963
  getCurrentUrl() {
901
- return this.execute(new command.Command(command.Name.GET_CURRENT_URL));
964
+ return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
902
965
  }
903
966
 
904
967
  /** @override */
905
968
  getTitle() {
906
- return this.execute(new command.Command(command.Name.GET_TITLE));
969
+ return this.execute(new command.Command(command.Name.GET_TITLE))
907
970
  }
908
971
 
909
972
  /** @override */
910
973
  findElement(locator) {
911
- let id;
912
- locator = by.checkedLocator(locator);
974
+ let id
975
+ locator = by.checkedLocator(locator)
913
976
  if (typeof locator === 'function') {
914
- id = this.findElementInternal_(locator, this);
977
+ id = this.findElementInternal_(locator, this)
915
978
  } else {
916
- let cmd = new command.Command(command.Name.FIND_ELEMENT).
917
- setParameter('using', locator.using).
918
- setParameter('value', locator.value);
919
- id = this.execute(cmd);
979
+ let cmd = new command.Command(command.Name.FIND_ELEMENT)
980
+ .setParameter('using', locator.using)
981
+ .setParameter('value', locator.value)
982
+ id = this.execute(cmd)
920
983
  }
921
- return new WebElementPromise(this, id);
984
+ return new WebElementPromise(this, id)
922
985
  }
923
986
 
924
987
  /**
@@ -929,34 +992,42 @@ class WebDriver {
929
992
  * @private
930
993
  */
931
994
  async findElementInternal_(locatorFn, context) {
932
- let result = await locatorFn(context);
995
+ let result = await locatorFn(context)
933
996
  if (Array.isArray(result)) {
934
- result = result[0];
997
+ result = result[0]
935
998
  }
936
999
  if (!(result instanceof WebElement)) {
937
- throw new TypeError('Custom locator did not return a WebElement');
1000
+ throw new TypeError('Custom locator did not return a WebElement')
938
1001
  }
939
- return result;
1002
+ return result
940
1003
  }
941
1004
 
942
1005
  /** @override */
943
1006
  async findElements(locator) {
944
- locator = by.checkedLocator(locator);
945
- if (typeof locator === 'function') {
946
- return this.findElementsInternal_(locator, this);
1007
+ let cmd = null
1008
+ if (locator instanceof RelativeBy) {
1009
+ cmd = new command.Command(
1010
+ command.Name.FIND_ELEMENTS_RELATIVE
1011
+ ).setParameter('args', locator.marshall())
947
1012
  } else {
948
- let cmd = new command.Command(command.Name.FIND_ELEMENTS).
949
- setParameter('using', locator.using).
950
- setParameter('value', locator.value);
951
- try {
952
- let res = await this.execute(cmd);
953
- return Array.isArray(res) ? res : [];
954
- } catch (ex) {
955
- if (ex instanceof error.NoSuchElementError) {
956
- return [];
957
- }
958
- throw ex;
1013
+ locator = by.checkedLocator(locator)
1014
+ }
1015
+
1016
+ if (typeof locator === 'function') {
1017
+ return this.findElementsInternal_(locator, this)
1018
+ } else if (cmd === null) {
1019
+ cmd = new command.Command(command.Name.FIND_ELEMENTS)
1020
+ .setParameter('using', locator.using)
1021
+ .setParameter('value', locator.value)
1022
+ }
1023
+ try {
1024
+ let res = await this.execute(cmd)
1025
+ return Array.isArray(res) ? res : []
1026
+ } catch (ex) {
1027
+ if (ex instanceof error.NoSuchElementError) {
1028
+ return []
959
1029
  }
1030
+ throw ex
960
1031
  }
961
1032
  }
962
1033
 
@@ -968,41 +1039,383 @@ class WebDriver {
968
1039
  * @private
969
1040
  */
970
1041
  async findElementsInternal_(locatorFn, context) {
971
- const result = await locatorFn(context);
1042
+ const result = await locatorFn(context)
972
1043
  if (result instanceof WebElement) {
973
- return [result];
1044
+ return [result]
974
1045
  }
975
1046
 
976
1047
  if (!Array.isArray(result)) {
977
- return [];
1048
+ return []
978
1049
  }
979
1050
 
980
- return result.filter(function(item) {
981
- return item instanceof WebElement;
982
- });
1051
+ return result.filter(function (item) {
1052
+ return item instanceof WebElement
1053
+ })
983
1054
  }
984
1055
 
985
1056
  /** @override */
986
1057
  takeScreenshot() {
987
- return this.execute(new command.Command(command.Name.SCREENSHOT));
1058
+ return this.execute(new command.Command(command.Name.SCREENSHOT))
988
1059
  }
989
1060
 
990
1061
  /** @override */
991
1062
  manage() {
992
- return new Options(this);
1063
+ return new Options(this)
993
1064
  }
994
1065
 
995
1066
  /** @override */
996
1067
  navigate() {
997
- return new Navigation(this);
1068
+ return new Navigation(this)
998
1069
  }
999
1070
 
1000
1071
  /** @override */
1001
1072
  switchTo() {
1002
- return new TargetLocator(this);
1073
+ return new TargetLocator(this)
1074
+ }
1075
+
1076
+ validatePrintPageParams(keys, object) {
1077
+ let page = {}
1078
+ let margin = {}
1079
+ let data
1080
+ Object.keys(keys).forEach(function (key) {
1081
+ data = keys[key]
1082
+ let obj = {
1083
+ orientation: function () {
1084
+ object.orientation = data
1085
+ },
1086
+
1087
+ scale: function () {
1088
+ object.scale = data
1089
+ },
1090
+
1091
+ background: function () {
1092
+ object.background = data
1093
+ },
1094
+
1095
+ width: function () {
1096
+ page.width = data
1097
+ object.page = page
1098
+ },
1099
+
1100
+ height: function () {
1101
+ page.height = data
1102
+ object.page = page
1103
+ },
1104
+
1105
+ top: function () {
1106
+ margin.top = data
1107
+ object.margin = margin
1108
+ },
1109
+
1110
+ left: function () {
1111
+ margin.left = data
1112
+ object.margin = margin
1113
+ },
1114
+
1115
+ bottom: function () {
1116
+ margin.bottom = data
1117
+ object.margin = margin
1118
+ },
1119
+
1120
+ right: function () {
1121
+ margin.right = data
1122
+ object.margin = margin
1123
+ },
1124
+
1125
+ shrinkToFit: function () {
1126
+ object.shrinkToFit = data
1127
+ },
1128
+
1129
+ pageRanges: function () {
1130
+ object.pageRanges = data
1131
+ },
1132
+ }
1133
+
1134
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
1135
+ throw new error.InvalidArgumentError(`Invalid Argument '${key}'`)
1136
+ } else {
1137
+ obj[key]()
1138
+ }
1139
+ })
1140
+
1141
+ return object
1003
1142
  }
1004
- }
1005
1143
 
1144
+ /** @override */
1145
+ printPage(options = {}) {
1146
+ let keys = options
1147
+ let params = {}
1148
+ let resultObj
1149
+
1150
+ let self = this
1151
+ resultObj = self.validatePrintPageParams(keys, params)
1152
+
1153
+ return this.execute(
1154
+ new command.Command(command.Name.PRINT_PAGE).setParameters(resultObj)
1155
+ )
1156
+ }
1157
+
1158
+ /**
1159
+ * Creates a new WebSocket connection.
1160
+ * @return {!Promise<resolved>} A new CDP instance.
1161
+ */
1162
+ async createCDPConnection(target) {
1163
+ const caps = await this.getCapabilities()
1164
+ const seCdp = caps['map_'].get('se:cdp')
1165
+ const vendorInfo =
1166
+ caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
1167
+ caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
1168
+ caps['map_'].get('moz:debuggerAddress') ||
1169
+ new Map();
1170
+ const debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
1171
+ this._wsUrl = await this.getWsUrl(debuggerUrl, target)
1172
+
1173
+ return new Promise((resolve, reject) => {
1174
+ try {
1175
+ this._wsConnection = new WebSocket(this._wsUrl)
1176
+ } catch (err) {
1177
+ reject(err)
1178
+ return
1179
+ }
1180
+
1181
+ this._wsConnection.on('open', () => {
1182
+ this._cdpConnection = new cdp.CdpConnection(this._wsConnection)
1183
+ resolve(this._cdpConnection)
1184
+ })
1185
+
1186
+ this._wsConnection.on('error', (error) => {
1187
+ reject(error)
1188
+ })
1189
+ })
1190
+ }
1191
+
1192
+ /**
1193
+ * Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
1194
+ * @param {string} debuggerAddress
1195
+ * @param {string} target
1196
+ * @return {string} Returns parsed webSocketDebuggerUrl obtained from the http request
1197
+ */
1198
+ async getWsUrl(debuggerAddress, target) {
1199
+ if (target && cdpTargets.indexOf(target.toLowerCase()) === -1) {
1200
+ throw new error.InvalidArgumentError('invalid target value')
1201
+ }
1202
+ let path
1203
+ if (target === 'page') {
1204
+ path = '/json'
1205
+ } else {
1206
+ path = '/json/version'
1207
+ }
1208
+ let request = new http.Request('GET', path)
1209
+ let client = new http.HttpClient('http://' + debuggerAddress)
1210
+ let response = await client.send(request)
1211
+ let url
1212
+ if (target.toLowerCase() === 'page') {
1213
+ url = JSON.parse(response.body)[0]['webSocketDebuggerUrl']
1214
+ } else {
1215
+ url = JSON.parse(response.body)['webSocketDebuggerUrl']
1216
+ }
1217
+
1218
+ return url
1219
+ }
1220
+
1221
+ /**
1222
+ * Sets a listener for Fetch.authRequired event from CDP
1223
+ * If event is triggered, it enter username and password
1224
+ * and allows the test to move forward
1225
+ * @param {string} username
1226
+ * @param {string} password
1227
+ * @param connection CDP Connection
1228
+ */
1229
+ async register(username, password, connection) {
1230
+ await connection.execute(
1231
+ 'Network.setCacheDisabled',
1232
+ this.getRandomNumber(1, 10),
1233
+ {
1234
+ cacheDisabled: true,
1235
+ },
1236
+ null
1237
+ )
1238
+
1239
+ this._wsConnection.on('message', (message) => {
1240
+ const params = JSON.parse(message)
1241
+
1242
+ if (params.method === 'Fetch.authRequired') {
1243
+ const requestParams = params['params']
1244
+ connection.execute(
1245
+ 'Fetch.continueWithAuth',
1246
+ this.getRandomNumber(1, 10),
1247
+ {
1248
+ requestId: requestParams['requestId'],
1249
+ authChallengeResponse: {
1250
+ response: 'ProvideCredentials',
1251
+ username: username,
1252
+ password: password,
1253
+ },
1254
+ }
1255
+ )
1256
+ } else if (params.method === 'Fetch.requestPaused') {
1257
+ const requestPausedParams = params['params']
1258
+ connection.execute(
1259
+ 'Fetch.continueRequest',
1260
+ this.getRandomNumber(1, 10),
1261
+ {
1262
+ requestId: requestPausedParams['requestId'],
1263
+ }
1264
+ )
1265
+ }
1266
+ })
1267
+
1268
+ await connection.execute(
1269
+ 'Fetch.enable',
1270
+ 1,
1271
+ {
1272
+ handleAuthRequests: true,
1273
+ },
1274
+ null
1275
+ )
1276
+ }
1277
+
1278
+ /**
1279
+ *
1280
+ * @param connection
1281
+ * @param callback
1282
+ * @returns {Promise<void>}
1283
+ */
1284
+ async onLogEvent(connection, callback) {
1285
+ await connection.execute(
1286
+ 'Runtime.enable',
1287
+ this.getRandomNumber(1, 10),
1288
+ {},
1289
+ null
1290
+ )
1291
+
1292
+ this._wsConnection.on('message', (message) => {
1293
+ const params = JSON.parse(message)
1294
+
1295
+ if (params.method === 'Runtime.consoleAPICalled') {
1296
+ const consoleEventParams = params['params']
1297
+ let event = {
1298
+ type: consoleEventParams['type'],
1299
+ timestamp: new Date(consoleEventParams['timestamp']),
1300
+ args: consoleEventParams['args'],
1301
+ }
1302
+
1303
+ callback(event)
1304
+ }
1305
+ })
1306
+ }
1307
+
1308
+ /**
1309
+ *
1310
+ * @param connection
1311
+ * @param callback
1312
+ * @returns {Promise<void>}
1313
+ */
1314
+ async onLogException(connection, callback) {
1315
+ await connection.execute(
1316
+ 'Runtime.enable',
1317
+ this.getRandomNumber(1, 10),
1318
+ {},
1319
+ null
1320
+ )
1321
+
1322
+ this._wsConnection.on('message', (message) => {
1323
+ const params = JSON.parse(message)
1324
+
1325
+ if (params.method === 'Runtime.exceptionThrown') {
1326
+ const exceptionEventParams = params['params']
1327
+ let event = {
1328
+ exceptionDetails: exceptionEventParams['exceptionDetails'],
1329
+ timestamp: new Date(exceptionEventParams['timestamp']),
1330
+ }
1331
+
1332
+ callback(event)
1333
+ }
1334
+ })
1335
+ }
1336
+
1337
+ /**
1338
+ * @param connection
1339
+ * @param callback
1340
+ * @returns {Promise<void>}
1341
+ */
1342
+ async logMutationEvents(connection, callback) {
1343
+ await connection.execute(
1344
+ 'Runtime.enable',
1345
+ this.getRandomNumber(1, 10),
1346
+ {},
1347
+ null
1348
+ )
1349
+ await connection.execute(
1350
+ 'Page.enable',
1351
+ this.getRandomNumber(1, 10),
1352
+ {},
1353
+ null
1354
+ )
1355
+
1356
+ await connection.execute(
1357
+ 'Runtime.addBinding',
1358
+ this.getRandomNumber(1, 10),
1359
+ {
1360
+ name: '__webdriver_attribute',
1361
+ },
1362
+ null
1363
+ )
1364
+
1365
+ let mutationListener = ''
1366
+ try {
1367
+ // Depending on what is running the code it could appear in 2 different places which is why we try
1368
+ // here and then the other location
1369
+ mutationListener = fs
1370
+ .readFileSync(
1371
+ './javascript/node/selenium-webdriver/lib/atoms/mutation-listener.js',
1372
+ 'utf-8'
1373
+ )
1374
+ .toString()
1375
+ } catch {
1376
+ mutationListener = fs
1377
+ .readFileSync(path.resolve(__dirname, './atoms/mutation-listener.js'), 'utf-8')
1378
+ .toString()
1379
+ }
1380
+
1381
+ this.executeScript(mutationListener)
1382
+
1383
+ await connection.execute(
1384
+ 'Page.addScriptToEvaluateOnNewDocument',
1385
+ this.getRandomNumber(1, 10),
1386
+ {
1387
+ source: mutationListener,
1388
+ },
1389
+ null
1390
+ )
1391
+
1392
+ this._wsConnection.on('message', async (message) => {
1393
+ const params = JSON.parse(message)
1394
+ if (params.method === 'Runtime.bindingCalled') {
1395
+ let payload = JSON.parse(params['params']['payload'])
1396
+ let elements = await this.findElements({
1397
+ css: '*[data-__webdriver_id=' + payload['target'],
1398
+ })
1399
+
1400
+ if (elements.length === 0) {
1401
+ return
1402
+ }
1403
+
1404
+ let event = {
1405
+ element: elements[0],
1406
+ attribute_name: payload['name'],
1407
+ current_value: payload['value'],
1408
+ old_value: payload['oldValue'],
1409
+ }
1410
+ callback(event)
1411
+ }
1412
+ })
1413
+ }
1414
+
1415
+ getRandomNumber(min, max) {
1416
+ return Math.floor(Math.random() * (max - min + 1) + min)
1417
+ }
1418
+ }
1006
1419
 
1007
1420
  /**
1008
1421
  * Interface for navigating back and forth in the browser history.
@@ -1021,7 +1434,7 @@ class Navigation {
1021
1434
  */
1022
1435
  constructor(driver) {
1023
1436
  /** @private {!WebDriver} */
1024
- this.driver_ = driver;
1437
+ this.driver_ = driver
1025
1438
  }
1026
1439
 
1027
1440
  /**
@@ -1033,8 +1446,8 @@ class Navigation {
1033
1446
  */
1034
1447
  to(url) {
1035
1448
  return this.driver_.execute(
1036
- new command.Command(command.Name.GET).
1037
- setParameter('url', url));
1449
+ new command.Command(command.Name.GET).setParameter('url', url)
1450
+ )
1038
1451
  }
1039
1452
 
1040
1453
  /**
@@ -1044,7 +1457,7 @@ class Navigation {
1044
1457
  * navigation event has completed.
1045
1458
  */
1046
1459
  back() {
1047
- return this.driver_.execute(new command.Command(command.Name.GO_BACK));
1460
+ return this.driver_.execute(new command.Command(command.Name.GO_BACK))
1048
1461
  }
1049
1462
 
1050
1463
  /**
@@ -1054,7 +1467,7 @@ class Navigation {
1054
1467
  * navigation event has completed.
1055
1468
  */
1056
1469
  forward() {
1057
- return this.driver_.execute(new command.Command(command.Name.GO_FORWARD));
1470
+ return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
1058
1471
  }
1059
1472
 
1060
1473
  /**
@@ -1064,11 +1477,10 @@ class Navigation {
1064
1477
  * navigation event has completed.
1065
1478
  */
1066
1479
  refresh() {
1067
- return this.driver_.execute(new command.Command(command.Name.REFRESH));
1480
+ return this.driver_.execute(new command.Command(command.Name.REFRESH))
1068
1481
  }
1069
1482
  }
1070
1483
 
1071
-
1072
1484
  /**
1073
1485
  * Provides methods for managing browser and driver state.
1074
1486
  *
@@ -1082,7 +1494,7 @@ class Options {
1082
1494
  */
1083
1495
  constructor(driver) {
1084
1496
  /** @private {!WebDriver} */
1085
- this.driver_ = driver;
1497
+ this.driver_ = driver
1086
1498
  }
1087
1499
 
1088
1500
  /**
@@ -1111,43 +1523,50 @@ class Options {
1111
1523
  * invalid.
1112
1524
  * @throws {TypeError} if `spec` is not a cookie object.
1113
1525
  */
1114
- addCookie({name, value, path, domain, secure, httpOnly, expiry, sameSite}) {
1526
+ addCookie({ name, value, path, domain, secure, httpOnly, expiry, sameSite }) {
1115
1527
  // We do not allow '=' or ';' in the name.
1116
1528
  if (/[;=]/.test(name)) {
1117
- throw new error.InvalidArgumentError(
1118
- 'Invalid cookie name "' + name + '"');
1529
+ throw new error.InvalidArgumentError('Invalid cookie name "' + name + '"')
1119
1530
  }
1120
1531
 
1121
1532
  // We do not allow ';' in value.
1122
1533
  if (/;/.test(value)) {
1123
1534
  throw new error.InvalidArgumentError(
1124
- 'Invalid cookie value "' + value + '"');
1535
+ 'Invalid cookie value "' + value + '"'
1536
+ )
1125
1537
  }
1126
1538
 
1127
1539
  if (typeof expiry === 'number') {
1128
- expiry = Math.floor(expiry);
1540
+ expiry = Math.floor(expiry)
1129
1541
  } else if (expiry instanceof Date) {
1130
- let date = /** @type {!Date} */(expiry);
1131
- expiry = Math.floor(date.getTime() / 1000);
1542
+ let date = /** @type {!Date} */ (expiry)
1543
+ expiry = Math.floor(date.getTime() / 1000)
1544
+ }
1545
+
1546
+ if (sameSite && !['Strict', 'Lax', 'None'].includes(sameSite)) {
1547
+ throw new error.InvalidArgumentError(
1548
+ `Invalid sameSite cookie value '${sameSite}'. It should be one of "Lax", "Strict" or "None"`
1549
+ )
1132
1550
  }
1133
1551
 
1134
- if(sameSite && sameSite !== 'Strict' && sameSite !== 'Lax') {
1552
+ if (sameSite === 'None' && !secure) {
1135
1553
  throw new error.InvalidArgumentError(
1136
- `Invalid sameSite cookie value '${sameSite}'. It should be either "Lax" (or) "Strict" `);
1554
+ 'Invalid cookie configuration: SameSite=None must be Secure'
1555
+ )
1137
1556
  }
1138
1557
 
1139
1558
  return this.driver_.execute(
1140
- new command.Command(command.Name.ADD_COOKIE).
1141
- setParameter('cookie', {
1142
- 'name': name,
1143
- 'value': value,
1144
- 'path': path,
1145
- 'domain': domain,
1146
- 'secure': !!secure,
1147
- 'httpOnly': !!httpOnly,
1148
- 'expiry': expiry,
1149
- 'sameSite': sameSite
1150
- }));
1559
+ new command.Command(command.Name.ADD_COOKIE).setParameter('cookie', {
1560
+ name: name,
1561
+ value: value,
1562
+ path: path,
1563
+ domain: domain,
1564
+ secure: !!secure,
1565
+ httpOnly: !!httpOnly,
1566
+ expiry: expiry,
1567
+ sameSite: sameSite,
1568
+ })
1569
+ )
1151
1570
  }
1152
1571
 
1153
1572
  /**
@@ -1158,7 +1577,8 @@ class Options {
1158
1577
  */
1159
1578
  deleteAllCookies() {
1160
1579
  return this.driver_.execute(
1161
- new command.Command(command.Name.DELETE_ALL_COOKIES));
1580
+ new command.Command(command.Name.DELETE_ALL_COOKIES)
1581
+ )
1162
1582
  }
1163
1583
 
1164
1584
  /**
@@ -1171,8 +1591,8 @@ class Options {
1171
1591
  */
1172
1592
  deleteCookie(name) {
1173
1593
  return this.driver_.execute(
1174
- new command.Command(command.Name.DELETE_COOKIE).
1175
- setParameter('name', name));
1594
+ new command.Command(command.Name.DELETE_COOKIE).setParameter('name', name)
1595
+ )
1176
1596
  }
1177
1597
 
1178
1598
  /**
@@ -1184,7 +1604,8 @@ class Options {
1184
1604
  */
1185
1605
  getCookies() {
1186
1606
  return this.driver_.execute(
1187
- new command.Command(command.Name.GET_ALL_COOKIES));
1607
+ new command.Command(command.Name.GET_ALL_COOKIES)
1608
+ )
1188
1609
  }
1189
1610
 
1190
1611
  /**
@@ -1199,24 +1620,25 @@ class Options {
1199
1620
  */
1200
1621
  async getCookie(name) {
1201
1622
  try {
1202
- const cookie =
1203
- await this.driver_.execute(
1204
- new command.Command(command.Name.GET_COOKIE)
1205
- .setParameter('name', name));
1206
- return cookie;
1623
+ const cookie = await this.driver_.execute(
1624
+ new command.Command(command.Name.GET_COOKIE).setParameter('name', name)
1625
+ )
1626
+ return cookie
1207
1627
  } catch (err) {
1208
- if (!(err instanceof error.UnknownCommandError)
1209
- && !(err instanceof error.UnsupportedOperationError)) {
1210
- throw err;
1628
+ if (
1629
+ !(err instanceof error.UnknownCommandError) &&
1630
+ !(err instanceof error.UnsupportedOperationError)
1631
+ ) {
1632
+ throw err
1211
1633
  }
1212
1634
 
1213
- const cookies = await this.getCookies();
1635
+ const cookies = await this.getCookies()
1214
1636
  for (let cookie of cookies) {
1215
1637
  if (cookie && cookie['name'] === name) {
1216
- return cookie;
1638
+ return cookie
1217
1639
  }
1218
1640
  }
1219
- return null;
1641
+ return null
1220
1642
  }
1221
1643
  }
1222
1644
 
@@ -1231,7 +1653,7 @@ class Options {
1231
1653
  * @see #setTimeouts()
1232
1654
  */
1233
1655
  getTimeouts() {
1234
- return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT));
1656
+ return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
1235
1657
  }
1236
1658
 
1237
1659
  /**
@@ -1263,60 +1685,59 @@ class Options {
1263
1685
  * @see #getTimeouts()
1264
1686
  * @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
1265
1687
  */
1266
- setTimeouts({script, pageLoad, implicit} = {}) {
1267
- let cmd = new command.Command(command.Name.SET_TIMEOUT);
1688
+ setTimeouts({ script, pageLoad, implicit } = {}) {
1689
+ let cmd = new command.Command(command.Name.SET_TIMEOUT)
1268
1690
 
1269
- let valid = false;
1691
+ let valid = false
1270
1692
  function setParam(key, value) {
1271
1693
  if (value === null || typeof value === 'number') {
1272
- valid = true;
1273
- cmd.setParameter(key, value);
1694
+ valid = true
1695
+ cmd.setParameter(key, value)
1274
1696
  } else if (typeof value !== 'undefined') {
1275
1697
  throw TypeError(
1276
- 'invalid timeouts configuration:'
1277
- + ` expected "${key}" to be a number, got ${typeof value}`);
1698
+ 'invalid timeouts configuration:' +
1699
+ ` expected "${key}" to be a number, got ${typeof value}`
1700
+ )
1278
1701
  }
1279
1702
  }
1280
- setParam('implicit', implicit);
1281
- setParam('pageLoad', pageLoad);
1282
- setParam('script', script);
1703
+ setParam('implicit', implicit)
1704
+ setParam('pageLoad', pageLoad)
1705
+ setParam('script', script)
1283
1706
 
1284
1707
  if (valid) {
1285
- return this.driver_.execute(cmd)
1286
- .catch(() => {
1287
- // Fallback to the legacy method.
1288
- let cmds = [];
1289
- if (typeof script === 'number') {
1290
- cmds.push(legacyTimeout(this.driver_, 'script', script));
1291
- }
1292
- if (typeof implicit === 'number') {
1293
- cmds.push(legacyTimeout(this.driver_, 'implicit', implicit));
1294
- }
1295
- if (typeof pageLoad === 'number') {
1296
- cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad));
1297
- }
1298
- return Promise.all(cmds);
1299
- });
1708
+ return this.driver_.execute(cmd).catch(() => {
1709
+ // Fallback to the legacy method.
1710
+ let cmds = []
1711
+ if (typeof script === 'number') {
1712
+ cmds.push(legacyTimeout(this.driver_, 'script', script))
1713
+ }
1714
+ if (typeof implicit === 'number') {
1715
+ cmds.push(legacyTimeout(this.driver_, 'implicit', implicit))
1716
+ }
1717
+ if (typeof pageLoad === 'number') {
1718
+ cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad))
1719
+ }
1720
+ return Promise.all(cmds)
1721
+ })
1300
1722
  }
1301
- throw TypeError('no timeouts specified');
1723
+ throw TypeError('no timeouts specified')
1302
1724
  }
1303
1725
 
1304
1726
  /**
1305
1727
  * @return {!Logs} The interface for managing driver logs.
1306
1728
  */
1307
1729
  logs() {
1308
- return new Logs(this.driver_);
1730
+ return new Logs(this.driver_)
1309
1731
  }
1310
1732
 
1311
1733
  /**
1312
1734
  * @return {!Window} The interface for managing the current window.
1313
1735
  */
1314
1736
  window() {
1315
- return new Window(this.driver_);
1737
+ return new Window(this.driver_)
1316
1738
  }
1317
1739
  }
1318
1740
 
1319
-
1320
1741
  /**
1321
1742
  * @param {!WebDriver} driver
1322
1743
  * @param {string} type
@@ -1325,44 +1746,39 @@ class Options {
1325
1746
  */
1326
1747
  function legacyTimeout(driver, type, ms) {
1327
1748
  return driver.execute(
1328
- new command.Command(command.Name.SET_TIMEOUT)
1329
- .setParameter('type', type)
1330
- .setParameter('ms', ms));
1749
+ new command.Command(command.Name.SET_TIMEOUT)
1750
+ .setParameter('type', type)
1751
+ .setParameter('ms', ms)
1752
+ )
1331
1753
  }
1332
1754
 
1333
-
1334
-
1335
1755
  /**
1336
1756
  * A record object describing a browser cookie.
1337
1757
  *
1338
1758
  * @record
1339
1759
  */
1340
- Options.Cookie = function() {};
1341
-
1760
+ Options.Cookie = function () { }
1342
1761
 
1343
1762
  /**
1344
1763
  * The name of the cookie.
1345
1764
  *
1346
1765
  * @type {string}
1347
1766
  */
1348
- Options.Cookie.prototype.name;
1349
-
1767
+ Options.Cookie.prototype.name
1350
1768
 
1351
1769
  /**
1352
1770
  * The cookie value.
1353
1771
  *
1354
1772
  * @type {string}
1355
1773
  */
1356
- Options.Cookie.prototype.value;
1357
-
1774
+ Options.Cookie.prototype.value
1358
1775
 
1359
1776
  /**
1360
1777
  * The cookie path. Defaults to "/" when adding a cookie.
1361
1778
  *
1362
1779
  * @type {(string|undefined)}
1363
1780
  */
1364
- Options.Cookie.prototype.path;
1365
-
1781
+ Options.Cookie.prototype.path
1366
1782
 
1367
1783
  /**
1368
1784
  * The domain the cookie is visible to. Defaults to the current browsing
@@ -1370,8 +1786,7 @@ Options.Cookie.prototype.path;
1370
1786
  *
1371
1787
  * @type {(string|undefined)}
1372
1788
  */
1373
- Options.Cookie.prototype.domain;
1374
-
1789
+ Options.Cookie.prototype.domain
1375
1790
 
1376
1791
  /**
1377
1792
  * Whether the cookie is a secure cookie. Defaults to false when adding a new
@@ -1379,8 +1794,7 @@ Options.Cookie.prototype.domain;
1379
1794
  *
1380
1795
  * @type {(boolean|undefined)}
1381
1796
  */
1382
- Options.Cookie.prototype.secure;
1383
-
1797
+ Options.Cookie.prototype.secure
1384
1798
 
1385
1799
  /**
1386
1800
  * Whether the cookie is an HTTP only cookie. Defaults to false when adding a
@@ -1388,8 +1802,7 @@ Options.Cookie.prototype.secure;
1388
1802
  *
1389
1803
  * @type {(boolean|undefined)}
1390
1804
  */
1391
- Options.Cookie.prototype.httpOnly;
1392
-
1805
+ Options.Cookie.prototype.httpOnly
1393
1806
 
1394
1807
  /**
1395
1808
  * When the cookie expires.
@@ -1402,19 +1815,18 @@ Options.Cookie.prototype.httpOnly;
1402
1815
  *
1403
1816
  * @type {(!Date|number|undefined)}
1404
1817
  */
1405
- Options.Cookie.prototype.expiry;
1406
-
1818
+ Options.Cookie.prototype.expiry
1407
1819
 
1408
1820
  /**
1409
1821
  * When the cookie applies to a SameSite policy.
1410
1822
  *
1411
1823
  * When {@linkplain Options#addCookie() adding a cookie}, this may be specified
1412
- * as a {@link string} object which is either 'Lax' or 'Strict'.
1824
+ * as a {@link string} object which is one of 'Lax', 'Strict' or 'None'.
1413
1825
  *
1414
1826
  *
1415
- * @type {(!Date|number|undefined)}
1827
+ * @type {(string|undefined)}
1416
1828
  */
1417
- Options.Cookie.prototype.sameSite;
1829
+ Options.Cookie.prototype.sameSite
1418
1830
 
1419
1831
  /**
1420
1832
  * An interface for managing the current window.
@@ -1434,7 +1846,7 @@ class Window {
1434
1846
  */
1435
1847
  constructor(driver) {
1436
1848
  /** @private {!WebDriver} */
1437
- this.driver_ = driver;
1849
+ this.driver_ = driver
1438
1850
  }
1439
1851
 
1440
1852
  /**
@@ -1447,20 +1859,25 @@ class Window {
1447
1859
  async getRect() {
1448
1860
  try {
1449
1861
  return await this.driver_.execute(
1450
- new command.Command(command.Name.GET_WINDOW_RECT));
1862
+ new command.Command(command.Name.GET_WINDOW_RECT)
1863
+ )
1451
1864
  } catch (ex) {
1452
1865
  if (ex instanceof error.UnknownCommandError) {
1453
- let {width, height} =
1454
- await this.driver_.execute(
1455
- new command.Command(command.Name.GET_WINDOW_SIZE)
1456
- .setParameter('windowHandle', 'current'));
1457
- let {x, y} =
1458
- await this.driver_.execute(
1459
- new command.Command(command.Name.GET_WINDOW_POSITION)
1460
- .setParameter('windowHandle', 'current'));
1461
- return {x, y, width, height};
1866
+ let { width, height } = await this.driver_.execute(
1867
+ new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
1868
+ 'windowHandle',
1869
+ 'current'
1870
+ )
1871
+ )
1872
+ let { x, y } = await this.driver_.execute(
1873
+ new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
1874
+ 'windowHandle',
1875
+ 'current'
1876
+ )
1877
+ )
1878
+ return { x, y, width, height }
1462
1879
  }
1463
- throw ex;
1880
+ throw ex
1464
1881
  }
1465
1882
  }
1466
1883
 
@@ -1475,34 +1892,41 @@ class Window {
1475
1892
  * height: (number|undefined)}} options
1476
1893
  * The desired window size and position.
1477
1894
  * @return {!Promise<{x: number, y: number, width: number, height: number}>}
1478
- * A promise that will resolve to the current widnow's updated window
1895
+ * A promise that will resolve to the current window's updated window
1479
1896
  * rect.
1480
1897
  */
1481
- async setRect({x, y, width, height}) {
1898
+ async setRect({ x, y, width, height }) {
1482
1899
  try {
1483
1900
  return await this.driver_.execute(
1484
- new command.Command(command.Name.SET_WINDOW_RECT)
1485
- .setParameters({x, y, width, height}));
1901
+ new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
1902
+ x,
1903
+ y,
1904
+ width,
1905
+ height,
1906
+ })
1907
+ )
1486
1908
  } catch (ex) {
1487
1909
  if (ex instanceof error.UnknownCommandError) {
1488
1910
  if (typeof x === 'number' && typeof y === 'number') {
1489
1911
  await this.driver_.execute(
1490
- new command.Command(command.Name.SET_WINDOW_POSITION)
1491
- .setParameter('windowHandle', 'current')
1492
- .setParameter('x', x)
1493
- .setParameter('y', y));
1912
+ new command.Command(command.Name.SET_WINDOW_POSITION)
1913
+ .setParameter('windowHandle', 'current')
1914
+ .setParameter('x', x)
1915
+ .setParameter('y', y)
1916
+ )
1494
1917
  }
1495
1918
 
1496
- if (typeof width === 'number' && typeof height === 'number') {
1919
+ if (typeof width === 'number' && typeof height === 'number') {
1497
1920
  await this.driver_.execute(
1498
- new command.Command(command.Name.SET_WINDOW_SIZE)
1499
- .setParameter('windowHandle', 'current')
1500
- .setParameter('width', width)
1501
- .setParameter('height', height));
1921
+ new command.Command(command.Name.SET_WINDOW_SIZE)
1922
+ .setParameter('windowHandle', 'current')
1923
+ .setParameter('width', width)
1924
+ .setParameter('height', height)
1925
+ )
1502
1926
  }
1503
- return this.getRect();
1927
+ return this.getRect()
1504
1928
  }
1505
- throw ex;
1929
+ throw ex
1506
1930
  }
1507
1931
  }
1508
1932
 
@@ -1516,13 +1940,16 @@ class Window {
1516
1940
  */
1517
1941
  maximize() {
1518
1942
  return this.driver_.execute(
1519
- new command.Command(command.Name.MAXIMIZE_WINDOW).
1520
- setParameter('windowHandle', 'current'));
1943
+ new command.Command(command.Name.MAXIMIZE_WINDOW).setParameter(
1944
+ 'windowHandle',
1945
+ 'current'
1946
+ )
1947
+ )
1521
1948
  }
1522
1949
 
1523
1950
  /**
1524
1951
  * Minimizes the current window. The exact behavior of this command is
1525
- * specific to individual window managers, but typicallly involves hiding
1952
+ * specific to individual window managers, but typically involves hiding
1526
1953
  * the window in the system tray.
1527
1954
  *
1528
1955
  * @return {!Promise<void>} A promise that will be resolved when the command
@@ -1530,7 +1957,8 @@ class Window {
1530
1957
  */
1531
1958
  minimize() {
1532
1959
  return this.driver_.execute(
1533
- new command.Command(command.Name.MINIMIZE_WINDOW));
1960
+ new command.Command(command.Name.MINIMIZE_WINDOW)
1961
+ )
1534
1962
  }
1535
1963
 
1536
1964
  /**
@@ -1545,11 +1973,11 @@ class Window {
1545
1973
  */
1546
1974
  fullscreen() {
1547
1975
  return this.driver_.execute(
1548
- new command.Command(command.Name.FULLSCREEN_WINDOW));
1976
+ new command.Command(command.Name.FULLSCREEN_WINDOW)
1977
+ )
1549
1978
  }
1550
1979
  }
1551
1980
 
1552
-
1553
1981
  /**
1554
1982
  * Interface for managing WebDriver log records.
1555
1983
  *
@@ -1568,7 +1996,7 @@ class Logs {
1568
1996
  */
1569
1997
  constructor(driver) {
1570
1998
  /** @private {!WebDriver} */
1571
- this.driver_ = driver;
1999
+ this.driver_ = driver
1572
2000
  }
1573
2001
 
1574
2002
  /**
@@ -1585,19 +2013,23 @@ class Logs {
1585
2013
  * type.
1586
2014
  */
1587
2015
  get(type) {
1588
- let cmd = new command.Command(command.Name.GET_LOG).
1589
- setParameter('type', type);
1590
- return this.driver_.execute(cmd).
1591
- then(function(entries) {
1592
- return entries.map(function(entry) {
1593
- if (!(entry instanceof logging.Entry)) {
1594
- return new logging.Entry(
1595
- entry['level'], entry['message'], entry['timestamp'],
1596
- entry['type']);
1597
- }
1598
- return entry;
1599
- });
1600
- });
2016
+ let cmd = new command.Command(command.Name.GET_LOG).setParameter(
2017
+ 'type',
2018
+ type
2019
+ )
2020
+ return this.driver_.execute(cmd).then(function (entries) {
2021
+ return entries.map(function (entry) {
2022
+ if (!(entry instanceof logging.Entry)) {
2023
+ return new logging.Entry(
2024
+ entry['level'],
2025
+ entry['message'],
2026
+ entry['timestamp'],
2027
+ entry['type']
2028
+ )
2029
+ }
2030
+ return entry
2031
+ })
2032
+ })
1601
2033
  }
1602
2034
 
1603
2035
  /**
@@ -1607,11 +2039,11 @@ class Logs {
1607
2039
  */
1608
2040
  getAvailableLogTypes() {
1609
2041
  return this.driver_.execute(
1610
- new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES));
2042
+ new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES)
2043
+ )
1611
2044
  }
1612
2045
  }
1613
2046
 
1614
-
1615
2047
  /**
1616
2048
  * An interface for changing the focus of the driver to another frame or window.
1617
2049
  *
@@ -1629,7 +2061,7 @@ class TargetLocator {
1629
2061
  */
1630
2062
  constructor(driver) {
1631
2063
  /** @private {!WebDriver} */
1632
- this.driver_ = driver;
2064
+ this.driver_ = driver
1633
2065
  }
1634
2066
 
1635
2067
  /**
@@ -1641,8 +2073,9 @@ class TargetLocator {
1641
2073
  */
1642
2074
  activeElement() {
1643
2075
  var id = this.driver_.execute(
1644
- new command.Command(command.Name.GET_ACTIVE_ELEMENT));
1645
- return new WebElementPromise(this.driver_, id);
2076
+ new command.Command(command.Name.GET_ACTIVE_ELEMENT)
2077
+ )
2078
+ return new WebElementPromise(this.driver_, id)
1646
2079
  }
1647
2080
 
1648
2081
  /**
@@ -1654,8 +2087,8 @@ class TargetLocator {
1654
2087
  */
1655
2088
  defaultContent() {
1656
2089
  return this.driver_.execute(
1657
- new command.Command(command.Name.SWITCH_TO_FRAME).
1658
- setParameter('id', null));
2090
+ new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', null)
2091
+ )
1659
2092
  }
1660
2093
 
1661
2094
  /**
@@ -1678,8 +2111,8 @@ class TargetLocator {
1678
2111
  */
1679
2112
  frame(id) {
1680
2113
  return this.driver_.execute(
1681
- new command.Command(command.Name.SWITCH_TO_FRAME).
1682
- setParameter('id', id));
2114
+ new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', id)
2115
+ )
1683
2116
  }
1684
2117
 
1685
2118
  /**
@@ -1692,7 +2125,8 @@ class TargetLocator {
1692
2125
  */
1693
2126
  parentFrame() {
1694
2127
  return this.driver_.execute(
1695
- new command.Command(command.Name.SWITCH_TO_FRAME_PARENT));
2128
+ new command.Command(command.Name.SWITCH_TO_FRAME_PARENT)
2129
+ )
1696
2130
  }
1697
2131
 
1698
2132
  /**
@@ -1710,11 +2144,12 @@ class TargetLocator {
1710
2144
  */
1711
2145
  window(nameOrHandle) {
1712
2146
  return this.driver_.execute(
1713
- new command.Command(command.Name.SWITCH_TO_WINDOW).
1714
- // "name" supports the legacy drivers. "handle" is the W3C
1715
- // compliant parameter.
1716
- setParameter('name', nameOrHandle).
1717
- setParameter('handle', nameOrHandle));
2147
+ new command.Command(command.Name.SWITCH_TO_WINDOW)
2148
+ // "name" supports the legacy drivers. "handle" is the W3C
2149
+ // compliant parameter.
2150
+ .setParameter('name', nameOrHandle)
2151
+ .setParameter('handle', nameOrHandle)
2152
+ )
1718
2153
  }
1719
2154
 
1720
2155
  /**
@@ -1730,12 +2165,16 @@ class TargetLocator {
1730
2165
  */
1731
2166
  newWindow(typeHint) {
1732
2167
  var driver = this.driver_
1733
- return this.driver_.execute(
1734
- new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).
1735
- setParameter('type', typeHint)
1736
- ).then(function(response) {
1737
- return driver.switchTo().window(response.handle);
1738
- });
2168
+ return this.driver_
2169
+ .execute(
2170
+ new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).setParameter(
2171
+ 'type',
2172
+ typeHint
2173
+ )
2174
+ )
2175
+ .then(function (response) {
2176
+ return driver.switchTo().window(response.handle)
2177
+ })
1739
2178
  }
1740
2179
 
1741
2180
  /**
@@ -1748,25 +2187,26 @@ class TargetLocator {
1748
2187
  */
1749
2188
  alert() {
1750
2189
  var text = this.driver_.execute(
1751
- new command.Command(command.Name.GET_ALERT_TEXT));
1752
- var driver = this.driver_;
1753
- return new AlertPromise(driver, text.then(function(text) {
1754
- return new Alert(driver, text);
1755
- }));
2190
+ new command.Command(command.Name.GET_ALERT_TEXT)
2191
+ )
2192
+ var driver = this.driver_
2193
+ return new AlertPromise(
2194
+ driver,
2195
+ text.then(function (text) {
2196
+ return new Alert(driver, text)
2197
+ })
2198
+ )
1756
2199
  }
1757
2200
  }
1758
2201
 
1759
-
1760
2202
  //////////////////////////////////////////////////////////////////////////////
1761
2203
  //
1762
2204
  // WebElement
1763
2205
  //
1764
2206
  //////////////////////////////////////////////////////////////////////////////
1765
2207
 
1766
-
1767
- const LEGACY_ELEMENT_ID_KEY = 'ELEMENT';
1768
- const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
1769
-
2208
+ const LEGACY_ELEMENT_ID_KEY = 'ELEMENT'
2209
+ const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf'
1770
2210
 
1771
2211
  /**
1772
2212
  * Represents a DOM element. WebElements can be found by searching from the
@@ -1786,10 +2226,10 @@ class WebElement {
1786
2226
  */
1787
2227
  constructor(driver, id) {
1788
2228
  /** @private {!WebDriver} */
1789
- this.driver_ = driver;
2229
+ this.driver_ = driver
1790
2230
 
1791
2231
  /** @private {!Promise<string>} */
1792
- this.id_ = Promise.resolve(id);
2232
+ this.id_ = Promise.resolve(id)
1793
2233
  }
1794
2234
 
1795
2235
  /**
@@ -1799,8 +2239,8 @@ class WebElement {
1799
2239
  */
1800
2240
  static buildId(id, noLegacy = false) {
1801
2241
  return noLegacy
1802
- ? {[ELEMENT_ID_KEY]: id}
1803
- : {[ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id};
2242
+ ? { [ELEMENT_ID_KEY]: id }
2243
+ : { [ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id }
1804
2244
  }
1805
2245
 
1806
2246
  /**
@@ -1813,12 +2253,12 @@ class WebElement {
1813
2253
  static extractId(obj) {
1814
2254
  if (obj && typeof obj === 'object') {
1815
2255
  if (typeof obj[ELEMENT_ID_KEY] === 'string') {
1816
- return obj[ELEMENT_ID_KEY];
2256
+ return obj[ELEMENT_ID_KEY]
1817
2257
  } else if (typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string') {
1818
- return obj[LEGACY_ELEMENT_ID_KEY];
2258
+ return obj[LEGACY_ELEMENT_ID_KEY]
1819
2259
  }
1820
2260
  }
1821
- throw new TypeError('object is not a WebElement ID');
2261
+ throw new TypeError('object is not a WebElement ID')
1822
2262
  }
1823
2263
 
1824
2264
  /**
@@ -1826,9 +2266,12 @@ class WebElement {
1826
2266
  * @return {boolean} whether the object is a valid encoded WebElement ID.
1827
2267
  */
1828
2268
  static isId(obj) {
1829
- return obj && typeof obj === 'object'
1830
- && (typeof obj[ELEMENT_ID_KEY] === 'string'
1831
- || typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string');
2269
+ return (
2270
+ obj &&
2271
+ typeof obj === 'object' &&
2272
+ (typeof obj[ELEMENT_ID_KEY] === 'string' ||
2273
+ typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string')
2274
+ )
1832
2275
  }
1833
2276
 
1834
2277
  /**
@@ -1841,15 +2284,14 @@ class WebElement {
1841
2284
  */
1842
2285
  static async equals(a, b) {
1843
2286
  if (a === b) {
1844
- return true;
2287
+ return true
1845
2288
  }
1846
- return a.driver_.executeScript(
1847
- 'return arguments[0] === arguments[1]', a, b);
2289
+ return a.driver_.executeScript('return arguments[0] === arguments[1]', a, b)
1848
2290
  }
1849
2291
 
1850
2292
  /** @return {!WebDriver} The parent driver for this instance. */
1851
2293
  getDriver() {
1852
- return this.driver_;
2294
+ return this.driver_
1853
2295
  }
1854
2296
 
1855
2297
  /**
@@ -1857,14 +2299,14 @@ class WebElement {
1857
2299
  * the server-assigned opaque ID assigned to this element.
1858
2300
  */
1859
2301
  getId() {
1860
- return this.id_;
2302
+ return this.id_
1861
2303
  }
1862
2304
 
1863
2305
  /**
1864
2306
  * @return {!Object} Returns the serialized representation of this WebElement.
1865
2307
  */
1866
2308
  [Symbols.serialize]() {
1867
- return this.getId().then(WebElement.buildId);
2309
+ return this.getId().then(WebElement.buildId)
1868
2310
  }
1869
2311
 
1870
2312
  /**
@@ -1879,8 +2321,8 @@ class WebElement {
1879
2321
  * @private
1880
2322
  */
1881
2323
  execute_(command) {
1882
- command.setParameter('id', this);
1883
- return this.driver_.execute(command);
2324
+ command.setParameter('id', this)
2325
+ return this.driver_.execute(command)
1884
2326
  }
1885
2327
 
1886
2328
  /**
@@ -1918,18 +2360,17 @@ class WebElement {
1918
2360
  * element will be invalidated and all scheduled commands aborted.
1919
2361
  */
1920
2362
  findElement(locator) {
1921
- locator = by.checkedLocator(locator);
1922
- let id;
2363
+ locator = by.checkedLocator(locator)
2364
+ let id
1923
2365
  if (typeof locator === 'function') {
1924
- id = this.driver_.findElementInternal_(locator, this);
2366
+ id = this.driver_.findElementInternal_(locator, this)
1925
2367
  } else {
1926
- let cmd = new command.Command(
1927
- command.Name.FIND_CHILD_ELEMENT).
1928
- setParameter('using', locator.using).
1929
- setParameter('value', locator.value);
1930
- id = this.execute_(cmd);
2368
+ let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENT)
2369
+ .setParameter('using', locator.using)
2370
+ .setParameter('value', locator.value)
2371
+ id = this.execute_(cmd)
1931
2372
  }
1932
- return new WebElementPromise(this.driver_, id);
2373
+ return new WebElementPromise(this.driver_, id)
1933
2374
  }
1934
2375
 
1935
2376
  /**
@@ -1942,16 +2383,15 @@ class WebElement {
1942
2383
  * array of WebElements.
1943
2384
  */
1944
2385
  async findElements(locator) {
1945
- locator = by.checkedLocator(locator);
1946
- let id;
2386
+ locator = by.checkedLocator(locator)
1947
2387
  if (typeof locator === 'function') {
1948
- return this.driver_.findElementsInternal_(locator, this);
2388
+ return this.driver_.findElementsInternal_(locator, this)
1949
2389
  } else {
1950
2390
  let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENTS)
1951
- .setParameter('using', locator.using)
1952
- .setParameter('value', locator.value);
1953
- let result = await this.execute_(cmd);
1954
- return Array.isArray(result) ? result : [];
2391
+ .setParameter('using', locator.using)
2392
+ .setParameter('value', locator.value)
2393
+ let result = await this.execute_(cmd)
2394
+ return Array.isArray(result) ? result : []
1955
2395
  }
1956
2396
  }
1957
2397
 
@@ -1962,7 +2402,7 @@ class WebElement {
1962
2402
  * command has completed.
1963
2403
  */
1964
2404
  click() {
1965
- return this.execute_(new command.Command(command.Name.CLICK_ELEMENT));
2405
+ return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
1966
2406
  }
1967
2407
 
1968
2408
  /**
@@ -2021,34 +2461,37 @@ class WebElement {
2021
2461
  * have been typed.
2022
2462
  */
2023
2463
  async sendKeys(...args) {
2024
- let keys = [];
2025
- (await Promise.all(args)).forEach(key => {
2026
- let type = typeof key;
2027
- if (type === 'number') {
2028
- key = String(key);
2029
- } else if (type !== 'string') {
2030
- throw TypeError('each key must be a number of string; got ' + type);
2031
- }
2464
+ let keys = []
2465
+ ; (await Promise.all(args)).forEach((key) => {
2466
+ let type = typeof key
2467
+ if (type === 'number') {
2468
+ key = String(key)
2469
+ } else if (type !== 'string') {
2470
+ throw TypeError('each key must be a number of string; got ' + type)
2471
+ }
2032
2472
 
2033
- // The W3C protocol requires keys to be specified as an array where
2034
- // each element is a single key.
2035
- keys.push(...key.split(''));
2036
- });
2473
+ // The W3C protocol requires keys to be specified as an array where
2474
+ // each element is a single key.
2475
+ keys.push(...key.split(''))
2476
+ })
2037
2477
 
2038
2478
  if (!this.driver_.fileDetector_) {
2039
2479
  return this.execute_(
2040
- new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2041
- .setParameter('text', keys.join(''))
2042
- .setParameter('value', keys));
2480
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2481
+ .setParameter('text', keys.join(''))
2482
+ .setParameter('value', keys)
2483
+ )
2043
2484
  }
2044
2485
 
2045
- keys =
2046
- await this.driver_.fileDetector_.handleFile(
2047
- this.driver_, keys.join(''));
2486
+ keys = await this.driver_.fileDetector_.handleFile(
2487
+ this.driver_,
2488
+ keys.join('')
2489
+ )
2048
2490
  return this.execute_(
2049
- new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2050
- .setParameter('text', keys)
2051
- .setParameter('value', keys.split('')));
2491
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2492
+ .setParameter('text', keys)
2493
+ .setParameter('value', keys.split(''))
2494
+ )
2052
2495
  }
2053
2496
 
2054
2497
  /**
@@ -2058,8 +2501,7 @@ class WebElement {
2058
2501
  * element's tag name.
2059
2502
  */
2060
2503
  getTagName() {
2061
- return this.execute_(
2062
- new command.Command(command.Name.GET_ELEMENT_TAG_NAME));
2504
+ return this.execute_(new command.Command(command.Name.GET_ELEMENT_TAG_NAME))
2063
2505
  }
2064
2506
 
2065
2507
  /**
@@ -2077,10 +2519,10 @@ class WebElement {
2077
2519
  * requested CSS value.
2078
2520
  */
2079
2521
  getCssValue(cssStyleProperty) {
2080
- var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY;
2522
+ var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
2081
2523
  return this.execute_(
2082
- new command.Command(name).
2083
- setParameter('propertyName', cssStyleProperty));
2524
+ new command.Command(name).setParameter('propertyName', cssStyleProperty)
2525
+ )
2084
2526
  }
2085
2527
 
2086
2528
  /**
@@ -2114,8 +2556,11 @@ class WebElement {
2114
2556
  */
2115
2557
  getAttribute(attributeName) {
2116
2558
  return this.execute_(
2117
- new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).
2118
- setParameter('name', attributeName));
2559
+ new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).setParameter(
2560
+ 'name',
2561
+ attributeName
2562
+ )
2563
+ )
2119
2564
  }
2120
2565
 
2121
2566
  /**
@@ -2126,7 +2571,11 @@ class WebElement {
2126
2571
  */
2127
2572
  getProperty(propertyName) {
2128
2573
  return this.execute_(
2129
- new command.Command(command.Name.GET_ELEMENT_PROPERTY).setParameter('name', propertyName));
2574
+ new command.Command(command.Name.GET_ELEMENT_PROPERTY).setParameter(
2575
+ 'name',
2576
+ propertyName
2577
+ )
2578
+ )
2130
2579
  }
2131
2580
 
2132
2581
  /**
@@ -2137,9 +2586,28 @@ class WebElement {
2137
2586
  * resolved with the element's visible text.
2138
2587
  */
2139
2588
  getText() {
2140
- return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT));
2589
+ return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
2590
+ }
2591
+
2592
+ /**
2593
+ * Get the computed WAI-ARIA role of element.
2594
+ *
2595
+ * @return {!Promise<string>} A promise that will be
2596
+ * resolved with the element's computed role.
2597
+ */
2598
+ getAriaRole() {
2599
+ return this.execute_(new command.Command(command.Name.GET_COMPUTED_ROLE))
2141
2600
  }
2142
2601
 
2602
+ /**
2603
+ * Get the computed WAI-ARIA label of element.
2604
+ *
2605
+ * @return {!Promise<string>} A promise that will be
2606
+ * resolved with the element's computed label.
2607
+ */
2608
+ getAccessibleName() {
2609
+ return this.execute_(new command.Command(command.Name.GET_COMPUTED_LABEL))
2610
+ }
2143
2611
  /**
2144
2612
  * Returns an object describing an element's location, in pixels relative to
2145
2613
  * the document element, and the element's size in pixels.
@@ -2150,16 +2618,17 @@ class WebElement {
2150
2618
  async getRect() {
2151
2619
  try {
2152
2620
  return await this.execute_(
2153
- new command.Command(command.Name.GET_ELEMENT_RECT));
2621
+ new command.Command(command.Name.GET_ELEMENT_RECT)
2622
+ )
2154
2623
  } catch (err) {
2155
2624
  if (err instanceof error.UnknownCommandError) {
2156
- const {width, height} =
2157
- await this.execute_(
2158
- new command.Command(command.Name.GET_ELEMENT_SIZE));
2159
- const {x, y} =
2160
- await this.execute_(
2161
- new command.Command(command.Name.GET_ELEMENT_LOCATION));
2162
- return {x, y, width, height};
2625
+ const { width, height } = await this.execute_(
2626
+ new command.Command(command.Name.GET_ELEMENT_SIZE)
2627
+ )
2628
+ const { x, y } = await this.execute_(
2629
+ new command.Command(command.Name.GET_ELEMENT_LOCATION)
2630
+ )
2631
+ return { x, y, width, height }
2163
2632
  }
2164
2633
  }
2165
2634
  }
@@ -2172,7 +2641,7 @@ class WebElement {
2172
2641
  * resolved with whether this element is currently enabled.
2173
2642
  */
2174
2643
  isEnabled() {
2175
- return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED));
2644
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
2176
2645
  }
2177
2646
 
2178
2647
  /**
@@ -2182,8 +2651,7 @@ class WebElement {
2182
2651
  * resolved with whether this element is currently selected.
2183
2652
  */
2184
2653
  isSelected() {
2185
- return this.execute_(
2186
- new command.Command(command.Name.IS_ELEMENT_SELECTED));
2654
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_SELECTED))
2187
2655
  }
2188
2656
 
2189
2657
  /**
@@ -2195,7 +2663,7 @@ class WebElement {
2195
2663
  * when the form has been submitted.
2196
2664
  */
2197
2665
  submit() {
2198
- return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT));
2666
+ return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
2199
2667
  }
2200
2668
 
2201
2669
  /**
@@ -2207,7 +2675,7 @@ class WebElement {
2207
2675
  * when the element has been cleared.
2208
2676
  */
2209
2677
  clear() {
2210
- return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT));
2678
+ return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
2211
2679
  }
2212
2680
 
2213
2681
  /**
@@ -2217,8 +2685,7 @@ class WebElement {
2217
2685
  * resolved with whether this element is currently visible on the page.
2218
2686
  */
2219
2687
  isDisplayed() {
2220
- return this.execute_(
2221
- new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
2688
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_DISPLAYED))
2222
2689
  }
2223
2690
 
2224
2691
  /**
@@ -2233,12 +2700,14 @@ class WebElement {
2233
2700
  */
2234
2701
  takeScreenshot(scroll = false) {
2235
2702
  return this.execute_(
2236
- new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT)
2237
- .setParameter('scroll', scroll));
2703
+ new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT).setParameter(
2704
+ 'scroll',
2705
+ scroll
2706
+ )
2707
+ )
2238
2708
  }
2239
2709
  }
2240
2710
 
2241
-
2242
2711
  /**
2243
2712
  * WebElementPromise is a promise that will be fulfilled with a WebElement.
2244
2713
  * This serves as a forward proxy on WebElement, allowing calls to be
@@ -2262,35 +2731,33 @@ class WebElementPromise extends WebElement {
2262
2731
  * that will resolve to the promised element.
2263
2732
  */
2264
2733
  constructor(driver, el) {
2265
- super(driver, 'unused');
2734
+ super(driver, 'unused')
2266
2735
 
2267
2736
  /** @override */
2268
- this.then = el.then.bind(el);
2737
+ this.then = el.then.bind(el)
2269
2738
 
2270
2739
  /** @override */
2271
- this.catch = el.catch.bind(el);
2740
+ this.catch = el.catch.bind(el)
2272
2741
 
2273
2742
  /**
2274
2743
  * Defers returning the element ID until the wrapped WebElement has been
2275
2744
  * resolved.
2276
2745
  * @override
2277
2746
  */
2278
- this.getId = function() {
2279
- return el.then(function(el) {
2280
- return el.getId();
2281
- });
2282
- };
2747
+ this.getId = function () {
2748
+ return el.then(function (el) {
2749
+ return el.getId()
2750
+ })
2751
+ }
2283
2752
  }
2284
2753
  }
2285
2754
 
2286
-
2287
2755
  //////////////////////////////////////////////////////////////////////////////
2288
2756
  //
2289
2757
  // Alert
2290
2758
  //
2291
2759
  //////////////////////////////////////////////////////////////////////////////
2292
2760
 
2293
-
2294
2761
  /**
2295
2762
  * Represents a modal dialog such as {@code alert}, {@code confirm}, or
2296
2763
  * {@code prompt}. Provides functions to retrieve the message displayed with
@@ -2305,10 +2772,10 @@ class Alert {
2305
2772
  */
2306
2773
  constructor(driver, text) {
2307
2774
  /** @private {!WebDriver} */
2308
- this.driver_ = driver;
2775
+ this.driver_ = driver
2309
2776
 
2310
2777
  /** @private {!Promise<string>} */
2311
- this.text_ = Promise.resolve(text);
2778
+ this.text_ = Promise.resolve(text)
2312
2779
  }
2313
2780
 
2314
2781
  /**
@@ -2319,7 +2786,7 @@ class Alert {
2319
2786
  * resolved to the text displayed with this alert.
2320
2787
  */
2321
2788
  getText() {
2322
- return this.text_;
2789
+ return this.text_
2323
2790
  }
2324
2791
 
2325
2792
  /**
@@ -2329,8 +2796,7 @@ class Alert {
2329
2796
  * when this command has completed.
2330
2797
  */
2331
2798
  accept() {
2332
- return this.driver_.execute(
2333
- new command.Command(command.Name.ACCEPT_ALERT));
2799
+ return this.driver_.execute(new command.Command(command.Name.ACCEPT_ALERT))
2334
2800
  }
2335
2801
 
2336
2802
  /**
@@ -2340,8 +2806,7 @@ class Alert {
2340
2806
  * when this command has completed.
2341
2807
  */
2342
2808
  dismiss() {
2343
- return this.driver_.execute(
2344
- new command.Command(command.Name.DISMISS_ALERT));
2809
+ return this.driver_.execute(new command.Command(command.Name.DISMISS_ALERT))
2345
2810
  }
2346
2811
 
2347
2812
  /**
@@ -2355,12 +2820,14 @@ class Alert {
2355
2820
  */
2356
2821
  sendKeys(text) {
2357
2822
  return this.driver_.execute(
2358
- new command.Command(command.Name.SET_ALERT_TEXT).
2359
- setParameter('text', text));
2823
+ new command.Command(command.Name.SET_ALERT_TEXT).setParameter(
2824
+ 'text',
2825
+ text
2826
+ )
2827
+ )
2360
2828
  }
2361
2829
  }
2362
2830
 
2363
-
2364
2831
  /**
2365
2832
  * AlertPromise is a promise that will be fulfilled with an Alert. This promise
2366
2833
  * serves as a forward proxy on an Alert, allowing calls to be scheduled
@@ -2383,60 +2850,58 @@ class AlertPromise extends Alert {
2383
2850
  * that will be fulfilled with the promised alert.
2384
2851
  */
2385
2852
  constructor(driver, alert) {
2386
- super(driver, 'unused');
2853
+ super(driver, 'unused')
2387
2854
 
2388
2855
  /** @override */
2389
- this.then = alert.then.bind(alert);
2856
+ this.then = alert.then.bind(alert)
2390
2857
 
2391
2858
  /** @override */
2392
- this.catch = alert.catch.bind(alert);
2859
+ this.catch = alert.catch.bind(alert)
2393
2860
 
2394
2861
  /**
2395
2862
  * Defer returning text until the promised alert has been resolved.
2396
2863
  * @override
2397
2864
  */
2398
- this.getText = function() {
2399
- return alert.then(function(alert) {
2400
- return alert.getText();
2401
- });
2402
- };
2865
+ this.getText = function () {
2866
+ return alert.then(function (alert) {
2867
+ return alert.getText()
2868
+ })
2869
+ }
2403
2870
 
2404
2871
  /**
2405
2872
  * Defers action until the alert has been located.
2406
2873
  * @override
2407
2874
  */
2408
- this.accept = function() {
2409
- return alert.then(function(alert) {
2410
- return alert.accept();
2411
- });
2412
- };
2875
+ this.accept = function () {
2876
+ return alert.then(function (alert) {
2877
+ return alert.accept()
2878
+ })
2879
+ }
2413
2880
 
2414
2881
  /**
2415
2882
  * Defers action until the alert has been located.
2416
2883
  * @override
2417
2884
  */
2418
- this.dismiss = function() {
2419
- return alert.then(function(alert) {
2420
- return alert.dismiss();
2421
- });
2422
- };
2885
+ this.dismiss = function () {
2886
+ return alert.then(function (alert) {
2887
+ return alert.dismiss()
2888
+ })
2889
+ }
2423
2890
 
2424
2891
  /**
2425
2892
  * Defers action until the alert has been located.
2426
2893
  * @override
2427
2894
  */
2428
- this.sendKeys = function(text) {
2429
- return alert.then(function(alert) {
2430
- return alert.sendKeys(text);
2431
- });
2432
- };
2895
+ this.sendKeys = function (text) {
2896
+ return alert.then(function (alert) {
2897
+ return alert.sendKeys(text)
2898
+ })
2899
+ }
2433
2900
  }
2434
2901
  }
2435
2902
 
2436
-
2437
2903
  // PUBLIC API
2438
2904
 
2439
-
2440
2905
  module.exports = {
2441
2906
  Alert,
2442
2907
  AlertPromise,
@@ -2450,5 +2915,5 @@ module.exports = {
2450
2915
  WebElement,
2451
2916
  WebElementCondition,
2452
2917
  WebElementPromise,
2453
- Window
2454
- };
2918
+ Window,
2919
+ }