selenium-webdriver 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/until.js CHANGED
@@ -137,14 +137,13 @@ exports.alertIsPresent = function alertIsPresent() {
137
137
  * @return {!Condition<boolean>} The new condition.
138
138
  */
139
139
  exports.titleIs = function titleIs(title) {
140
- return new Condition(
141
- 'for title to be ' + JSON.stringify(title),
142
- function (driver) {
143
- return driver.getTitle().then(function (t) {
144
- return t === title
145
- })
146
- }
147
- )
140
+ return new Condition('for title to be ' + JSON.stringify(title), function (
141
+ driver
142
+ ) {
143
+ return driver.getTitle().then(function (t) {
144
+ return t === title
145
+ })
146
+ })
148
147
  }
149
148
 
150
149
  /**
@@ -189,14 +188,13 @@ exports.titleMatches = function titleMatches(regex) {
189
188
  * @return {!Condition<boolean>} The new condition.
190
189
  */
191
190
  exports.urlIs = function urlIs(url) {
192
- return new Condition(
193
- 'for URL to be ' + JSON.stringify(url),
194
- function (driver) {
195
- return driver.getCurrentUrl().then(function (u) {
196
- return u === url
197
- })
198
- }
199
- )
191
+ return new Condition('for URL to be ' + JSON.stringify(url), function (
192
+ driver
193
+ ) {
194
+ return driver.getCurrentUrl().then(function (u) {
195
+ return u === url
196
+ })
197
+ })
200
198
  }
201
199
 
202
200
  /**
package/lib/webdriver.js CHANGED
@@ -250,30 +250,30 @@ class IWebDriver {
250
250
  * result.
251
251
  * @template T
252
252
  */
253
- execute(command) { } // eslint-disable-line
253
+ execute(command) {} // eslint-disable-line
254
254
 
255
255
  /**
256
256
  * Sets the {@linkplain input.FileDetector file detector} that should be
257
257
  * used with this instance.
258
258
  * @param {input.FileDetector} detector The detector to use or `null`.
259
259
  */
260
- setFileDetector(detector) { } // eslint-disable-line
260
+ setFileDetector(detector) {} // eslint-disable-line
261
261
 
262
262
  /**
263
263
  * @return {!command.Executor} The command executor used by this instance.
264
264
  */
265
- getExecutor() { }
265
+ getExecutor() {}
266
266
 
267
267
  /**
268
268
  * @return {!Promise<!Session>} A promise for this client's session.
269
269
  */
270
- getSession() { }
270
+ getSession() {}
271
271
 
272
272
  /**
273
273
  * @return {!Promise<!Capabilities>} A promise that will resolve with
274
274
  * the this instance's capabilities.
275
275
  */
276
- getCapabilities() { }
276
+ getCapabilities() {}
277
277
 
278
278
  /**
279
279
  * Terminates the browser session. After calling quit, this instance will be
@@ -283,7 +283,7 @@ class IWebDriver {
283
283
  * @return {!Promise<void>} A promise that will be resolved when the
284
284
  * command has completed.
285
285
  */
286
- quit() { }
286
+ quit() {}
287
287
 
288
288
  /**
289
289
  * Creates a new action sequence using this driver. The sequence will not be
@@ -296,7 +296,7 @@ class IWebDriver {
296
296
  * for details).
297
297
  * @return {!input.Actions} A new action sequence for this instance.
298
298
  */
299
- actions(options) { } // eslint-disable-line
299
+ actions(options) {} // eslint-disable-line
300
300
 
301
301
  /**
302
302
  * Executes a snippet of JavaScript in the context of the currently selected
@@ -334,7 +334,7 @@ class IWebDriver {
334
334
  * scripts return value.
335
335
  * @template T
336
336
  */
337
- executeScript(script, ...args) { } // eslint-disable-line
337
+ executeScript(script, ...args) {} // eslint-disable-line
338
338
 
339
339
  /**
340
340
  * Executes a snippet of asynchronous JavaScript in the context of the
@@ -411,7 +411,7 @@ class IWebDriver {
411
411
  * value.
412
412
  * @template T
413
413
  */
414
- executeAsyncScript(script, ...args) { } // eslint-disable-line
414
+ executeAsyncScript(script, ...args) {} // eslint-disable-line
415
415
 
416
416
  /**
417
417
  * Waits for a condition to evaluate to a "truthy" value. The condition may be
@@ -462,7 +462,7 @@ class IWebDriver {
462
462
  timeout = undefined, // eslint-disable-line
463
463
  message = undefined, // eslint-disable-line
464
464
  pollTimeout = undefined // eslint-disable-line
465
- ) { }
465
+ ) {}
466
466
 
467
467
  /**
468
468
  * Makes the driver sleep for the given amount of time.
@@ -471,7 +471,7 @@ class IWebDriver {
471
471
  * @return {!Promise<void>} A promise that will be resolved when the sleep has
472
472
  * finished.
473
473
  */
474
- sleep(ms) { } // eslint-disable-line
474
+ sleep(ms) {} // eslint-disable-line
475
475
 
476
476
  /**
477
477
  * Retrieves the current window handle.
@@ -479,7 +479,7 @@ class IWebDriver {
479
479
  * @return {!Promise<string>} A promise that will be resolved with the current
480
480
  * window handle.
481
481
  */
482
- getWindowHandle() { }
482
+ getWindowHandle() {}
483
483
 
484
484
  /**
485
485
  * Retrieves a list of all available window handles.
@@ -487,7 +487,7 @@ class IWebDriver {
487
487
  * @return {!Promise<!Array<string>>} A promise that will be resolved with an
488
488
  * array of window handles.
489
489
  */
490
- getAllWindowHandles() { }
490
+ getAllWindowHandles() {}
491
491
 
492
492
  /**
493
493
  * Retrieves the current page's source. The returned source is a representation
@@ -497,7 +497,7 @@ class IWebDriver {
497
497
  * @return {!Promise<string>} A promise that will be resolved with the current
498
498
  * page source.
499
499
  */
500
- getPageSource() { }
500
+ getPageSource() {}
501
501
 
502
502
  /**
503
503
  * Closes the current window.
@@ -505,7 +505,7 @@ class IWebDriver {
505
505
  * @return {!Promise<void>} A promise that will be resolved when this command
506
506
  * has completed.
507
507
  */
508
- close() { }
508
+ close() {}
509
509
 
510
510
  /**
511
511
  * Navigates to the given URL.
@@ -514,7 +514,7 @@ class IWebDriver {
514
514
  * @return {!Promise<void>} A promise that will be resolved when the document
515
515
  * has finished loading.
516
516
  */
517
- get(url) { } // eslint-disable-line
517
+ get(url) {} // eslint-disable-line
518
518
 
519
519
  /**
520
520
  * Retrieves the URL for the current page.
@@ -522,7 +522,7 @@ class IWebDriver {
522
522
  * @return {!Promise<string>} A promise that will be resolved with the
523
523
  * current URL.
524
524
  */
525
- getCurrentUrl() { }
525
+ getCurrentUrl() {}
526
526
 
527
527
  /**
528
528
  * Retrieves the current page title.
@@ -530,7 +530,7 @@ class IWebDriver {
530
530
  * @return {!Promise<string>} A promise that will be resolved with the current
531
531
  * page's title.
532
532
  */
533
- getTitle() { }
533
+ getTitle() {}
534
534
 
535
535
  /**
536
536
  * Locates an element on the page. If the element cannot be found, a
@@ -570,7 +570,7 @@ class IWebDriver {
570
570
  * commands against the located element. If the element is not found, the
571
571
  * element will be invalidated and all scheduled commands aborted.
572
572
  */
573
- findElement(locator) { } // eslint-disable-line
573
+ findElement(locator) {} // eslint-disable-line
574
574
 
575
575
  /**
576
576
  * Search for multiple elements on the page. Refer to the documentation on
@@ -580,7 +580,7 @@ class IWebDriver {
580
580
  * @return {!Promise<!Array<!WebElement>>} A promise that will resolve to an
581
581
  * array of WebElements.
582
582
  */
583
- findElements(locator) { } // eslint-disable-line
583
+ findElements(locator) {} // eslint-disable-line
584
584
 
585
585
  /**
586
586
  * Takes a screenshot of the current page. The driver makes a best effort to
@@ -594,23 +594,23 @@ class IWebDriver {
594
594
  * @return {!Promise<string>} A promise that will be resolved to the
595
595
  * screenshot as a base-64 encoded PNG.
596
596
  */
597
- takeScreenshot() { }
597
+ takeScreenshot() {}
598
598
 
599
599
  /**
600
600
  * @return {!Options} The options interface for this instance.
601
601
  */
602
- manage() { }
602
+ manage() {}
603
603
 
604
604
  /**
605
605
  * @return {!Navigation} The navigation interface for this instance.
606
606
  */
607
- navigate() { }
607
+ navigate() {}
608
608
 
609
609
  /**
610
610
  * @return {!TargetLocator} The target locator interface for this
611
611
  * instance.
612
612
  */
613
- switchTo() { }
613
+ switchTo() {}
614
614
 
615
615
  /**
616
616
  *
@@ -629,7 +629,7 @@ class IWebDriver {
629
629
  * shrinkToFit: (boolean|undefined)
630
630
  * pageRanges: (<Array>|undefined)}} options.
631
631
  */
632
- printPage(options) { } // eslint-disable-line
632
+ printPage(options) {} // eslint-disable-line
633
633
  }
634
634
 
635
635
  /**
@@ -669,7 +669,7 @@ class WebDriver {
669
669
  // If session is a rejected promise, add a no-op rejection handler.
670
670
  // This effectively hides setup errors until users attempt to interact
671
671
  // with the session.
672
- this.session_.catch(function () { })
672
+ this.session_.catch(function () {})
673
673
 
674
674
  /** @private {!command.Executor} */
675
675
  this.executor_ = executor
@@ -765,12 +765,12 @@ class WebDriver {
765
765
  this.session_ = Promise.reject(
766
766
  new error.NoSuchSessionError(
767
767
  'This driver instance does not have a valid session ID ' +
768
- '(did you call WebDriver.quit()?) and may no longer be used.'
768
+ '(did you call WebDriver.quit()?) and may no longer be used.'
769
769
  )
770
770
  )
771
771
 
772
772
  // Only want the session rejection to bubble if accessed.
773
- this.session_.catch(function () { })
773
+ this.session_.catch(function () {})
774
774
 
775
775
  if (this.onQuit_) {
776
776
  return this.onQuit_.call(void 0)
@@ -831,15 +831,18 @@ class WebDriver {
831
831
  let timeoutMessage = resolveWaitMessage(message)
832
832
  reject(
833
833
  new error.TimeoutError(
834
- `${timeoutMessage}Timed out waiting for promise to resolve after ${Date.now() - start
834
+ `${timeoutMessage}Timed out waiting for promise to resolve after ${
835
+ Date.now() - start
835
836
  }ms`
836
837
  )
837
838
  )
838
839
  } catch (ex) {
839
840
  reject(
840
841
  new error.TimeoutError(
841
- `${ex.message
842
- }\nTimed out waiting for promise to resolve after ${Date.now() - start
842
+ `${
843
+ ex.message
844
+ }\nTimed out waiting for promise to resolve after ${
845
+ Date.now() - start
843
846
  }ms`
844
847
  )
845
848
  )
@@ -869,7 +872,7 @@ class WebDriver {
869
872
  if (typeof fn !== 'function') {
870
873
  throw TypeError(
871
874
  'Wait condition must be a promise-like object, function, or a ' +
872
- 'Condition object'
875
+ 'Condition object'
873
876
  )
874
877
  }
875
878
 
@@ -921,7 +924,7 @@ class WebDriver {
921
924
  if (!(value instanceof WebElement)) {
922
925
  throw TypeError(
923
926
  'WebElementCondition did not resolve to a WebElement: ' +
924
- Object.prototype.toString.call(value)
927
+ Object.prototype.toString.call(value)
925
928
  )
926
929
  }
927
930
  return value
@@ -1194,14 +1197,25 @@ class WebDriver {
1194
1197
  * @return {!Promise<resolved>} A new CDP instance.
1195
1198
  */
1196
1199
  async createCDPConnection(target) {
1200
+ let debuggerUrl = null
1201
+
1197
1202
  const caps = await this.getCapabilities()
1198
- const seCdp = caps['map_'].get('se:cdp')
1199
- const vendorInfo =
1200
- caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
1201
- caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
1202
- caps['map_'].get('moz:debuggerAddress') ||
1203
- new Map()
1204
- const debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
1203
+
1204
+ if (process.env.SELENIUM_REMOTE_URL) {
1205
+ const host = new URL(process.env.SELENIUM_REMOTE_URL).host
1206
+ const sessionId = await this.getSession().then((session) =>
1207
+ session.getId()
1208
+ )
1209
+ debuggerUrl = `ws://${host}/session/${sessionId}/se/cdp`
1210
+ } else {
1211
+ const seCdp = caps['map_'].get('se:cdp')
1212
+ const vendorInfo =
1213
+ caps['map_'].get(this.VENDOR_COMMAND_PREFIX + ':chromeOptions') ||
1214
+ caps['map_'].get(this.VENDOR_CAPABILITY_PREFIX + ':edgeOptions') ||
1215
+ caps['map_'].get('moz:debuggerAddress') ||
1216
+ new Map()
1217
+ debuggerUrl = seCdp || vendorInfo['debuggerAddress'] || vendorInfo
1218
+ }
1205
1219
  this._wsUrl = await this.getWsUrl(debuggerUrl, target, caps)
1206
1220
  return new Promise((resolve, reject) => {
1207
1221
  try {
@@ -1393,7 +1407,7 @@ class WebDriver {
1393
1407
 
1394
1408
  callback(event)
1395
1409
  }
1396
-
1410
+
1397
1411
  if (params.method === 'Log.entryAdded') {
1398
1412
  const logEventParams = params['params']
1399
1413
  const logEntry = logEventParams['entry']
@@ -1405,7 +1419,6 @@ class WebDriver {
1405
1419
 
1406
1420
  callback(event)
1407
1421
  }
1408
-
1409
1422
  })
1410
1423
  await connection.execute('Runtime.enable', {}, null)
1411
1424
  }
@@ -1783,7 +1796,7 @@ class Options {
1783
1796
  } else if (typeof value !== 'undefined') {
1784
1797
  throw TypeError(
1785
1798
  'invalid timeouts configuration:' +
1786
- ` expected "${key}" to be a number, got ${typeof value}`
1799
+ ` expected "${key}" to be a number, got ${typeof value}`
1787
1800
  )
1788
1801
  }
1789
1802
  }
@@ -1844,7 +1857,7 @@ function legacyTimeout(driver, type, ms) {
1844
1857
  *
1845
1858
  * @record
1846
1859
  */
1847
- Options.Cookie = function () { }
1860
+ Options.Cookie = function () {}
1848
1861
 
1849
1862
  /**
1850
1863
  * The name of the cookie.
@@ -1943,29 +1956,10 @@ class Window {
1943
1956
  * @return {!Promise<{x: number, y: number, width: number, height: number}>}
1944
1957
  * A promise that will resolve to the window rect of the current window.
1945
1958
  */
1946
- async getRect() {
1947
- try {
1948
- return await this.driver_.execute(
1949
- new command.Command(command.Name.GET_WINDOW_RECT)
1950
- )
1951
- } catch (ex) {
1952
- if (ex instanceof error.UnknownCommandError) {
1953
- let { width, height } = await this.driver_.execute(
1954
- new command.Command(command.Name.GET_WINDOW_SIZE).setParameter(
1955
- 'windowHandle',
1956
- 'current'
1957
- )
1958
- )
1959
- let { x, y } = await this.driver_.execute(
1960
- new command.Command(command.Name.GET_WINDOW_POSITION).setParameter(
1961
- 'windowHandle',
1962
- 'current'
1963
- )
1964
- )
1965
- return { x, y, width, height }
1966
- }
1967
- throw ex
1968
- }
1959
+ getRect() {
1960
+ return this.driver_.execute(
1961
+ new command.Command(command.Name.GET_WINDOW_RECT)
1962
+ )
1969
1963
  }
1970
1964
 
1971
1965
  /**
@@ -1982,39 +1976,15 @@ class Window {
1982
1976
  * A promise that will resolve to the current window's updated window
1983
1977
  * rect.
1984
1978
  */
1985
- async setRect({ x, y, width, height }) {
1986
- try {
1987
- return await this.driver_.execute(
1988
- new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
1989
- x,
1990
- y,
1991
- width,
1992
- height,
1993
- })
1994
- )
1995
- } catch (ex) {
1996
- if (ex instanceof error.UnknownCommandError) {
1997
- if (typeof x === 'number' && typeof y === 'number') {
1998
- await this.driver_.execute(
1999
- new command.Command(command.Name.SET_WINDOW_POSITION)
2000
- .setParameter('windowHandle', 'current')
2001
- .setParameter('x', x)
2002
- .setParameter('y', y)
2003
- )
2004
- }
2005
-
2006
- if (typeof width === 'number' && typeof height === 'number') {
2007
- await this.driver_.execute(
2008
- new command.Command(command.Name.SET_WINDOW_SIZE)
2009
- .setParameter('windowHandle', 'current')
2010
- .setParameter('width', width)
2011
- .setParameter('height', height)
2012
- )
2013
- }
2014
- return this.getRect()
2015
- }
2016
- throw ex
2017
- }
1979
+ setRect({ x, y, width, height }) {
1980
+ return this.driver_.execute(
1981
+ new command.Command(command.Name.SET_WINDOW_RECT).setParameters({
1982
+ x,
1983
+ y,
1984
+ width,
1985
+ height,
1986
+ })
1987
+ )
2018
1988
  }
2019
1989
 
2020
1990
  /**
@@ -2192,13 +2162,23 @@ class TargetLocator {
2192
2162
  * If the specified frame can not be found, the returned promise will be
2193
2163
  * rejected with a {@linkplain error.NoSuchFrameError}.
2194
2164
  *
2195
- * @param {(number|WebElement|null)} id The frame locator.
2165
+ * @param {(number|string|WebElement|null)} id The frame locator.
2196
2166
  * @return {!Promise<void>} A promise that will be resolved
2197
2167
  * when the driver has changed focus to the specified frame.
2198
2168
  */
2199
2169
  frame(id) {
2170
+ let frameReference = id
2171
+ if (typeof id === 'string') {
2172
+ frameReference = this.driver_
2173
+ .findElement({ id })
2174
+ .catch((_) => this.driver_.findElement({ name: id }))
2175
+ }
2176
+
2200
2177
  return this.driver_.execute(
2201
- new command.Command(command.Name.SWITCH_TO_FRAME).setParameter('id', id)
2178
+ new command.Command(command.Name.SWITCH_TO_FRAME).setParameter(
2179
+ 'id',
2180
+ frameReference
2181
+ )
2202
2182
  )
2203
2183
  }
2204
2184
 
@@ -2550,18 +2530,18 @@ class WebElement {
2550
2530
  */
2551
2531
  async sendKeys(...args) {
2552
2532
  let keys = []
2553
- ; (await Promise.all(args)).forEach((key) => {
2554
- let type = typeof key
2555
- if (type === 'number') {
2556
- key = String(key)
2557
- } else if (type !== 'string') {
2558
- throw TypeError('each key must be a number of string; got ' + type)
2559
- }
2533
+ ;(await Promise.all(args)).forEach((key) => {
2534
+ let type = typeof key
2535
+ if (type === 'number') {
2536
+ key = String(key)
2537
+ } else if (type !== 'string') {
2538
+ throw TypeError('each key must be a number or string; got ' + type)
2539
+ }
2560
2540
 
2561
- // The W3C protocol requires keys to be specified as an array where
2562
- // each element is a single key.
2563
- keys.push(...key.split(''))
2564
- })
2541
+ // The W3C protocol requires keys to be specified as an array where
2542
+ // each element is a single key.
2543
+ keys.push(...key)
2544
+ })
2565
2545
 
2566
2546
  if (!this.driver_.fileDetector_) {
2567
2547
  return this.execute_(
@@ -2571,10 +2551,18 @@ class WebElement {
2571
2551
  )
2572
2552
  }
2573
2553
 
2574
- keys = await this.driver_.fileDetector_.handleFile(
2575
- this.driver_,
2576
- keys.join('')
2577
- )
2554
+ try {
2555
+ keys = await this.driver_.fileDetector_.handleFile(
2556
+ this.driver_,
2557
+ keys.join('')
2558
+ )
2559
+ } catch (ex) {
2560
+ console.log(
2561
+ 'Error trying parse string as a file with file detector; sending keys instead' +
2562
+ ex
2563
+ )
2564
+ }
2565
+
2578
2566
  return this.execute_(
2579
2567
  new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
2580
2568
  .setParameter('text', keys)
@@ -2651,6 +2639,36 @@ class WebElement {
2651
2639
  )
2652
2640
  }
2653
2641
 
2642
+ /**
2643
+ * Get the value of the given attribute of the element.
2644
+ * <p>
2645
+ * This method, unlike {@link #getAttribute(String)}, returns the value of the attribute with the
2646
+ * given name but not the property with the same name.
2647
+ * <p>
2648
+ * The following are deemed to be "boolean" attributes, and will return either "true" or null:
2649
+ * <p>
2650
+ * async, autofocus, autoplay, checked, compact, complete, controls, declare, defaultchecked,
2651
+ * defaultselected, defer, disabled, draggable, ended, formnovalidate, hidden, indeterminate,
2652
+ * iscontenteditable, ismap, itemscope, loop, multiple, muted, nohref, noresize, noshade,
2653
+ * novalidate, nowrap, open, paused, pubdate, readonly, required, reversed, scoped, seamless,
2654
+ * seeking, selected, truespeed, willvalidate
2655
+ * <p>
2656
+ * See <a href="https://w3c.github.io/webdriver/#get-element-attribute">W3C WebDriver specification</a>
2657
+ * for more details.
2658
+ *
2659
+ * @param attributeName The name of the attribute.
2660
+ * @return The attribute's value or null if the value is not set.
2661
+ */
2662
+
2663
+ getDomAttribute(attributeName) {
2664
+ return this.execute_(
2665
+ new command.Command(command.Name.GET_DOM_ATTRIBUTE).setParameter(
2666
+ 'name',
2667
+ attributeName
2668
+ )
2669
+ )
2670
+ }
2671
+
2654
2672
  /**
2655
2673
  * Get the given property of the referenced web element
2656
2674
  * @param {string} propertyName The name of the attribute to query.
@@ -2713,22 +2731,8 @@ class WebElement {
2713
2731
  * @return {!Promise<{width: number, height: number, x: number, y: number}>}
2714
2732
  * A promise that will resolve with the element's rect.
2715
2733
  */
2716
- async getRect() {
2717
- try {
2718
- return await this.execute_(
2719
- new command.Command(command.Name.GET_ELEMENT_RECT)
2720
- )
2721
- } catch (err) {
2722
- if (err instanceof error.UnknownCommandError) {
2723
- const { width, height } = await this.execute_(
2724
- new command.Command(command.Name.GET_ELEMENT_SIZE)
2725
- )
2726
- const { x, y } = await this.execute_(
2727
- new command.Command(command.Name.GET_ELEMENT_LOCATION)
2728
- )
2729
- return { x, y, width, height }
2730
- }
2731
- }
2734
+ getRect() {
2735
+ return this.execute_(new command.Command(command.Name.GET_ELEMENT_RECT))
2732
2736
  }
2733
2737
 
2734
2738
  /**
@@ -2761,13 +2765,17 @@ class WebElement {
2761
2765
  * when the form has been submitted.
2762
2766
  */
2763
2767
  submit() {
2764
- const form = this.findElement({ xpath: './ancestor-or-self::form' })
2765
- this.driver_.executeScript(
2766
- "var e = arguments[0].ownerDocument.createEvent('Event');" +
2767
- "e.initEvent('submit', true, true);" +
2768
- 'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }',
2769
- form
2770
- )
2768
+ const script = "var form = arguments[0];\n" +
2769
+ "while (form.nodeName != \"FORM\" && form.parentNode) {\n" +
2770
+ " form = form.parentNode;\n" +
2771
+ "}\n" +
2772
+ "if (!form) { throw Error('Unable to find containing form element'); }\n" +
2773
+ "if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" +
2774
+ "var e = form.ownerDocument.createEvent('Event');\n" +
2775
+ "e.initEvent('submit', true, true);\n" +
2776
+ "if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n";
2777
+
2778
+ this.driver_.executeScript(script, this);
2771
2779
  }
2772
2780
 
2773
2781
  /**
@@ -2861,7 +2869,6 @@ class WebElementPromise extends WebElement {
2861
2869
  * retrieve elements that live in the DOM below the ShadowRoot.
2862
2870
  */
2863
2871
  class ShadowRoot {
2864
-
2865
2872
  constructor(driver, id) {
2866
2873
  this.driver_ = driver
2867
2874
  this.id_ = id
@@ -2891,7 +2898,8 @@ class ShadowRoot {
2891
2898
  return (
2892
2899
  obj &&
2893
2900
  typeof obj === 'object' &&
2894
- typeof obj[SHADOWROOT_ID_KEY] === 'string')
2901
+ typeof obj[SHADOWROOT_ID_KEY] === 'string'
2902
+ )
2895
2903
  }
2896
2904
 
2897
2905
  /**
@@ -3005,7 +3013,7 @@ class ShadowRootPromise extends ShadowRoot {
3005
3013
  /**
3006
3014
  * @param {!WebDriver} driver The parent WebDriver instance for this
3007
3015
  * element.
3008
- * @param {!Promise<!ShadowRoot>} el A promise
3016
+ * @param {!Promise<!ShadowRoot>} shadow A promise
3009
3017
  * that will resolve to the promised element.
3010
3018
  */
3011
3019
  constructor(driver, shadow) {