selenium-webdriver 4.0.0-alpha.4 → 4.0.0-alpha.8

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 (52) hide show
  1. package/.eslintrc.js +27 -0
  2. package/.prettierrc +4 -0
  3. package/CHANGES.md +22 -1
  4. package/README.md +4 -4
  5. package/chrome.js +72 -590
  6. package/chromium.js +1024 -0
  7. package/devtools/CDPConnection.js +37 -0
  8. package/devtools/generator/protocol-dts-generator.js +429 -0
  9. package/edge.js +124 -86
  10. package/firefox.js +201 -202
  11. package/http/index.js +131 -115
  12. package/http/util.js +56 -64
  13. package/ie.js +180 -104
  14. package/index.js +246 -199
  15. package/io/exec.js +34 -39
  16. package/io/index.js +141 -151
  17. package/io/zip.js +75 -65
  18. package/lib/README +5 -0
  19. package/lib/actions.js +138 -121
  20. package/lib/atoms/find-elements.js +123 -0
  21. package/lib/atoms/get-attribute.js +79 -60
  22. package/lib/atoms/is-displayed.js +72 -73
  23. package/{example/chrome_mobile_emulation.js → lib/atoms/make-atoms-module.js} +16 -23
  24. package/lib/by.js +192 -65
  25. package/lib/capabilities.js +82 -78
  26. package/lib/command.js +18 -20
  27. package/lib/error.js +134 -168
  28. package/lib/http.js +324 -230
  29. package/lib/input.js +325 -302
  30. package/lib/logging.js +127 -138
  31. package/lib/promise.js +60 -66
  32. package/lib/proxy.js +31 -41
  33. package/lib/session.js +12 -15
  34. package/lib/symbols.js +3 -4
  35. package/lib/until.js +162 -162
  36. package/lib/webdriver.js +733 -522
  37. package/net/index.js +30 -36
  38. package/net/portprober.js +31 -144
  39. package/opera.js +406 -0
  40. package/package.json +18 -11
  41. package/proxy.js +2 -2
  42. package/remote/index.js +190 -187
  43. package/safari.js +40 -49
  44. package/LICENSE +0 -202
  45. package/NOTICE +0 -2
  46. package/example/chrome_android.js +0 -42
  47. package/example/firefox_channels.js +0 -77
  48. package/example/google_search.js +0 -50
  49. package/example/google_search_test.js +0 -72
  50. package/example/headless.js +0 -55
  51. package/example/logging.js +0 -68
  52. package/testing/index.js +0 -498
package/lib/webdriver.js CHANGED
@@ -19,32 +19,31 @@
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 { Capabilities } = require('./capabilities')
34
33
 
35
34
  // Capability names that are defined in the W3C spec.
36
35
  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
-
36
+ 'acceptInsecureCerts',
37
+ 'browserName',
38
+ 'browserVersion',
39
+ 'platformName',
40
+ 'pageLoadStrategy',
41
+ 'proxy',
42
+ 'setWindowRect',
43
+ 'timeouts',
44
+ 'strictFileInteractability',
45
+ 'unhandledPromptBehavior',
46
+ ])
48
47
 
49
48
  /**
50
49
  * Defines a condition for use with WebDriver's {@linkplain WebDriver#wait wait
@@ -61,19 +60,18 @@ class Condition {
61
60
  */
62
61
  constructor(message, fn) {
63
62
  /** @private {string} */
64
- this.description_ = 'Waiting ' + message;
63
+ this.description_ = 'Waiting ' + message
65
64
 
66
65
  /** @type {function(!WebDriver): OUT} */
67
- this.fn = fn;
66
+ this.fn = fn
68
67
  }
69
68
 
70
69
  /** @return {string} A description of this condition. */
71
70
  description() {
72
- return this.description_;
71
+ return this.description_
73
72
  }
74
73
  }
75
74
 
76
-
77
75
  /**
78
76
  * Defines a condition that will result in a {@link WebElement}.
79
77
  *
@@ -88,18 +86,16 @@ class WebElementCondition extends Condition {
88
86
  * loop.
89
87
  */
90
88
  constructor(message, fn) {
91
- super(message, fn);
89
+ super(message, fn)
92
90
  }
93
91
  }
94
92
 
95
-
96
93
  //////////////////////////////////////////////////////////////////////////////
97
94
  //
98
95
  // WebDriver
99
96
  //
100
97
  //////////////////////////////////////////////////////////////////////////////
101
98
 
102
-
103
99
  /**
104
100
  * Translates a command to its wire-protocol representation before passing it
105
101
  * to the given `executor` for execution.
@@ -108,14 +104,12 @@ class WebElementCondition extends Condition {
108
104
  * @return {!Promise} A promise that will resolve with the command response.
109
105
  */
110
106
  function executeCommand(executor, command) {
111
- return toWireValue(command.getParameters()).
112
- then(function(parameters) {
113
- command.setParameters(parameters);
114
- return executor.execute(command);
115
- });
107
+ return toWireValue(command.getParameters()).then(function (parameters) {
108
+ command.setParameters(parameters)
109
+ return executor.execute(command)
110
+ })
116
111
  }
117
112
 
118
-
119
113
  /**
120
114
  * Converts an object to its JSON representation in the WebDriver wire protocol.
121
115
  * When converting values of type object, the following steps will be taken:
@@ -135,64 +129,62 @@ function executeCommand(executor, command) {
135
129
  * representation.
136
130
  */
137
131
  async function toWireValue(obj) {
138
- let value = await Promise.resolve(obj);
132
+ let value = await Promise.resolve(obj)
139
133
  if (value === void 0 || value === null) {
140
- return value;
134
+ return value
141
135
  }
142
136
 
143
- if (typeof value === 'boolean'
144
- || typeof value === 'number'
145
- || typeof value === 'string') {
146
- return value;
137
+ if (
138
+ typeof value === 'boolean' ||
139
+ typeof value === 'number' ||
140
+ typeof value === 'string'
141
+ ) {
142
+ return value
147
143
  }
148
144
 
149
145
  if (Array.isArray(value)) {
150
- return convertKeys(value);
146
+ return convertKeys(value)
151
147
  }
152
148
 
153
149
  if (typeof value === 'function') {
154
- return '' + value;
150
+ return '' + value
155
151
  }
156
152
 
157
153
  if (typeof value[Symbols.serialize] === 'function') {
158
- return toWireValue(value[Symbols.serialize]());
154
+ return toWireValue(value[Symbols.serialize]())
159
155
  } else if (typeof value.toJSON === 'function') {
160
- return toWireValue(value.toJSON());
156
+ return toWireValue(value.toJSON())
161
157
  }
162
- return convertKeys(value);
158
+ return convertKeys(value)
163
159
  }
164
160
 
165
-
166
161
  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) : {};
162
+ const isArray = Array.isArray(obj)
163
+ const numKeys = isArray ? obj.length : Object.keys(obj).length
164
+ const ret = isArray ? new Array(numKeys) : {}
170
165
  if (!numKeys) {
171
- return ret;
166
+ return ret
172
167
  }
173
168
 
174
- let numResolved = 0;
175
-
176
169
  async function forEachKey(obj, fn) {
177
170
  if (Array.isArray(obj)) {
178
171
  for (let i = 0, n = obj.length; i < n; i++) {
179
- await fn(obj[i], i);
172
+ await fn(obj[i], i)
180
173
  }
181
174
  } else {
182
175
  for (let key in obj) {
183
- await fn(obj[key], key);
176
+ await fn(obj[key], key)
184
177
  }
185
178
  }
186
179
  }
187
180
 
188
- await forEachKey(obj, async function(value, key) {
189
- ret[key] = await toWireValue(value);
190
- });
181
+ await forEachKey(obj, async function (value, key) {
182
+ ret[key] = await toWireValue(value)
183
+ })
191
184
 
192
- return ret;
185
+ return ret
193
186
  }
194
187
 
195
-
196
188
  /**
197
189
  * Converts a value from its JSON representation according to the WebDriver wire
198
190
  * protocol. Any JSON object that defines a WebElement ID will be decoded to a
@@ -205,22 +197,32 @@ async function convertKeys(obj) {
205
197
  */
206
198
  function fromWireValue(driver, value) {
207
199
  if (Array.isArray(value)) {
208
- value = value.map(v => fromWireValue(driver, v));
200
+ value = value.map((v) => fromWireValue(driver, v))
209
201
  } else if (WebElement.isId(value)) {
210
- let id = WebElement.extractId(value);
211
- value = new WebElement(driver, id);
202
+ let id = WebElement.extractId(value)
203
+ value = new WebElement(driver, id)
212
204
  } else if (value && typeof value === 'object') {
213
- let result = {};
205
+ let result = {}
214
206
  for (let key in value) {
215
- if (value.hasOwnProperty(key)) {
216
- result[key] = fromWireValue(driver, value[key]);
207
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
208
+ result[key] = fromWireValue(driver, value[key])
217
209
  }
218
210
  }
219
- value = result;
211
+ value = result
220
212
  }
221
- return value;
213
+ return value
222
214
  }
223
215
 
216
+ /**
217
+ * Resolves a wait message from either a function or a string.
218
+ * @param {(string|Function)=} message An optional message to use if the wait times out.
219
+ * @return {string} The resolved message
220
+ */
221
+ function resolveWaitMessage(message) {
222
+ return message
223
+ ? `${typeof message === 'function' ? message() : message}\n`
224
+ : ''
225
+ }
224
226
 
225
227
  /**
226
228
  * Structural interface for a WebDriver client.
@@ -228,7 +230,6 @@ function fromWireValue(driver, value) {
228
230
  * @record
229
231
  */
230
232
  class IWebDriver {
231
-
232
233
  /**
233
234
  * Executes the provided {@link command.Command} using this driver's
234
235
  * {@link command.Executor}.
@@ -238,14 +239,14 @@ class IWebDriver {
238
239
  * result.
239
240
  * @template T
240
241
  */
241
- execute(command) {}
242
+ execute(command) {} // eslint-disable-line
242
243
 
243
244
  /**
244
245
  * Sets the {@linkplain input.FileDetector file detector} that should be
245
246
  * used with this instance.
246
247
  * @param {input.FileDetector} detector The detector to use or `null`.
247
248
  */
248
- setFileDetector(detector) {}
249
+ setFileDetector(detector) {} // eslint-disable-line
249
250
 
250
251
  /**
251
252
  * @return {!command.Executor} The command executor used by this instance.
@@ -284,7 +285,7 @@ class IWebDriver {
284
285
  * for details).
285
286
  * @return {!input.Actions} A new action sequence for this instance.
286
287
  */
287
- actions(options) {}
288
+ actions(options) {} // eslint-disable-line
288
289
 
289
290
  /**
290
291
  * Executes a snippet of JavaScript in the context of the currently selected
@@ -322,7 +323,7 @@ class IWebDriver {
322
323
  * scripts return value.
323
324
  * @template T
324
325
  */
325
- executeScript(script, ...args) {}
326
+ executeScript(script, ...args) {} // eslint-disable-line
326
327
 
327
328
  /**
328
329
  * Executes a snippet of asynchronous JavaScript in the context of the
@@ -399,7 +400,7 @@ class IWebDriver {
399
400
  * value.
400
401
  * @template T
401
402
  */
402
- executeAsyncScript(script, ...args) {}
403
+ executeAsyncScript(script, ...args) {} // eslint-disable-line
403
404
 
404
405
  /**
405
406
  * Waits for a condition to evaluate to a "truthy" value. The condition may be
@@ -434,7 +435,7 @@ class IWebDriver {
434
435
  * evaluate as a condition.
435
436
  * @param {number=} timeout The duration in milliseconds, how long to wait
436
437
  * for the condition to be true.
437
- * @param {string=} message An optional message to use if the wait times out.
438
+ * @param {(string|Function)=} message An optional message to use if the wait times out.
438
439
  * @param {number=} pollTimeout The duration in milliseconds, how long to
439
440
  * wait between polling the condition.
440
441
  * @return {!(IThenable<T>|WebElementPromise)} A promise that will be
@@ -445,7 +446,12 @@ class IWebDriver {
445
446
  * @throws {TypeError} if the provided `condition` is not a valid type.
446
447
  * @template T
447
448
  */
448
- wait(condition, timeout = undefined, message = undefined, pollTimeout = undefined) {}
449
+ wait(
450
+ condition, // eslint-disable-line
451
+ timeout = undefined, // eslint-disable-line
452
+ message = undefined, // eslint-disable-line
453
+ pollTimeout = undefined // eslint-disable-line
454
+ ) {}
449
455
 
450
456
  /**
451
457
  * Makes the driver sleep for the given amount of time.
@@ -454,7 +460,7 @@ class IWebDriver {
454
460
  * @return {!Promise<void>} A promise that will be resolved when the sleep has
455
461
  * finished.
456
462
  */
457
- sleep(ms) {}
463
+ sleep(ms) {} // eslint-disable-line
458
464
 
459
465
  /**
460
466
  * Retrieves the current window handle.
@@ -473,7 +479,7 @@ class IWebDriver {
473
479
  getAllWindowHandles() {}
474
480
 
475
481
  /**
476
- * Retrieves the current page's source. The returned souce is a representation
482
+ * Retrieves the current page's source. The returned source is a representation
477
483
  * of the underlying DOM: do not expect it to be formatted or escaped in the
478
484
  * same way as the raw response sent from the web server.
479
485
  *
@@ -497,7 +503,7 @@ class IWebDriver {
497
503
  * @return {!Promise<void>} A promise that will be resolved when the document
498
504
  * has finished loading.
499
505
  */
500
- get(url) {}
506
+ get(url) {} // eslint-disable-line
501
507
 
502
508
  /**
503
509
  * Retrieves the URL for the current page.
@@ -517,7 +523,7 @@ class IWebDriver {
517
523
 
518
524
  /**
519
525
  * Locates an element on the page. If the element cannot be found, a
520
- * {@link error.NoSuchEementError} will be returned by the driver.
526
+ * {@link error.NoSuchElementError} will be returned by the driver.
521
527
  *
522
528
  * This function should not be used to test whether an element is present on
523
529
  * the page. Rather, you should use {@link #findElements}:
@@ -553,7 +559,7 @@ class IWebDriver {
553
559
  * commands against the located element. If the element is not found, the
554
560
  * element will be invalidated and all scheduled commands aborted.
555
561
  */
556
- findElement(locator) {}
562
+ findElement(locator) {} // eslint-disable-line
557
563
 
558
564
  /**
559
565
  * Search for multiple elements on the page. Refer to the documentation on
@@ -563,7 +569,7 @@ class IWebDriver {
563
569
  * @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
564
570
  * array of WebElements.
565
571
  */
566
- findElements(locator) {}
572
+ findElements(locator) {} // eslint-disable-line
567
573
 
568
574
  /**
569
575
  * Takes a screenshot of the current page. The driver makes a best effort to
@@ -594,8 +600,26 @@ class IWebDriver {
594
600
  * instance.
595
601
  */
596
602
  switchTo() {}
597
- }
598
603
 
604
+ /**
605
+ *
606
+ * Takes a PDF of the current page. The driver makes a best effort to
607
+ * return a PDF based on the provided parameters.
608
+ *
609
+ * @param {{orientation: (string|undefined),
610
+ * scale: (number|undefined),
611
+ * background: (boolean|undefined)
612
+ * width: (number|undefined)
613
+ * height: (number|undefined)
614
+ * top: (number|undefined)
615
+ * bottom: (number|undefined)
616
+ * left: (number|undefined)
617
+ * right: (number|undefined)
618
+ * shrinkToFit: (boolean|undefined)
619
+ * pageRanges: (<Array>|undefined)}} options.
620
+ */
621
+ printPage(options) {} // eslint-disable-line
622
+ }
599
623
 
600
624
  /**
601
625
  * @param {!Capabilities} capabilities A capabilities object.
@@ -603,17 +627,16 @@ class IWebDriver {
603
627
  * capability names that are not valid W3C names.
604
628
  */
605
629
  function filterNonW3CCaps(capabilities) {
606
- let newCaps = new Capabilities(capabilities);
630
+ let newCaps = new Capabilities(capabilities)
607
631
  for (let k of newCaps.keys()) {
608
632
  // Any key containing a colon is a vendor-prefixed capability.
609
633
  if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
610
- newCaps.delete(k);
634
+ newCaps.delete(k)
611
635
  }
612
636
  }
613
- return newCaps;
637
+ return newCaps
614
638
  }
615
639
 
616
-
617
640
  /**
618
641
  * Each WebDriver instance provides automated control over a browser session.
619
642
  *
@@ -630,21 +653,21 @@ class WebDriver {
630
653
  */
631
654
  constructor(session, executor, onQuit = undefined) {
632
655
  /** @private {!Promise<!Session>} */
633
- this.session_ = Promise.resolve(session);
656
+ this.session_ = Promise.resolve(session)
634
657
 
635
658
  // If session is a rejected promise, add a no-op rejection handler.
636
659
  // This effectively hides setup errors until users attempt to interact
637
660
  // with the session.
638
- this.session_.catch(function() {});
661
+ this.session_.catch(function () {})
639
662
 
640
663
  /** @private {!command.Executor} */
641
- this.executor_ = executor;
664
+ this.executor_ = executor
642
665
 
643
666
  /** @private {input.FileDetector} */
644
- this.fileDetector_ = null;
667
+ this.fileDetector_ = null
645
668
 
646
669
  /** @private @const {(function(this: void): ?|undefined)} */
647
- this.onQuit_ = onQuit;
670
+ this.onQuit_ = onQuit
648
671
  }
649
672
 
650
673
  /**
@@ -673,251 +696,288 @@ class WebDriver {
673
696
  * @return {!WebDriver} The driver for the newly created session.
674
697
  */
675
698
  static createSession(executor, capabilities, onQuit = undefined) {
676
- let cmd = new command.Command(command.Name.NEW_SESSION);
699
+ let cmd = new command.Command(command.Name.NEW_SESSION)
677
700
 
678
701
  // For OSS remote ends.
679
- cmd.setParameter('desiredCapabilities', capabilities);
702
+ cmd.setParameter('desiredCapabilities', capabilities)
680
703
  // For W3C remote ends.
681
704
  cmd.setParameter('capabilities', {
682
705
  alwaysMatch: filterNonW3CCaps(capabilities),
683
- });
706
+ })
684
707
 
685
- let session = executeCommand(executor, cmd);
708
+ let session = executeCommand(executor, cmd)
686
709
  if (typeof onQuit === 'function') {
687
- session = session.catch(err => {
688
- return Promise.resolve(onQuit.call(void 0)).then(_ => {throw err;});
689
- });
710
+ session = session.catch((err) => {
711
+ return Promise.resolve(onQuit.call(void 0)).then((_) => {
712
+ throw err
713
+ })
714
+ })
690
715
  }
691
- return new this(session, executor, onQuit);
716
+ return new this(session, executor, onQuit)
692
717
  }
693
718
 
694
719
  /** @override */
695
720
  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);
721
+ command.setParameter('sessionId', this.session_)
722
+ let parameters = await toWireValue(command.getParameters())
723
+ command.setParameters(parameters)
724
+ let value = await this.executor_.execute(command)
725
+ return fromWireValue(this, value)
701
726
  }
702
727
 
703
728
  /** @override */
704
729
  setFileDetector(detector) {
705
- this.fileDetector_ = detector;
730
+ this.fileDetector_ = detector
706
731
  }
707
732
 
708
733
  /** @override */
709
734
  getExecutor() {
710
- return this.executor_;
735
+ return this.executor_
711
736
  }
712
737
 
713
738
  /** @override */
714
739
  getSession() {
715
- return this.session_;
740
+ return this.session_
716
741
  }
717
742
 
718
743
  /** @override */
719
744
  getCapabilities() {
720
- return this.session_.then(s => s.getCapabilities());
745
+ return this.session_.then((s) => s.getCapabilities())
721
746
  }
722
747
 
723
748
  /** @override */
724
749
  quit() {
725
- let result = this.execute(new command.Command(command.Name.QUIT));
750
+ let result = this.execute(new command.Command(command.Name.QUIT))
726
751
  // Delete our session ID when the quit command finishes; this will allow us
727
752
  // to throw an error when attempting to use a driver post-quit.
728
753
  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.'));
754
+ this.session_ = Promise.reject(
755
+ new error.NoSuchSessionError(
756
+ 'This driver instance does not have a valid session ID ' +
757
+ '(did you call WebDriver.quit()?) and may no longer be used.'
758
+ )
759
+ )
732
760
 
733
761
  // Only want the session rejection to bubble if accessed.
734
- this.session_.catch(function() {});
762
+ this.session_.catch(function () {})
735
763
 
736
764
  if (this.onQuit_) {
737
- return this.onQuit_.call(void 0);
765
+ return this.onQuit_.call(void 0)
738
766
  }
739
- });
767
+ })
740
768
  }
741
769
 
742
770
  /** @override */
743
771
  actions(options) {
744
- return new input.Actions(this, options || undefined);
772
+ return new input.Actions(this, options || undefined)
745
773
  }
746
774
 
747
775
  /** @override */
748
776
  executeScript(script, ...args) {
749
777
  if (typeof script === 'function') {
750
- script = 'return (' + script + ').apply(null, arguments);';
778
+ script = 'return (' + script + ').apply(null, arguments);'
751
779
  }
752
- return this.execute(
753
- new command.Command(command.Name.EXECUTE_SCRIPT).
754
- setParameter('script', script).
755
- setParameter('args', args));
780
+ return this.execute(
781
+ new command.Command(command.Name.EXECUTE_SCRIPT)
782
+ .setParameter('script', script)
783
+ .setParameter('args', args)
784
+ )
756
785
  }
757
786
 
758
787
  /** @override */
759
788
  executeAsyncScript(script, ...args) {
760
789
  if (typeof script === 'function') {
761
- script = 'return (' + script + ').apply(null, arguments);';
790
+ script = 'return (' + script + ').apply(null, arguments);'
762
791
  }
763
792
  return this.execute(
764
- new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT).
765
- setParameter('script', script).
766
- setParameter('args', args));
793
+ new command.Command(command.Name.EXECUTE_ASYNC_SCRIPT)
794
+ .setParameter('script', script)
795
+ .setParameter('args', args)
796
+ )
767
797
  }
768
798
 
769
799
  /** @override */
770
800
  wait(condition, timeout = 0, message = undefined, pollTimeout = 200) {
771
801
  if (typeof timeout !== 'number' || timeout < 0) {
772
- throw TypeError('timeout must be a number >= 0: ' + timeout);
802
+ throw TypeError('timeout must be a number >= 0: ' + timeout)
773
803
  }
774
804
 
775
805
  if (typeof pollTimeout !== 'number' || pollTimeout < 0) {
776
- throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout);
806
+ throw TypeError('pollTimeout must be a number >= 0: ' + pollTimeout)
777
807
  }
778
808
 
779
809
  if (promise.isPromise(condition)) {
780
810
  return new Promise((resolve, reject) => {
781
811
  if (!timeout) {
782
- resolve(condition);
783
- return;
812
+ resolve(condition)
813
+ return
784
814
  }
785
815
 
786
- let start = Date.now();
787
- let timer = setTimeout(function() {
788
- timer = null;
789
- reject(
816
+ let start = Date.now()
817
+ let timer = setTimeout(function () {
818
+ timer = null
819
+ try {
820
+ let timeoutMessage = resolveWaitMessage(message)
821
+ reject(
790
822
  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
- });
823
+ `${timeoutMessage}Timed out waiting for promise to resolve after ${
824
+ Date.now() - start
825
+ }ms`
826
+ )
827
+ )
828
+ } catch (ex) {
829
+ reject(
830
+ new error.TimeoutError(
831
+ `${
832
+ ex.message
833
+ }\nTimed out waiting for promise to resolve after ${
834
+ Date.now() - start
835
+ }ms`
836
+ )
837
+ )
838
+ }
839
+ }, timeout)
840
+ const clearTimer = () => timer && clearTimeout(timer)
841
+
842
+ /** @type {!IThenable} */ condition.then(
843
+ function (value) {
844
+ clearTimer()
845
+ resolve(value)
846
+ },
847
+ function (error) {
848
+ clearTimer()
849
+ reject(error)
850
+ }
851
+ )
852
+ })
807
853
  }
808
854
 
809
- let fn = /** @type {!Function} */(condition);
855
+ let fn = /** @type {!Function} */ (condition)
810
856
  if (condition instanceof Condition) {
811
- message = message || condition.description();
812
- fn = condition.fn;
857
+ message = message || condition.description()
858
+ fn = condition.fn
813
859
  }
814
860
 
815
861
  if (typeof fn !== 'function') {
816
862
  throw TypeError(
817
- 'Wait condition must be a promise-like object, function, or a '
818
- + 'Condition object');
863
+ 'Wait condition must be a promise-like object, function, or a ' +
864
+ 'Condition object'
865
+ )
819
866
  }
820
867
 
821
- const driver = this;
868
+ const driver = this
822
869
  function evaluateCondition() {
823
870
  return new Promise((resolve, reject) => {
824
871
  try {
825
- resolve(fn(driver));
872
+ resolve(fn(driver))
826
873
  } catch (ex) {
827
- reject(ex);
874
+ reject(ex)
828
875
  }
829
- });
876
+ })
830
877
  }
831
878
 
832
879
  let result = new Promise((resolve, reject) => {
833
- const startTime = Date.now();
880
+ const startTime = Date.now()
834
881
  const pollCondition = async () => {
835
- evaluateCondition().then(function(value) {
836
- const elapsed = Date.now() - startTime;
837
- if (!!value) {
838
- resolve(value);
882
+ evaluateCondition().then(function (value) {
883
+ const elapsed = Date.now() - startTime
884
+ if (value) {
885
+ resolve(value)
839
886
  } else if (timeout && elapsed >= timeout) {
840
- reject(
887
+ try {
888
+ let timeoutMessage = resolveWaitMessage(message)
889
+ reject(
890
+ new error.TimeoutError(
891
+ `${timeoutMessage}Wait timed out after ${elapsed}ms`
892
+ )
893
+ )
894
+ } catch (ex) {
895
+ reject(
841
896
  new error.TimeoutError(
842
- (message ? `${message}\n` : '')
843
- + `Wait timed out after ${elapsed}ms`));
897
+ `${ex.message}\nWait timed out after ${elapsed}ms`
898
+ )
899
+ )
900
+ }
844
901
  } else {
845
- setTimeout(pollCondition, pollTimeout);
902
+ setTimeout(pollCondition, pollTimeout)
846
903
  }
847
- }, reject);
848
- };
849
- pollCondition();
850
- });
904
+ }, reject)
905
+ }
906
+ pollCondition()
907
+ })
851
908
 
852
909
  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
- }));
910
+ result = new WebElementPromise(
911
+ this,
912
+ result.then(function (value) {
913
+ if (!(value instanceof WebElement)) {
914
+ throw TypeError(
915
+ 'WebElementCondition did not resolve to a WebElement: ' +
916
+ Object.prototype.toString.call(value)
917
+ )
918
+ }
919
+ return value
920
+ })
921
+ )
861
922
  }
862
- return result;
923
+ return result
863
924
  }
864
925
 
865
926
  /** @override */
866
927
  sleep(ms) {
867
- return new Promise(resolve => setTimeout(() => resolve(), ms));
928
+ return new Promise((resolve) => setTimeout(() => resolve(), ms))
868
929
  }
869
930
 
870
931
  /** @override */
871
932
  getWindowHandle() {
872
933
  return this.execute(
873
- new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE));
934
+ new command.Command(command.Name.GET_CURRENT_WINDOW_HANDLE)
935
+ )
874
936
  }
875
937
 
876
938
  /** @override */
877
939
  getAllWindowHandles() {
878
- return this.execute(
879
- new command.Command(command.Name.GET_WINDOW_HANDLES));
940
+ return this.execute(new command.Command(command.Name.GET_WINDOW_HANDLES))
880
941
  }
881
942
 
882
943
  /** @override */
883
944
  getPageSource() {
884
- return this.execute(
885
- new command.Command(command.Name.GET_PAGE_SOURCE));
945
+ return this.execute(new command.Command(command.Name.GET_PAGE_SOURCE))
886
946
  }
887
947
 
888
948
  /** @override */
889
949
  close() {
890
- return this.execute(new command.Command(command.Name.CLOSE));
950
+ return this.execute(new command.Command(command.Name.CLOSE))
891
951
  }
892
952
 
893
953
  /** @override */
894
954
  get(url) {
895
- return this.navigate().to(url);
955
+ return this.navigate().to(url)
896
956
  }
897
957
 
898
958
  /** @override */
899
959
  getCurrentUrl() {
900
- return this.execute(new command.Command(command.Name.GET_CURRENT_URL));
960
+ return this.execute(new command.Command(command.Name.GET_CURRENT_URL))
901
961
  }
902
962
 
903
963
  /** @override */
904
964
  getTitle() {
905
- return this.execute(new command.Command(command.Name.GET_TITLE));
965
+ return this.execute(new command.Command(command.Name.GET_TITLE))
906
966
  }
907
967
 
908
968
  /** @override */
909
969
  findElement(locator) {
910
- let id;
911
- locator = by.checkedLocator(locator);
970
+ let id
971
+ locator = by.checkedLocator(locator)
912
972
  if (typeof locator === 'function') {
913
- id = this.findElementInternal_(locator, this);
973
+ id = this.findElementInternal_(locator, this)
914
974
  } 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);
975
+ let cmd = new command.Command(command.Name.FIND_ELEMENT)
976
+ .setParameter('using', locator.using)
977
+ .setParameter('value', locator.value)
978
+ id = this.execute(cmd)
919
979
  }
920
- return new WebElementPromise(this, id);
980
+ return new WebElementPromise(this, id)
921
981
  }
922
982
 
923
983
  /**
@@ -928,34 +988,42 @@ class WebDriver {
928
988
  * @private
929
989
  */
930
990
  async findElementInternal_(locatorFn, context) {
931
- let result = await locatorFn(context);
991
+ let result = await locatorFn(context)
932
992
  if (Array.isArray(result)) {
933
- result = result[0];
993
+ result = result[0]
934
994
  }
935
995
  if (!(result instanceof WebElement)) {
936
- throw new TypeError('Custom locator did not return a WebElement');
996
+ throw new TypeError('Custom locator did not return a WebElement')
937
997
  }
938
- return result;
998
+ return result
939
999
  }
940
1000
 
941
1001
  /** @override */
942
1002
  async findElements(locator) {
943
- locator = by.checkedLocator(locator);
944
- if (typeof locator === 'function') {
945
- return this.findElementsInternal_(locator, this);
1003
+ let cmd = null
1004
+ if (locator instanceof RelativeBy) {
1005
+ cmd = new command.Command(
1006
+ command.Name.FIND_ELEMENTS_RELATIVE
1007
+ ).setParameter('args', locator.marshall())
946
1008
  } 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;
1009
+ locator = by.checkedLocator(locator)
1010
+ }
1011
+
1012
+ if (typeof locator === 'function') {
1013
+ return this.findElementsInternal_(locator, this)
1014
+ } else if (cmd === null) {
1015
+ cmd = new command.Command(command.Name.FIND_ELEMENTS)
1016
+ .setParameter('using', locator.using)
1017
+ .setParameter('value', locator.value)
1018
+ }
1019
+ try {
1020
+ let res = await this.execute(cmd)
1021
+ return Array.isArray(res) ? res : []
1022
+ } catch (ex) {
1023
+ if (ex instanceof error.NoSuchElementError) {
1024
+ return []
958
1025
  }
1026
+ throw ex
959
1027
  }
960
1028
  }
961
1029
 
@@ -967,41 +1035,122 @@ class WebDriver {
967
1035
  * @private
968
1036
  */
969
1037
  async findElementsInternal_(locatorFn, context) {
970
- const result = await locatorFn(context);
1038
+ const result = await locatorFn(context)
971
1039
  if (result instanceof WebElement) {
972
- return [result];
1040
+ return [result]
973
1041
  }
974
1042
 
975
1043
  if (!Array.isArray(result)) {
976
- return [];
1044
+ return []
977
1045
  }
978
1046
 
979
- return result.filter(function(item) {
980
- return item instanceof WebElement;
981
- });
1047
+ return result.filter(function (item) {
1048
+ return item instanceof WebElement
1049
+ })
982
1050
  }
983
1051
 
984
1052
  /** @override */
985
1053
  takeScreenshot() {
986
- return this.execute(new command.Command(command.Name.SCREENSHOT));
1054
+ return this.execute(new command.Command(command.Name.SCREENSHOT))
987
1055
  }
988
1056
 
989
1057
  /** @override */
990
1058
  manage() {
991
- return new Options(this);
1059
+ return new Options(this)
992
1060
  }
993
1061
 
994
1062
  /** @override */
995
1063
  navigate() {
996
- return new Navigation(this);
1064
+ return new Navigation(this)
997
1065
  }
998
1066
 
999
1067
  /** @override */
1000
1068
  switchTo() {
1001
- return new TargetLocator(this);
1069
+ return new TargetLocator(this)
1070
+ }
1071
+
1072
+ validatePrintPageParams(keys, object) {
1073
+ let page = {}
1074
+ let margin = {}
1075
+ let data
1076
+ Object.keys(keys).forEach(function (key) {
1077
+ data = keys[key]
1078
+ let obj = {
1079
+ orientation: function () {
1080
+ object.orientation = data
1081
+ },
1082
+
1083
+ scale: function () {
1084
+ object.scale = data
1085
+ },
1086
+
1087
+ background: function () {
1088
+ object.background = data
1089
+ },
1090
+
1091
+ width: function () {
1092
+ page.width = data
1093
+ object.page = page
1094
+ },
1095
+
1096
+ height: function () {
1097
+ page.height = data
1098
+ object.page = page
1099
+ },
1100
+
1101
+ top: function () {
1102
+ margin.top = data
1103
+ object.margin = margin
1104
+ },
1105
+
1106
+ left: function () {
1107
+ margin.left = data
1108
+ object.margin = margin
1109
+ },
1110
+
1111
+ bottom: function () {
1112
+ margin.bottom = data
1113
+ object.margin = margin
1114
+ },
1115
+
1116
+ right: function () {
1117
+ margin.right = data
1118
+ object.margin = margin
1119
+ },
1120
+
1121
+ shrinkToFit: function () {
1122
+ object.shrinkToFit = data
1123
+ },
1124
+
1125
+ pageRanges: function () {
1126
+ object.pageRanges = data
1127
+ },
1128
+ }
1129
+
1130
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
1131
+ throw new error.InvalidArgumentError(`Invalid Argument '${key}'`)
1132
+ } else {
1133
+ obj[key]()
1134
+ }
1135
+ })
1136
+
1137
+ return object
1002
1138
  }
1003
- }
1004
1139
 
1140
+ /** @override */
1141
+ printPage(options = {}) {
1142
+ let keys = options
1143
+ let params = {}
1144
+ let resultObj
1145
+
1146
+ let self = this
1147
+ resultObj = self.validatePrintPageParams(keys, params)
1148
+
1149
+ return this.execute(
1150
+ new command.Command(command.Name.PRINT_PAGE).setParameters(resultObj)
1151
+ )
1152
+ }
1153
+ }
1005
1154
 
1006
1155
  /**
1007
1156
  * Interface for navigating back and forth in the browser history.
@@ -1020,7 +1169,7 @@ class Navigation {
1020
1169
  */
1021
1170
  constructor(driver) {
1022
1171
  /** @private {!WebDriver} */
1023
- this.driver_ = driver;
1172
+ this.driver_ = driver
1024
1173
  }
1025
1174
 
1026
1175
  /**
@@ -1032,8 +1181,8 @@ class Navigation {
1032
1181
  */
1033
1182
  to(url) {
1034
1183
  return this.driver_.execute(
1035
- new command.Command(command.Name.GET).
1036
- setParameter('url', url));
1184
+ new command.Command(command.Name.GET).setParameter('url', url)
1185
+ )
1037
1186
  }
1038
1187
 
1039
1188
  /**
@@ -1043,7 +1192,7 @@ class Navigation {
1043
1192
  * navigation event has completed.
1044
1193
  */
1045
1194
  back() {
1046
- return this.driver_.execute(new command.Command(command.Name.GO_BACK));
1195
+ return this.driver_.execute(new command.Command(command.Name.GO_BACK))
1047
1196
  }
1048
1197
 
1049
1198
  /**
@@ -1053,7 +1202,7 @@ class Navigation {
1053
1202
  * navigation event has completed.
1054
1203
  */
1055
1204
  forward() {
1056
- return this.driver_.execute(new command.Command(command.Name.GO_FORWARD));
1205
+ return this.driver_.execute(new command.Command(command.Name.GO_FORWARD))
1057
1206
  }
1058
1207
 
1059
1208
  /**
@@ -1063,11 +1212,10 @@ class Navigation {
1063
1212
  * navigation event has completed.
1064
1213
  */
1065
1214
  refresh() {
1066
- return this.driver_.execute(new command.Command(command.Name.REFRESH));
1215
+ return this.driver_.execute(new command.Command(command.Name.REFRESH))
1067
1216
  }
1068
1217
  }
1069
1218
 
1070
-
1071
1219
  /**
1072
1220
  * Provides methods for managing browser and driver state.
1073
1221
  *
@@ -1081,7 +1229,7 @@ class Options {
1081
1229
  */
1082
1230
  constructor(driver) {
1083
1231
  /** @private {!WebDriver} */
1084
- this.driver_ = driver;
1232
+ this.driver_ = driver
1085
1233
  }
1086
1234
 
1087
1235
  /**
@@ -1110,37 +1258,50 @@ class Options {
1110
1258
  * invalid.
1111
1259
  * @throws {TypeError} if `spec` is not a cookie object.
1112
1260
  */
1113
- addCookie({name, value, path, domain, secure, httpOnly, expiry}) {
1261
+ addCookie({ name, value, path, domain, secure, httpOnly, expiry, sameSite }) {
1114
1262
  // We do not allow '=' or ';' in the name.
1115
1263
  if (/[;=]/.test(name)) {
1116
- throw new error.InvalidArgumentError(
1117
- 'Invalid cookie name "' + name + '"');
1264
+ throw new error.InvalidArgumentError('Invalid cookie name "' + name + '"')
1118
1265
  }
1119
1266
 
1120
1267
  // We do not allow ';' in value.
1121
1268
  if (/;/.test(value)) {
1122
1269
  throw new error.InvalidArgumentError(
1123
- 'Invalid cookie value "' + value + '"');
1270
+ 'Invalid cookie value "' + value + '"'
1271
+ )
1124
1272
  }
1125
1273
 
1126
1274
  if (typeof expiry === 'number') {
1127
- expiry = Math.floor(expiry);
1275
+ expiry = Math.floor(expiry)
1128
1276
  } else if (expiry instanceof Date) {
1129
- let date = /** @type {!Date} */(expiry);
1130
- expiry = Math.floor(date.getTime() / 1000);
1277
+ let date = /** @type {!Date} */ (expiry)
1278
+ expiry = Math.floor(date.getTime() / 1000)
1279
+ }
1280
+
1281
+ if (sameSite && !['Strict', 'Lax', 'None'].includes(sameSite)) {
1282
+ throw new error.InvalidArgumentError(
1283
+ `Invalid sameSite cookie value '${sameSite}'. It should be one of "Lax", "Strict" or "None"`
1284
+ )
1285
+ }
1286
+
1287
+ if (sameSite === 'None' && !secure) {
1288
+ throw new error.InvalidArgumentError(
1289
+ 'Invalid cookie configuration: SameSite=None must be Secure'
1290
+ )
1131
1291
  }
1132
1292
 
1133
1293
  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
- }));
1294
+ new command.Command(command.Name.ADD_COOKIE).setParameter('cookie', {
1295
+ name: name,
1296
+ value: value,
1297
+ path: path,
1298
+ domain: domain,
1299
+ secure: !!secure,
1300
+ httpOnly: !!httpOnly,
1301
+ expiry: expiry,
1302
+ sameSite: sameSite,
1303
+ })
1304
+ )
1144
1305
  }
1145
1306
 
1146
1307
  /**
@@ -1151,7 +1312,8 @@ class Options {
1151
1312
  */
1152
1313
  deleteAllCookies() {
1153
1314
  return this.driver_.execute(
1154
- new command.Command(command.Name.DELETE_ALL_COOKIES));
1315
+ new command.Command(command.Name.DELETE_ALL_COOKIES)
1316
+ )
1155
1317
  }
1156
1318
 
1157
1319
  /**
@@ -1164,8 +1326,8 @@ class Options {
1164
1326
  */
1165
1327
  deleteCookie(name) {
1166
1328
  return this.driver_.execute(
1167
- new command.Command(command.Name.DELETE_COOKIE).
1168
- setParameter('name', name));
1329
+ new command.Command(command.Name.DELETE_COOKIE).setParameter('name', name)
1330
+ )
1169
1331
  }
1170
1332
 
1171
1333
  /**
@@ -1177,7 +1339,8 @@ class Options {
1177
1339
  */
1178
1340
  getCookies() {
1179
1341
  return this.driver_.execute(
1180
- new command.Command(command.Name.GET_ALL_COOKIES));
1342
+ new command.Command(command.Name.GET_ALL_COOKIES)
1343
+ )
1181
1344
  }
1182
1345
 
1183
1346
  /**
@@ -1187,28 +1350,30 @@ class Options {
1187
1350
  *
1188
1351
  * @param {string} name The name of the cookie to retrieve.
1189
1352
  * @return {!Promise<?Options.Cookie>} A promise that will be resolved
1190
- * with the named cookie, or `null` if there is no such cookie.
1353
+ * with the named cookie
1354
+ * @throws {error.NoSuchCookieError} if there is no such cookie.
1191
1355
  */
1192
1356
  async getCookie(name) {
1193
1357
  try {
1194
- const cookie =
1195
- await this.driver_.execute(
1196
- new command.Command(command.Name.GET_COOKIE)
1197
- .setParameter('name', name));
1198
- return cookie;
1358
+ const cookie = await this.driver_.execute(
1359
+ new command.Command(command.Name.GET_COOKIE).setParameter('name', name)
1360
+ )
1361
+ return cookie
1199
1362
  } catch (err) {
1200
- if (!(err instanceof error.UnknownCommandError)
1201
- && !(err instanceof error.UnsupportedOperationError)) {
1202
- throw err;
1363
+ if (
1364
+ !(err instanceof error.UnknownCommandError) &&
1365
+ !(err instanceof error.UnsupportedOperationError)
1366
+ ) {
1367
+ throw err
1203
1368
  }
1204
1369
 
1205
- const cookies = await this.getCookies();
1370
+ const cookies = await this.getCookies()
1206
1371
  for (let cookie of cookies) {
1207
1372
  if (cookie && cookie['name'] === name) {
1208
- return cookie;
1373
+ return cookie
1209
1374
  }
1210
1375
  }
1211
- return null;
1376
+ return null
1212
1377
  }
1213
1378
  }
1214
1379
 
@@ -1223,7 +1388,7 @@ class Options {
1223
1388
  * @see #setTimeouts()
1224
1389
  */
1225
1390
  getTimeouts() {
1226
- return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT));
1391
+ return this.driver_.execute(new command.Command(command.Name.GET_TIMEOUT))
1227
1392
  }
1228
1393
 
1229
1394
  /**
@@ -1255,60 +1420,59 @@ class Options {
1255
1420
  * @see #getTimeouts()
1256
1421
  * @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
1257
1422
  */
1258
- setTimeouts({script, pageLoad, implicit} = {}) {
1259
- let cmd = new command.Command(command.Name.SET_TIMEOUT);
1423
+ setTimeouts({ script, pageLoad, implicit } = {}) {
1424
+ let cmd = new command.Command(command.Name.SET_TIMEOUT)
1260
1425
 
1261
- let valid = false;
1426
+ let valid = false
1262
1427
  function setParam(key, value) {
1263
1428
  if (value === null || typeof value === 'number') {
1264
- valid = true;
1265
- cmd.setParameter(key, value);
1429
+ valid = true
1430
+ cmd.setParameter(key, value)
1266
1431
  } else if (typeof value !== 'undefined') {
1267
1432
  throw TypeError(
1268
- 'invalid timeouts configuration:'
1269
- + ` expected "${key}" to be a number, got ${typeof value}`);
1433
+ 'invalid timeouts configuration:' +
1434
+ ` expected "${key}" to be a number, got ${typeof value}`
1435
+ )
1270
1436
  }
1271
1437
  }
1272
- setParam('implicit', implicit);
1273
- setParam('pageLoad', pageLoad);
1274
- setParam('script', script);
1438
+ setParam('implicit', implicit)
1439
+ setParam('pageLoad', pageLoad)
1440
+ setParam('script', script)
1275
1441
 
1276
1442
  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
- });
1443
+ return this.driver_.execute(cmd).catch(() => {
1444
+ // Fallback to the legacy method.
1445
+ let cmds = []
1446
+ if (typeof script === 'number') {
1447
+ cmds.push(legacyTimeout(this.driver_, 'script', script))
1448
+ }
1449
+ if (typeof implicit === 'number') {
1450
+ cmds.push(legacyTimeout(this.driver_, 'implicit', implicit))
1451
+ }
1452
+ if (typeof pageLoad === 'number') {
1453
+ cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad))
1454
+ }
1455
+ return Promise.all(cmds)
1456
+ })
1292
1457
  }
1293
- throw TypeError('no timeouts specified');
1458
+ throw TypeError('no timeouts specified')
1294
1459
  }
1295
1460
 
1296
1461
  /**
1297
1462
  * @return {!Logs} The interface for managing driver logs.
1298
1463
  */
1299
1464
  logs() {
1300
- return new Logs(this.driver_);
1465
+ return new Logs(this.driver_)
1301
1466
  }
1302
1467
 
1303
1468
  /**
1304
1469
  * @return {!Window} The interface for managing the current window.
1305
1470
  */
1306
1471
  window() {
1307
- return new Window(this.driver_);
1472
+ return new Window(this.driver_)
1308
1473
  }
1309
1474
  }
1310
1475
 
1311
-
1312
1476
  /**
1313
1477
  * @param {!WebDriver} driver
1314
1478
  * @param {string} type
@@ -1317,44 +1481,39 @@ class Options {
1317
1481
  */
1318
1482
  function legacyTimeout(driver, type, ms) {
1319
1483
  return driver.execute(
1320
- new command.Command(command.Name.SET_TIMEOUT)
1321
- .setParameter('type', type)
1322
- .setParameter('ms', ms));
1484
+ new command.Command(command.Name.SET_TIMEOUT)
1485
+ .setParameter('type', type)
1486
+ .setParameter('ms', ms)
1487
+ )
1323
1488
  }
1324
1489
 
1325
-
1326
-
1327
1490
  /**
1328
1491
  * A record object describing a browser cookie.
1329
1492
  *
1330
1493
  * @record
1331
1494
  */
1332
- Options.Cookie = function() {};
1333
-
1495
+ Options.Cookie = function () {}
1334
1496
 
1335
1497
  /**
1336
1498
  * The name of the cookie.
1337
1499
  *
1338
1500
  * @type {string}
1339
1501
  */
1340
- Options.Cookie.prototype.name;
1341
-
1502
+ Options.Cookie.prototype.name
1342
1503
 
1343
1504
  /**
1344
1505
  * The cookie value.
1345
1506
  *
1346
1507
  * @type {string}
1347
1508
  */
1348
- Options.Cookie.prototype.value;
1349
-
1509
+ Options.Cookie.prototype.value
1350
1510
 
1351
1511
  /**
1352
1512
  * The cookie path. Defaults to "/" when adding a cookie.
1353
1513
  *
1354
1514
  * @type {(string|undefined)}
1355
1515
  */
1356
- Options.Cookie.prototype.path;
1357
-
1516
+ Options.Cookie.prototype.path
1358
1517
 
1359
1518
  /**
1360
1519
  * The domain the cookie is visible to. Defaults to the current browsing
@@ -1362,8 +1521,7 @@ Options.Cookie.prototype.path;
1362
1521
  *
1363
1522
  * @type {(string|undefined)}
1364
1523
  */
1365
- Options.Cookie.prototype.domain;
1366
-
1524
+ Options.Cookie.prototype.domain
1367
1525
 
1368
1526
  /**
1369
1527
  * Whether the cookie is a secure cookie. Defaults to false when adding a new
@@ -1371,8 +1529,7 @@ Options.Cookie.prototype.domain;
1371
1529
  *
1372
1530
  * @type {(boolean|undefined)}
1373
1531
  */
1374
- Options.Cookie.prototype.secure;
1375
-
1532
+ Options.Cookie.prototype.secure
1376
1533
 
1377
1534
  /**
1378
1535
  * Whether the cookie is an HTTP only cookie. Defaults to false when adding a
@@ -1380,8 +1537,7 @@ Options.Cookie.prototype.secure;
1380
1537
  *
1381
1538
  * @type {(boolean|undefined)}
1382
1539
  */
1383
- Options.Cookie.prototype.httpOnly;
1384
-
1540
+ Options.Cookie.prototype.httpOnly
1385
1541
 
1386
1542
  /**
1387
1543
  * When the cookie expires.
@@ -1394,8 +1550,18 @@ Options.Cookie.prototype.httpOnly;
1394
1550
  *
1395
1551
  * @type {(!Date|number|undefined)}
1396
1552
  */
1397
- Options.Cookie.prototype.expiry;
1553
+ Options.Cookie.prototype.expiry
1398
1554
 
1555
+ /**
1556
+ * When the cookie applies to a SameSite policy.
1557
+ *
1558
+ * When {@linkplain Options#addCookie() adding a cookie}, this may be specified
1559
+ * as a {@link string} object which is one of 'Lax', 'Strict' or 'None'.
1560
+ *
1561
+ *
1562
+ * @type {(string|undefined)}
1563
+ */
1564
+ Options.Cookie.prototype.sameSite
1399
1565
 
1400
1566
  /**
1401
1567
  * An interface for managing the current window.
@@ -1415,7 +1581,7 @@ class Window {
1415
1581
  */
1416
1582
  constructor(driver) {
1417
1583
  /** @private {!WebDriver} */
1418
- this.driver_ = driver;
1584
+ this.driver_ = driver
1419
1585
  }
1420
1586
 
1421
1587
  /**
@@ -1428,20 +1594,25 @@ class Window {
1428
1594
  async getRect() {
1429
1595
  try {
1430
1596
  return await this.driver_.execute(
1431
- new command.Command(command.Name.GET_WINDOW_RECT));
1597
+ new command.Command(command.Name.GET_WINDOW_RECT)
1598
+ )
1432
1599
  } catch (ex) {
1433
1600
  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};
1601
+ let { width, height } = await this.driver_.execute(
1602
+ new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
1603
+ 'windowHandle',
1604
+ 'current'
1605
+ )
1606
+ )
1607
+ let { x, y } = await this.driver_.execute(
1608
+ new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
1609
+ 'windowHandle',
1610
+ 'current'
1611
+ )
1612
+ )
1613
+ return { x, y, width, height }
1443
1614
  }
1444
- throw ex;
1615
+ throw ex
1445
1616
  }
1446
1617
  }
1447
1618
 
@@ -1456,34 +1627,41 @@ class Window {
1456
1627
  * height: (number|undefined)}} options
1457
1628
  * The desired window size and position.
1458
1629
  * @return {!Promise<{x: number, y: number, width: number, height: number}>}
1459
- * A promise that will resolve to the current widnow's updated window
1630
+ * A promise that will resolve to the current window's updated window
1460
1631
  * rect.
1461
1632
  */
1462
- async setRect({x, y, width, height}) {
1633
+ async setRect({ x, y, width, height }) {
1463
1634
  try {
1464
1635
  return await this.driver_.execute(
1465
- new command.Command(command.Name.SET_WINDOW_RECT)
1466
- .setParameters({x, y, width, height}));
1636
+ new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
1637
+ x,
1638
+ y,
1639
+ width,
1640
+ height,
1641
+ })
1642
+ )
1467
1643
  } catch (ex) {
1468
1644
  if (ex instanceof error.UnknownCommandError) {
1469
1645
  if (typeof x === 'number' && typeof y === 'number') {
1470
1646
  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));
1647
+ new command.Command(command.Name.SET_WINDOW_POSITION)
1648
+ .setParameter('windowHandle', 'current')
1649
+ .setParameter('x', x)
1650
+ .setParameter('y', y)
1651
+ )
1475
1652
  }
1476
1653
 
1477
- if (typeof width === 'number' && typeof height === 'number') {
1654
+ if (typeof width === 'number' && typeof height === 'number') {
1478
1655
  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));
1656
+ new command.Command(command.Name.SET_WINDOW_SIZE)
1657
+ .setParameter('windowHandle', 'current')
1658
+ .setParameter('width', width)
1659
+ .setParameter('height', height)
1660
+ )
1483
1661
  }
1484
- return this.getRect();
1662
+ return this.getRect()
1485
1663
  }
1486
- throw ex;
1664
+ throw ex
1487
1665
  }
1488
1666
  }
1489
1667
 
@@ -1497,13 +1675,16 @@ class Window {
1497
1675
  */
1498
1676
  maximize() {
1499
1677
  return this.driver_.execute(
1500
- new command.Command(command.Name.MAXIMIZE_WINDOW).
1501
- setParameter('windowHandle', 'current'));
1678
+ new command.Command(command.Name.MAXIMIZE_WINDOW).setParameter(
1679
+ 'windowHandle',
1680
+ 'current'
1681
+ )
1682
+ )
1502
1683
  }
1503
1684
 
1504
1685
  /**
1505
1686
  * Minimizes the current window. The exact behavior of this command is
1506
- * specific to individual window managers, but typicallly involves hiding
1687
+ * specific to individual window managers, but typically involves hiding
1507
1688
  * the window in the system tray.
1508
1689
  *
1509
1690
  * @return {!Promise<void>} A promise that will be resolved when the command
@@ -1511,7 +1692,8 @@ class Window {
1511
1692
  */
1512
1693
  minimize() {
1513
1694
  return this.driver_.execute(
1514
- new command.Command(command.Name.MINIMIZE_WINDOW));
1695
+ new command.Command(command.Name.MINIMIZE_WINDOW)
1696
+ )
1515
1697
  }
1516
1698
 
1517
1699
  /**
@@ -1526,11 +1708,11 @@ class Window {
1526
1708
  */
1527
1709
  fullscreen() {
1528
1710
  return this.driver_.execute(
1529
- new command.Command(command.Name.FULLSCREEN_WINDOW));
1711
+ new command.Command(command.Name.FULLSCREEN_WINDOW)
1712
+ )
1530
1713
  }
1531
1714
  }
1532
1715
 
1533
-
1534
1716
  /**
1535
1717
  * Interface for managing WebDriver log records.
1536
1718
  *
@@ -1549,7 +1731,7 @@ class Logs {
1549
1731
  */
1550
1732
  constructor(driver) {
1551
1733
  /** @private {!WebDriver} */
1552
- this.driver_ = driver;
1734
+ this.driver_ = driver
1553
1735
  }
1554
1736
 
1555
1737
  /**
@@ -1566,19 +1748,23 @@ class Logs {
1566
1748
  * type.
1567
1749
  */
1568
1750
  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
- });
1751
+ let cmd = new command.Command(command.Name.GET_LOG).setParameter(
1752
+ 'type',
1753
+ type
1754
+ )
1755
+ return this.driver_.execute(cmd).then(function (entries) {
1756
+ return entries.map(function (entry) {
1757
+ if (!(entry instanceof logging.Entry)) {
1758
+ return new logging.Entry(
1759
+ entry['level'],
1760
+ entry['message'],
1761
+ entry['timestamp'],
1762
+ entry['type']
1763
+ )
1764
+ }
1765
+ return entry
1766
+ })
1767
+ })
1582
1768
  }
1583
1769
 
1584
1770
  /**
@@ -1588,11 +1774,11 @@ class Logs {
1588
1774
  */
1589
1775
  getAvailableLogTypes() {
1590
1776
  return this.driver_.execute(
1591
- new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES));
1777
+ new command.Command(command.Name.GET_AVAILABLE_LOG_TYPES)
1778
+ )
1592
1779
  }
1593
1780
  }
1594
1781
 
1595
-
1596
1782
  /**
1597
1783
  * An interface for changing the focus of the driver to another frame or window.
1598
1784
  *
@@ -1610,7 +1796,7 @@ class TargetLocator {
1610
1796
  */
1611
1797
  constructor(driver) {
1612
1798
  /** @private {!WebDriver} */
1613
- this.driver_ = driver;
1799
+ this.driver_ = driver
1614
1800
  }
1615
1801
 
1616
1802
  /**
@@ -1622,8 +1808,9 @@ class TargetLocator {
1622
1808
  */
1623
1809
  activeElement() {
1624
1810
  var id = this.driver_.execute(
1625
- new command.Command(command.Name.GET_ACTIVE_ELEMENT));
1626
- return new WebElementPromise(this.driver_, id);
1811
+ new command.Command(command.Name.GET_ACTIVE_ELEMENT)
1812
+ )
1813
+ return new WebElementPromise(this.driver_, id)
1627
1814
  }
1628
1815
 
1629
1816
  /**
@@ -1635,8 +1822,8 @@ class TargetLocator {
1635
1822
  */
1636
1823
  defaultContent() {
1637
1824
  return this.driver_.execute(
1638
- new command.Command(command.Name.SWITCH_TO_FRAME).
1639
- setParameter('id', null));
1825
+ new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', null)
1826
+ )
1640
1827
  }
1641
1828
 
1642
1829
  /**
@@ -1659,8 +1846,8 @@ class TargetLocator {
1659
1846
  */
1660
1847
  frame(id) {
1661
1848
  return this.driver_.execute(
1662
- new command.Command(command.Name.SWITCH_TO_FRAME).
1663
- setParameter('id', id));
1849
+ new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', id)
1850
+ )
1664
1851
  }
1665
1852
 
1666
1853
  /**
@@ -1673,7 +1860,8 @@ class TargetLocator {
1673
1860
  */
1674
1861
  parentFrame() {
1675
1862
  return this.driver_.execute(
1676
- new command.Command(command.Name.SWITCH_TO_FRAME_PARENT));
1863
+ new command.Command(command.Name.SWITCH_TO_FRAME_PARENT)
1864
+ )
1677
1865
  }
1678
1866
 
1679
1867
  /**
@@ -1691,11 +1879,12 @@ class TargetLocator {
1691
1879
  */
1692
1880
  window(nameOrHandle) {
1693
1881
  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));
1882
+ new command.Command(command.Name.SWITCH_TO_WINDOW)
1883
+ // "name" supports the legacy drivers. "handle" is the W3C
1884
+ // compliant parameter.
1885
+ .setParameter('name', nameOrHandle)
1886
+ .setParameter('handle', nameOrHandle)
1887
+ )
1699
1888
  }
1700
1889
 
1701
1890
  /**
@@ -1711,12 +1900,16 @@ class TargetLocator {
1711
1900
  */
1712
1901
  newWindow(typeHint) {
1713
1902
  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
- });
1903
+ return this.driver_
1904
+ .execute(
1905
+ new command.Command(command.Name.SWITCH_TO_NEW_WINDOW).setParameter(
1906
+ 'type',
1907
+ typeHint
1908
+ )
1909
+ )
1910
+ .then(function (response) {
1911
+ return driver.switchTo().window(response.handle)
1912
+ })
1720
1913
  }
1721
1914
 
1722
1915
  /**
@@ -1729,25 +1922,26 @@ class TargetLocator {
1729
1922
  */
1730
1923
  alert() {
1731
1924
  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
- }));
1925
+ new command.Command(command.Name.GET_ALERT_TEXT)
1926
+ )
1927
+ var driver = this.driver_
1928
+ return new AlertPromise(
1929
+ driver,
1930
+ text.then(function (text) {
1931
+ return new Alert(driver, text)
1932
+ })
1933
+ )
1737
1934
  }
1738
1935
  }
1739
1936
 
1740
-
1741
1937
  //////////////////////////////////////////////////////////////////////////////
1742
1938
  //
1743
1939
  // WebElement
1744
1940
  //
1745
1941
  //////////////////////////////////////////////////////////////////////////////
1746
1942
 
1747
-
1748
- const LEGACY_ELEMENT_ID_KEY = 'ELEMENT';
1749
- const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf';
1750
-
1943
+ const LEGACY_ELEMENT_ID_KEY = 'ELEMENT'
1944
+ const ELEMENT_ID_KEY = 'element-6066-11e4-a52e-4f735466cecf'
1751
1945
 
1752
1946
  /**
1753
1947
  * Represents a DOM element. WebElements can be found by searching from the
@@ -1767,10 +1961,10 @@ class WebElement {
1767
1961
  */
1768
1962
  constructor(driver, id) {
1769
1963
  /** @private {!WebDriver} */
1770
- this.driver_ = driver;
1964
+ this.driver_ = driver
1771
1965
 
1772
1966
  /** @private {!Promise<string>} */
1773
- this.id_ = Promise.resolve(id);
1967
+ this.id_ = Promise.resolve(id)
1774
1968
  }
1775
1969
 
1776
1970
  /**
@@ -1780,8 +1974,8 @@ class WebElement {
1780
1974
  */
1781
1975
  static buildId(id, noLegacy = false) {
1782
1976
  return noLegacy
1783
- ? {[ELEMENT_ID_KEY]: id}
1784
- : {[ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id};
1977
+ ? { [ELEMENT_ID_KEY]: id }
1978
+ : { [ELEMENT_ID_KEY]: id, [LEGACY_ELEMENT_ID_KEY]: id }
1785
1979
  }
1786
1980
 
1787
1981
  /**
@@ -1794,12 +1988,12 @@ class WebElement {
1794
1988
  static extractId(obj) {
1795
1989
  if (obj && typeof obj === 'object') {
1796
1990
  if (typeof obj[ELEMENT_ID_KEY] === 'string') {
1797
- return obj[ELEMENT_ID_KEY];
1991
+ return obj[ELEMENT_ID_KEY]
1798
1992
  } else if (typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string') {
1799
- return obj[LEGACY_ELEMENT_ID_KEY];
1993
+ return obj[LEGACY_ELEMENT_ID_KEY]
1800
1994
  }
1801
1995
  }
1802
- throw new TypeError('object is not a WebElement ID');
1996
+ throw new TypeError('object is not a WebElement ID')
1803
1997
  }
1804
1998
 
1805
1999
  /**
@@ -1807,9 +2001,12 @@ class WebElement {
1807
2001
  * @return {boolean} whether the object is a valid encoded WebElement ID.
1808
2002
  */
1809
2003
  static isId(obj) {
1810
- return obj && typeof obj === 'object'
1811
- && (typeof obj[ELEMENT_ID_KEY] === 'string'
1812
- || typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string');
2004
+ return (
2005
+ obj &&
2006
+ typeof obj === 'object' &&
2007
+ (typeof obj[ELEMENT_ID_KEY] === 'string' ||
2008
+ typeof obj[LEGACY_ELEMENT_ID_KEY] === 'string')
2009
+ )
1813
2010
  }
1814
2011
 
1815
2012
  /**
@@ -1822,15 +2019,14 @@ class WebElement {
1822
2019
  */
1823
2020
  static async equals(a, b) {
1824
2021
  if (a === b) {
1825
- return true;
2022
+ return true
1826
2023
  }
1827
- return a.driver_.executeScript(
1828
- 'return arguments[0] === arguments[1]', a, b);
2024
+ return a.driver_.executeScript('return arguments[0] === arguments[1]', a, b)
1829
2025
  }
1830
2026
 
1831
2027
  /** @return {!WebDriver} The parent driver for this instance. */
1832
2028
  getDriver() {
1833
- return this.driver_;
2029
+ return this.driver_
1834
2030
  }
1835
2031
 
1836
2032
  /**
@@ -1838,14 +2034,14 @@ class WebElement {
1838
2034
  * the server-assigned opaque ID assigned to this element.
1839
2035
  */
1840
2036
  getId() {
1841
- return this.id_;
2037
+ return this.id_
1842
2038
  }
1843
2039
 
1844
2040
  /**
1845
2041
  * @return {!Object} Returns the serialized representation of this WebElement.
1846
2042
  */
1847
2043
  [Symbols.serialize]() {
1848
- return this.getId().then(WebElement.buildId);
2044
+ return this.getId().then(WebElement.buildId)
1849
2045
  }
1850
2046
 
1851
2047
  /**
@@ -1860,8 +2056,8 @@ class WebElement {
1860
2056
  * @private
1861
2057
  */
1862
2058
  execute_(command) {
1863
- command.setParameter('id', this);
1864
- return this.driver_.execute(command);
2059
+ command.setParameter('id', this)
2060
+ return this.driver_.execute(command)
1865
2061
  }
1866
2062
 
1867
2063
  /**
@@ -1899,18 +2095,17 @@ class WebElement {
1899
2095
  * element will be invalidated and all scheduled commands aborted.
1900
2096
  */
1901
2097
  findElement(locator) {
1902
- locator = by.checkedLocator(locator);
1903
- let id;
2098
+ locator = by.checkedLocator(locator)
2099
+ let id
1904
2100
  if (typeof locator === 'function') {
1905
- id = this.driver_.findElementInternal_(locator, this);
2101
+ id = this.driver_.findElementInternal_(locator, this)
1906
2102
  } 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);
2103
+ let cmd = new command.Command(command.Name.FIND_CHILD_ELEMENT)
2104
+ .setParameter('using', locator.using)
2105
+ .setParameter('value', locator.value)
2106
+ id = this.execute_(cmd)
1912
2107
  }
1913
- return new WebElementPromise(this.driver_, id);
2108
+ return new WebElementPromise(this.driver_, id)
1914
2109
  }
1915
2110
 
1916
2111
  /**
@@ -1923,16 +2118,15 @@ class WebElement {
1923
2118
  * array of WebElements.
1924
2119
  */
1925
2120
  async findElements(locator) {
1926
- locator = by.checkedLocator(locator);
1927
- let id;
2121
+ locator = by.checkedLocator(locator)
1928
2122
  if (typeof locator === 'function') {
1929
- return this.driver_.findElementsInternal_(locator, this);
2123
+ return this.driver_.findElementsInternal_(locator, this)
1930
2124
  } else {
1931
2125
  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 : [];
2126
+ .setParameter('using', locator.using)
2127
+ .setParameter('value', locator.value)
2128
+ let result = await this.execute_(cmd)
2129
+ return Array.isArray(result) ? result : []
1936
2130
  }
1937
2131
  }
1938
2132
 
@@ -1943,7 +2137,7 @@ class WebElement {
1943
2137
  * command has completed.
1944
2138
  */
1945
2139
  click() {
1946
- return this.execute_(new command.Command(command.Name.CLICK_ELEMENT));
2140
+ return this.execute_(new command.Command(command.Name.CLICK_ELEMENT))
1947
2141
  }
1948
2142
 
1949
2143
  /**
@@ -2002,34 +2196,37 @@ class WebElement {
2002
2196
  * have been typed.
2003
2197
  */
2004
2198
  async sendKeys(...args) {
2005
- let keys = [];
2006
- (await Promise.all(args)).forEach(key => {
2007
- let type = typeof key;
2199
+ let keys = []
2200
+ ;(await Promise.all(args)).forEach((key) => {
2201
+ let type = typeof key
2008
2202
  if (type === 'number') {
2009
- key = String(key);
2203
+ key = String(key)
2010
2204
  } else if (type !== 'string') {
2011
- throw TypeError('each key must be a number of string; got ' + type);
2205
+ throw TypeError('each key must be a number of string; got ' + type)
2012
2206
  }
2013
2207
 
2014
2208
  // The W3C protocol requires keys to be specified as an array where
2015
2209
  // each element is a single key.
2016
- keys.push(...key.split(''));
2017
- });
2210
+ keys.push(...key.split(''))
2211
+ })
2018
2212
 
2019
2213
  if (!this.driver_.fileDetector_) {
2020
2214
  return this.execute_(
2021
- new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2022
- .setParameter('text', keys.join(''))
2023
- .setParameter('value', keys));
2215
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2216
+ .setParameter('text', keys.join(''))
2217
+ .setParameter('value', keys)
2218
+ )
2024
2219
  }
2025
2220
 
2026
- keys =
2027
- await this.driver_.fileDetector_.handleFile(
2028
- this.driver_, keys.join(''));
2221
+ keys = await this.driver_.fileDetector_.handleFile(
2222
+ this.driver_,
2223
+ keys.join('')
2224
+ )
2029
2225
  return this.execute_(
2030
- new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2031
- .setParameter('text', keys)
2032
- .setParameter('value', keys.split('')));
2226
+ new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2227
+ .setParameter('text', keys)
2228
+ .setParameter('value', keys.split(''))
2229
+ )
2033
2230
  }
2034
2231
 
2035
2232
  /**
@@ -2039,8 +2236,7 @@ class WebElement {
2039
2236
  * element's tag name.
2040
2237
  */
2041
2238
  getTagName() {
2042
- return this.execute_(
2043
- new command.Command(command.Name.GET_ELEMENT_TAG_NAME));
2239
+ return this.execute_(new command.Command(command.Name.GET_ELEMENT_TAG_NAME))
2044
2240
  }
2045
2241
 
2046
2242
  /**
@@ -2058,10 +2254,10 @@ class WebElement {
2058
2254
  * requested CSS value.
2059
2255
  */
2060
2256
  getCssValue(cssStyleProperty) {
2061
- var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY;
2257
+ var name = command.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY
2062
2258
  return this.execute_(
2063
- new command.Command(name).
2064
- setParameter('propertyName', cssStyleProperty));
2259
+ new command.Command(name).setParameter('propertyName', cssStyleProperty)
2260
+ )
2065
2261
  }
2066
2262
 
2067
2263
  /**
@@ -2095,8 +2291,26 @@ class WebElement {
2095
2291
  */
2096
2292
  getAttribute(attributeName) {
2097
2293
  return this.execute_(
2098
- new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).
2099
- setParameter('name', attributeName));
2294
+ new command.Command(command.Name.GET_ELEMENT_ATTRIBUTE).setParameter(
2295
+ 'name',
2296
+ attributeName
2297
+ )
2298
+ )
2299
+ }
2300
+
2301
+ /**
2302
+ * Get the given property of the referenced web element
2303
+ * @param {string} propertyName The name of the attribute to query.
2304
+ * @return {!Promise<string>} A promise that will be
2305
+ * resolved with the element's property value
2306
+ */
2307
+ getProperty(propertyName) {
2308
+ return this.execute_(
2309
+ new command.Command(command.Name.GET_ELEMENT_PROPERTY).setParameter(
2310
+ 'name',
2311
+ propertyName
2312
+ )
2313
+ )
2100
2314
  }
2101
2315
 
2102
2316
  /**
@@ -2107,7 +2321,7 @@ class WebElement {
2107
2321
  * resolved with the element's visible text.
2108
2322
  */
2109
2323
  getText() {
2110
- return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT));
2324
+ return this.execute_(new command.Command(command.Name.GET_ELEMENT_TEXT))
2111
2325
  }
2112
2326
 
2113
2327
  /**
@@ -2120,16 +2334,17 @@ class WebElement {
2120
2334
  async getRect() {
2121
2335
  try {
2122
2336
  return await this.execute_(
2123
- new command.Command(command.Name.GET_ELEMENT_RECT));
2337
+ new command.Command(command.Name.GET_ELEMENT_RECT)
2338
+ )
2124
2339
  } catch (err) {
2125
2340
  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};
2341
+ const { width, height } = await this.execute_(
2342
+ new command.Command(command.Name.GET_ELEMENT_SIZE)
2343
+ )
2344
+ const { x, y } = await this.execute_(
2345
+ new command.Command(command.Name.GET_ELEMENT_LOCATION)
2346
+ )
2347
+ return { x, y, width, height }
2133
2348
  }
2134
2349
  }
2135
2350
  }
@@ -2142,7 +2357,7 @@ class WebElement {
2142
2357
  * resolved with whether this element is currently enabled.
2143
2358
  */
2144
2359
  isEnabled() {
2145
- return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED));
2360
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_ENABLED))
2146
2361
  }
2147
2362
 
2148
2363
  /**
@@ -2152,8 +2367,7 @@ class WebElement {
2152
2367
  * resolved with whether this element is currently selected.
2153
2368
  */
2154
2369
  isSelected() {
2155
- return this.execute_(
2156
- new command.Command(command.Name.IS_ELEMENT_SELECTED));
2370
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_SELECTED))
2157
2371
  }
2158
2372
 
2159
2373
  /**
@@ -2165,7 +2379,7 @@ class WebElement {
2165
2379
  * when the form has been submitted.
2166
2380
  */
2167
2381
  submit() {
2168
- return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT));
2382
+ return this.execute_(new command.Command(command.Name.SUBMIT_ELEMENT))
2169
2383
  }
2170
2384
 
2171
2385
  /**
@@ -2177,7 +2391,7 @@ class WebElement {
2177
2391
  * when the element has been cleared.
2178
2392
  */
2179
2393
  clear() {
2180
- return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT));
2394
+ return this.execute_(new command.Command(command.Name.CLEAR_ELEMENT))
2181
2395
  }
2182
2396
 
2183
2397
  /**
@@ -2187,8 +2401,7 @@ class WebElement {
2187
2401
  * resolved with whether this element is currently visible on the page.
2188
2402
  */
2189
2403
  isDisplayed() {
2190
- return this.execute_(
2191
- new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
2404
+ return this.execute_(new command.Command(command.Name.IS_ELEMENT_DISPLAYED))
2192
2405
  }
2193
2406
 
2194
2407
  /**
@@ -2203,12 +2416,14 @@ class WebElement {
2203
2416
  */
2204
2417
  takeScreenshot(scroll = false) {
2205
2418
  return this.execute_(
2206
- new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT)
2207
- .setParameter('scroll', scroll));
2419
+ new command.Command(command.Name.TAKE_ELEMENT_SCREENSHOT).setParameter(
2420
+ 'scroll',
2421
+ scroll
2422
+ )
2423
+ )
2208
2424
  }
2209
2425
  }
2210
2426
 
2211
-
2212
2427
  /**
2213
2428
  * WebElementPromise is a promise that will be fulfilled with a WebElement.
2214
2429
  * This serves as a forward proxy on WebElement, allowing calls to be
@@ -2232,35 +2447,33 @@ class WebElementPromise extends WebElement {
2232
2447
  * that will resolve to the promised element.
2233
2448
  */
2234
2449
  constructor(driver, el) {
2235
- super(driver, 'unused');
2450
+ super(driver, 'unused')
2236
2451
 
2237
2452
  /** @override */
2238
- this.then = el.then.bind(el);
2453
+ this.then = el.then.bind(el)
2239
2454
 
2240
2455
  /** @override */
2241
- this.catch = el.catch.bind(el);
2456
+ this.catch = el.catch.bind(el)
2242
2457
 
2243
2458
  /**
2244
2459
  * Defers returning the element ID until the wrapped WebElement has been
2245
2460
  * resolved.
2246
2461
  * @override
2247
2462
  */
2248
- this.getId = function() {
2249
- return el.then(function(el) {
2250
- return el.getId();
2251
- });
2252
- };
2463
+ this.getId = function () {
2464
+ return el.then(function (el) {
2465
+ return el.getId()
2466
+ })
2467
+ }
2253
2468
  }
2254
2469
  }
2255
2470
 
2256
-
2257
2471
  //////////////////////////////////////////////////////////////////////////////
2258
2472
  //
2259
2473
  // Alert
2260
2474
  //
2261
2475
  //////////////////////////////////////////////////////////////////////////////
2262
2476
 
2263
-
2264
2477
  /**
2265
2478
  * Represents a modal dialog such as {@code alert}, {@code confirm}, or
2266
2479
  * {@code prompt}. Provides functions to retrieve the message displayed with
@@ -2275,10 +2488,10 @@ class Alert {
2275
2488
  */
2276
2489
  constructor(driver, text) {
2277
2490
  /** @private {!WebDriver} */
2278
- this.driver_ = driver;
2491
+ this.driver_ = driver
2279
2492
 
2280
2493
  /** @private {!Promise<string>} */
2281
- this.text_ = Promise.resolve(text);
2494
+ this.text_ = Promise.resolve(text)
2282
2495
  }
2283
2496
 
2284
2497
  /**
@@ -2289,7 +2502,7 @@ class Alert {
2289
2502
  * resolved to the text displayed with this alert.
2290
2503
  */
2291
2504
  getText() {
2292
- return this.text_;
2505
+ return this.text_
2293
2506
  }
2294
2507
 
2295
2508
  /**
@@ -2299,8 +2512,7 @@ class Alert {
2299
2512
  * when this command has completed.
2300
2513
  */
2301
2514
  accept() {
2302
- return this.driver_.execute(
2303
- new command.Command(command.Name.ACCEPT_ALERT));
2515
+ return this.driver_.execute(new command.Command(command.Name.ACCEPT_ALERT))
2304
2516
  }
2305
2517
 
2306
2518
  /**
@@ -2310,8 +2522,7 @@ class Alert {
2310
2522
  * when this command has completed.
2311
2523
  */
2312
2524
  dismiss() {
2313
- return this.driver_.execute(
2314
- new command.Command(command.Name.DISMISS_ALERT));
2525
+ return this.driver_.execute(new command.Command(command.Name.DISMISS_ALERT))
2315
2526
  }
2316
2527
 
2317
2528
  /**
@@ -2325,12 +2536,14 @@ class Alert {
2325
2536
  */
2326
2537
  sendKeys(text) {
2327
2538
  return this.driver_.execute(
2328
- new command.Command(command.Name.SET_ALERT_TEXT).
2329
- setParameter('text', text));
2539
+ new command.Command(command.Name.SET_ALERT_TEXT).setParameter(
2540
+ 'text',
2541
+ text
2542
+ )
2543
+ )
2330
2544
  }
2331
2545
  }
2332
2546
 
2333
-
2334
2547
  /**
2335
2548
  * AlertPromise is a promise that will be fulfilled with an Alert. This promise
2336
2549
  * serves as a forward proxy on an Alert, allowing calls to be scheduled
@@ -2353,60 +2566,58 @@ class AlertPromise extends Alert {
2353
2566
  * that will be fulfilled with the promised alert.
2354
2567
  */
2355
2568
  constructor(driver, alert) {
2356
- super(driver, 'unused');
2569
+ super(driver, 'unused')
2357
2570
 
2358
2571
  /** @override */
2359
- this.then = alert.then.bind(alert);
2572
+ this.then = alert.then.bind(alert)
2360
2573
 
2361
2574
  /** @override */
2362
- this.catch = alert.catch.bind(alert);
2575
+ this.catch = alert.catch.bind(alert)
2363
2576
 
2364
2577
  /**
2365
2578
  * Defer returning text until the promised alert has been resolved.
2366
2579
  * @override
2367
2580
  */
2368
- this.getText = function() {
2369
- return alert.then(function(alert) {
2370
- return alert.getText();
2371
- });
2372
- };
2581
+ this.getText = function () {
2582
+ return alert.then(function (alert) {
2583
+ return alert.getText()
2584
+ })
2585
+ }
2373
2586
 
2374
2587
  /**
2375
2588
  * Defers action until the alert has been located.
2376
2589
  * @override
2377
2590
  */
2378
- this.accept = function() {
2379
- return alert.then(function(alert) {
2380
- return alert.accept();
2381
- });
2382
- };
2591
+ this.accept = function () {
2592
+ return alert.then(function (alert) {
2593
+ return alert.accept()
2594
+ })
2595
+ }
2383
2596
 
2384
2597
  /**
2385
2598
  * Defers action until the alert has been located.
2386
2599
  * @override
2387
2600
  */
2388
- this.dismiss = function() {
2389
- return alert.then(function(alert) {
2390
- return alert.dismiss();
2391
- });
2392
- };
2601
+ this.dismiss = function () {
2602
+ return alert.then(function (alert) {
2603
+ return alert.dismiss()
2604
+ })
2605
+ }
2393
2606
 
2394
2607
  /**
2395
2608
  * Defers action until the alert has been located.
2396
2609
  * @override
2397
2610
  */
2398
- this.sendKeys = function(text) {
2399
- return alert.then(function(alert) {
2400
- return alert.sendKeys(text);
2401
- });
2402
- };
2611
+ this.sendKeys = function (text) {
2612
+ return alert.then(function (alert) {
2613
+ return alert.sendKeys(text)
2614
+ })
2615
+ }
2403
2616
  }
2404
2617
  }
2405
2618
 
2406
-
2407
2619
  // PUBLIC API
2408
2620
 
2409
-
2410
2621
  module.exports = {
2411
2622
  Alert,
2412
2623
  AlertPromise,
@@ -2420,5 +2631,5 @@ module.exports = {
2420
2631
  WebElement,
2421
2632
  WebElementCondition,
2422
2633
  WebElementPromise,
2423
- Window
2424
- };
2634
+ Window,
2635
+ }