selenium-webdriver 4.0.0-alpha.5 → 4.0.0-beta.1

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