selenium-webdriver 3.6.0 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGES.md +181 -0
  2. package/README.md +25 -27
  3. package/chrome.js +113 -127
  4. package/edge.js +42 -117
  5. package/example/chrome_android.js +8 -8
  6. package/example/chrome_mobile_emulation.js +8 -8
  7. package/example/firefox_channels.js +22 -18
  8. package/example/google_search_test.js +39 -26
  9. package/example/logging.js +39 -6
  10. package/firefox.js +769 -0
  11. package/http/index.js +41 -4
  12. package/http/util.js +11 -6
  13. package/ie.js +56 -97
  14. package/index.js +178 -114
  15. package/jasmine.json +11 -0
  16. package/lib/actions.js +68 -63
  17. package/lib/by.js +1 -1
  18. package/lib/capabilities.js +255 -192
  19. package/lib/command.js +26 -50
  20. package/lib/error.js +85 -44
  21. package/lib/http.js +133 -110
  22. package/lib/input.js +1044 -8
  23. package/lib/promise.js +222 -3323
  24. package/lib/proxy.js +134 -39
  25. package/lib/test/bootstrap_jasmine.js +28 -0
  26. package/lib/test/data/actions/click.html +24 -0
  27. package/lib/test/data/actions/drag.html +77 -0
  28. package/lib/test/data/actions/record_click.html +21 -0
  29. package/lib/test/data/chrome/download.html +2 -0
  30. package/lib/test/data/inputs.html +42 -0
  31. package/lib/test/data/selectPage.html +12 -0
  32. package/lib/test/data/simpleTest.html +5 -0
  33. package/lib/test/data/upload_invisible.html +45 -0
  34. package/lib/test/fileserver.js +23 -19
  35. package/lib/test/index.js +30 -212
  36. package/lib/test/resources.js +0 -1
  37. package/lib/webdriver.js +675 -936
  38. package/net/index.js +21 -25
  39. package/net/portprober.js +51 -68
  40. package/package.json +5 -3
  41. package/remote/index.js +5 -19
  42. package/safari.js +41 -128
  43. package/test/actions_test.js +173 -18
  44. package/test/{session_test.js → builder_test.js} +44 -37
  45. package/test/chrome/devtools_test.js +93 -0
  46. package/test/chrome/options_test.js +48 -154
  47. package/test/chrome/service_test.js +7 -7
  48. package/test/cookie_test.js +77 -63
  49. package/test/element_finding_test.js +206 -201
  50. package/test/execute_script_test.js +115 -114
  51. package/test/fingerprint_test.js +16 -15
  52. package/test/firefox_test.js +251 -0
  53. package/test/http/http_test.js +0 -1
  54. package/test/http/util_test.js +2 -2
  55. package/test/io/zip_test.js +6 -7
  56. package/test/lib/error_test.js +34 -7
  57. package/test/lib/http_test.js +8 -128
  58. package/test/lib/input_test.js +1379 -0
  59. package/test/lib/promise_test.js +473 -908
  60. package/test/lib/webdriver_test.js +296 -868
  61. package/test/logging_test.js +37 -43
  62. package/test/page_loading_test.js +71 -81
  63. package/test/proxy_test.js +64 -72
  64. package/test/rect_test.js +14 -25
  65. package/test/remote_test.js +10 -29
  66. package/test/safari_test.js +7 -71
  67. package/test/stale_element_test.js +20 -23
  68. package/test/tag_name_test.js +10 -9
  69. package/test/upload_test.js +27 -35
  70. package/test/window_test.js +72 -85
  71. package/testing/index.js +386 -314
  72. package/.npmignore +0 -2
  73. package/example/async_await_test.js +0 -69
  74. package/example/google_search_generator.js +0 -47
  75. package/example/parallel_flows.js +0 -51
  76. package/firefox/binary.js +0 -347
  77. package/firefox/extension.js +0 -224
  78. package/firefox/index.js +0 -576
  79. package/firefox/profile.js +0 -311
  80. package/lib/events.js +0 -210
  81. package/lib/test/data/firefox/jetpack-sample.xpi +0 -0
  82. package/lib/test/data/firefox/sample.xpi +0 -0
  83. package/lib/test/promise.js +0 -79
  84. package/opera.js +0 -405
  85. package/phantomjs.js +0 -282
  86. package/test/firefox/extension_test.js +0 -120
  87. package/test/firefox/firefox_test.js +0 -244
  88. package/test/firefox/profile_test.js +0 -140
  89. package/test/lib/events_test.js +0 -177
  90. package/test/lib/promise_aplus_test.js +0 -78
  91. package/test/lib/promise_error_test.js +0 -884
  92. package/test/lib/promise_flow_test.js +0 -2288
  93. package/test/lib/promise_generator_test.js +0 -310
  94. package/test/phantomjs/execute_phantomjs_test.js +0 -59
  95. package/test/testing/assert_test.js +0 -373
  96. package/test/testing/index_test.js +0 -224
  97. package/testing/assert.js +0 -378
package/CHANGES.md CHANGED
@@ -1,3 +1,184 @@
1
+ ## v4.0.0-alpha.1
2
+
3
+ ### Notice
4
+
5
+ * The minimum supported version of Node is now 8.9.0 LTS
6
+
7
+ ### Changes to Supported Browsers
8
+
9
+ Native support has been removed for Opera and PhantomJS as the WebDriver
10
+ implementations for these browsers are no longer under active development.
11
+
12
+ For Opera, users should be able to simply rely on testing Chrome as the Opera
13
+ browser is based on Chromium (and the operadriver was a thin wrapper around
14
+ chromedriver). For PhantomJS, users should use Chrome or Firefox in headless
15
+ mode (see `example/headless.js`)
16
+
17
+ ### Changes for W3C WebDriver Spec Compliance
18
+
19
+ * Revamped the actions API to conform with the WebDriver Spec:
20
+ <https://www.w3.org/TR/webdriver/#actions>. For details, refer to the JS doc
21
+ on the `lib/input.Actions` class.
22
+
23
+ As of January, 2018, only Firefox natively supports this new API. You can
24
+ put the `Actions` class into "bridge mode" and it will attempt to translate
25
+ mouse and keyboard actions to the legacy API (see class docs). Alternatively,
26
+ you may continue to use the legacy API directly via the `lib/actions` module.
27
+ __NOTE:__ The legacy API is considered strongly deprecated and will be
28
+ removed in a minor release once Google's Chrome and Microsoft's Edge browsers
29
+ support the new API.
30
+
31
+ * All window manipulation commands are now supported.
32
+ * Added `driver.switchTo().parentFrame()`
33
+ * When a named cookie is requested, attempt to fetch it directly using the
34
+ W3C endpoint, `GET /session/{session id}/cookie/{name}`. If this command is
35
+ not recognized by the remote end, fallback to fetching all cookies and then
36
+ searching for the desired name.
37
+ * Replaced `WebElement.getSize()` and `WebElement.getLocation()` with a single
38
+ method, `WebElement.getRect()`.
39
+
40
+ ### API Changes
41
+
42
+ * The core WebDriver API no longer uses promise manager
43
+ - Removed `index.Builder#setControlFlow()`
44
+ - The following thenable types no longer have a `cancel()` method:
45
+ - The dynamically generated thenable WebDrivers created by `index.Builder`
46
+ - `lib/webdriver.AlertPromise`
47
+ - `lib/webdriver.WebElementPromise`
48
+ * Removed `remote/index.DriverService.prototype.stop()` (use `#kill()` instead)
49
+ * Removed the `lib/actions` module
50
+ * Removed the `lib/events` module
51
+ * Removed the `phantomjs` module
52
+ * Removed the 'opera' module
53
+ * Removed the promise manager from `lib/promise`, which includes the removal
54
+ of the following exported names (replacements, if any, in parentheses):
55
+ - CancellableThenable
56
+ - CancellationError
57
+ - ControlFlow
58
+ - Deferred
59
+ - LONG_STACK_TRACES
60
+ - MultipleUnhandledRejectionError
61
+ - Promise (use native Promises)
62
+ - Resolver
63
+ - Scheduler
64
+ - Thenable
65
+ - USE_PROMISE_MANAGER
66
+ - all (use Promise.all)
67
+ - asap (use Promise.resolve)
68
+ - captureStackTrace (use Error.captureStackTrace)
69
+ - consume (use async functions)
70
+ - controlFlow
71
+ - createPromise (use new Promise)
72
+ - defer
73
+ - fulfilled (use Promise.resolve)
74
+ - isGenerator
75
+ - rejected (use Promise.reject)
76
+ - setDefaultFlow
77
+ - when (use Promise.resolve)
78
+ * Changes to the `Builder` class:
79
+ - Added setChromeService, setEdgeService, & setFirefoxService
80
+ - Removed setEnableNativeEvents
81
+ - Removed setScrollBehavior
82
+ * Changes to `chrome.Driver`
83
+ - Added sendDevToolsCommand
84
+ - Added setDownloadPath
85
+ * Changes to `chrome.Options`
86
+ - Now extends the `Capabilities` class
87
+ - Removed from/toCapabilities
88
+ * Changes to `edge.Options`
89
+ - Now extends the `Capabilities` class
90
+ - Removed from/toCapabilities
91
+ * Changes to `ie.Options`
92
+ - Now extends the `Capabilities` class
93
+ - Removed from/toCapabilities
94
+ * Removed the `firefox.Binary` class. Custom binaries can still be selected
95
+ using `firefox.Options#setBinary()`. Likewise, custom binary arguments can be
96
+ specified with `firefox.Options#addArguments()`.
97
+ * Changes to `firefox.Driver`
98
+ - Added installAddon(path)
99
+ - Added uninstallAddon(id)
100
+ * Changes to `firefox.Options`
101
+ - Now extends the `Capabilities` class
102
+ - Removed from/toCapabilities
103
+ - Removed setLoggingPreferences (was a no-op)
104
+ - setProfile now only accepts a path to an existing profile
105
+ - Added addExtensions
106
+ - Added setPreference
107
+ * Removed the `firefox.Profile` class. All of its functionality is now
108
+ provided directly by `firefox.Options`
109
+ * Removed the `firefox/binary` module
110
+ * Removed the `firefox/profile` module
111
+ * Changes to `safari.Options`
112
+ - Now extends the `Capabilities` class
113
+ - Removed from/toCapabilities
114
+ - Removed setCleanSession (was a no-op)
115
+ * Changes to `lib/capabilities.Browser`:
116
+ - Removed several enum values.
117
+ - ANDROID (use Chrome for Android; see docs on the chrome module)
118
+ - IPAD (no support available)
119
+ - IPHONE (no support available)
120
+ - OPERA (use Chrome)
121
+ - PHANTOM_JS (use Chrome or Firefox in headless mode)
122
+ - HTMLUNIT (use Chrome or Firefox in headless mode)
123
+ * Changes to `lib/capabilities.Capabilities`:
124
+ - Removed static factory methods android(), ipad(), iphone(), opera(),
125
+ phantomjs(), htmlunit(), and htmlunitwithjs(). Users can still manually
126
+ configure capabilities for these, but their use is not recommended and
127
+ they will no longer be surfaced in the API.
128
+ * Changes to `lib/error`:
129
+ - Added
130
+ - ElementClickInterceptedError
131
+ - InsecureCertificateError
132
+ - InvalidCoordinatesError
133
+ - NoSuchCookieError
134
+ - Removed
135
+ - ElementNotVisibleError
136
+ - InvalidElementCoordinatesError
137
+ * Changes to `lib/webdriver.WebDriver`:
138
+ - Dropped support for "requiredCapabilities" from WebDriver.createSession
139
+ - actions() now returns the new `lib/input.Actions` class
140
+ - Removed touchActions
141
+ - Renamed schedule to execute
142
+ - Removed the `WebDriver.attachToSession()` factory method. Users can just
143
+ the `WebDriver` constructor directly instead.
144
+ - Removed the `call()` method. This was used to inject custom function calls
145
+ into the control flow. Now that the promise manager is no longer used,
146
+ this method is no longer necessary. Users are now responsible for
147
+ coordinating actions (ideally with async functions) and can just call
148
+ functions directly instead of through `driver.call()`.
149
+ * Changes to `lib/webdriver.WebElement`:
150
+ - Replaced getSize & getLocation with getRect
151
+ * Changes to `lib/webdriver.Alert`:
152
+ - Removed authenticateAs
153
+ * Changes to `lib/webdriver.Options` (`driver.manage()`):
154
+ - Removed timeouts (use get/setTimeouts)
155
+ * Changes to `lib/webdriver.Window` (`driver.manage().window()`):
156
+ - Added
157
+ - getRect
158
+ - setRect
159
+ - fullscreen
160
+ - minimize
161
+ - Removed (use the getRect/setRect methods)
162
+ - getPosition
163
+ - setPosition
164
+ - getSize
165
+ - setSize
166
+ * Removed the `testing/assert` module
167
+ * Changes to `testing/index`
168
+ - Since the promise manager has been removed, it is no longer necessary to
169
+ wrap the Mocha test hooks; instead, users can simply use async functions.
170
+ The following have all been removed:
171
+ - describe
172
+ - before
173
+ - beforeEach
174
+ - after
175
+ - afterEach
176
+ - it
177
+ - Added the `suite` function. For details, refer to the jsdoc or
178
+ `example/google_search_test.js`
179
+
180
+
181
+
1
182
  ## v3.6.0
2
183
 
3
184
  ### Bug Fixes
package/README.md CHANGED
@@ -11,11 +11,11 @@ Selenium may be installed via npm with
11
11
  npm install selenium-webdriver
12
12
 
13
13
  You will need to download additional components to work with each of the major
14
- browsers. The drivers for Chrome, Firefox, PhantomJS, Opera, and
15
- Microsoft's IE and Edge web browsers are all standalone executables that should
16
- be placed on your system [PATH]. Apple's safaridriver is shipped with
17
- Safari 10 for OS X El Capitan and macOS Sierra. You will need to enable Remote
18
- Automation in the Develop menu of Safari 10 before testing.
14
+ browsers. The drivers for Chrome, Firefox, and Microsoft's IE and Edge web
15
+ browsers are all standalone executables that should be placed on your system
16
+ [PATH]. Apple's safaridriver is shipped with Safari 10 for OS X El Capitan and
17
+ macOS Sierra. You will need to enable Remote Automation in the Develop menu of
18
+ Safari 10 before testing.
19
19
 
20
20
 
21
21
  | Browser | Component |
@@ -24,8 +24,6 @@ Automation in the Develop menu of Safari 10 before testing.
24
24
  | Internet Explorer | [IEDriverServer.exe][release] |
25
25
  | Edge | [MicrosoftWebDriver.msi][edge] |
26
26
  | Firefox | [geckodriver(.exe)][geckodriver] |
27
- | PhantomJS | [phantomjs(.exe)][phantomjs] |
28
- | Opera | [operadriver(.exe)][opera] |
29
27
  | Safari | [safaridriver] |
30
28
 
31
29
  ## Usage
@@ -35,14 +33,16 @@ also find the tests for selenium-webdriver informative.
35
33
 
36
34
  const {Builder, By, Key, until} = require('selenium-webdriver');
37
35
 
38
- let driver = new Builder()
39
- .forBrowser('firefox')
40
- .build();
41
-
42
- driver.get('http://www.google.com/ncr');
43
- driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN);
44
- driver.wait(until.titleIs('webdriver - Google Search'), 1000);
45
- driver.quit();
36
+ (async function example() {
37
+ let driver = await new Builder().forBrowser('firefox').build();
38
+ try {
39
+ await driver.get('http://www.google.com/ncr');
40
+ await driver.findElement(By.name('q'));.sendKeys('webdriver', Key.RETURN);
41
+ await driver.wait(until.titleIs('webdriver - Google Search'), 1000);
42
+ } finally {
43
+ await driver.quit();
44
+ }
45
+ })();
46
46
 
47
47
  ### Using the Builder API
48
48
 
@@ -51,11 +51,11 @@ instances. Rather than clutter your code with branches for the various browsers,
51
51
  the builder lets you set all options in one flow. When you call
52
52
  `Builder#build()`, all options irrelevant to the selected browser are dropped:
53
53
 
54
- var webdriver = require('selenium-webdriver'),
55
- chrome = require('selenium-webdriver/chrome'),
56
- firefox = require('selenium-webdriver/firefox');
54
+ const webdriver = require('selenium-webdriver');
55
+ const chrome = require('selenium-webdriver/chrome');
56
+ const firefox = require('selenium-webdriver/firefox');
57
57
 
58
- var driver = new webdriver.Builder()
58
+ let driver = new webdriver.Builder()
59
59
  .forBrowser('firefox')
60
60
  .setChromeOptions(/* ... */)
61
61
  .setFirefoxOptions(/* ... */)
@@ -92,7 +92,7 @@ server with
92
92
  You may configure your tests to run against a remote server through the Builder
93
93
  API:
94
94
 
95
- var driver = new webdriver.Builder()
95
+ let driver = new webdriver.Builder()
96
96
  .forBrowser('firefox')
97
97
  .usingServer('http://localhost:4444/wd/hub')
98
98
  .build();
@@ -162,11 +162,11 @@ months, the support window for selenium-webdriver will be roughly:
162
162
 
163
163
  | Date | LTS | Stable |
164
164
  | --------- | ---: | -----: |
165
- | (current) | 6.9 | 7.5 |
166
- | 2017-04 | 6.0 | 8.0 |
167
- | 2017-10 | 8.0 | 9.0 |
168
- | 2018-04 | 8.0 | 10.0 |
169
- | 2018-10 | 10.0 | 11.0 |
165
+ | (current) | 8.9 | 9.0 |
166
+ | 2018-04 | 8.x | 10.0 |
167
+ | 2018-10 | 10.x | 11.0 |
168
+ | 2019-04 | 10.x | 12.0 |
169
+ | 2019-10 | 12.x | 13.0 |
170
170
 
171
171
  ## Issues
172
172
 
@@ -216,8 +216,6 @@ under the License.
216
216
  [chrome]: http://chromedriver.storage.googleapis.com/index.html
217
217
  [gh]: https://github.com/SeleniumHQ/selenium/
218
218
  [issues]: https://github.com/SeleniumHQ/selenium/issues
219
- [opera]: https://github.com/operasoftware/operachromiumdriver/releases
220
- [phantomjs]: http://phantomjs.org/
221
219
  [edge]: http://go.microsoft.com/fwlink/?LinkId=619687
222
220
  [geckodriver]: https://github.com/mozilla/geckodriver/releases/
223
221
  [reduction]: http://www.webkit.org/quality/reduction.html
package/chrome.js CHANGED
@@ -133,8 +133,9 @@ const util = require('util');
133
133
 
134
134
  const http = require('./http');
135
135
  const io = require('./io');
136
- const {Capabilities, Capability} = require('./lib/capabilities');
136
+ const {Browser, Capabilities, Capability} = require('./lib/capabilities');
137
137
  const command = require('./lib/command');
138
+ const error = require('./lib/error');
138
139
  const logging = require('./lib/logging');
139
140
  const promise = require('./lib/promise');
140
141
  const Symbols = require('./lib/symbols');
@@ -159,7 +160,8 @@ const CHROMEDRIVER_EXE =
159
160
  const Command = {
160
161
  LAUNCH_APP: 'launchApp',
161
162
  GET_NETWORK_CONDITIONS: 'getNetworkConditions',
162
- SET_NETWORK_CONDITIONS: 'setNetworkConditions'
163
+ SET_NETWORK_CONDITIONS: 'setNetworkConditions',
164
+ SEND_DEVTOOLS_COMMAND: 'sendDevToolsCommand',
163
165
  };
164
166
 
165
167
 
@@ -193,6 +195,21 @@ function configureExecutor(executor) {
193
195
  Command.SET_NETWORK_CONDITIONS,
194
196
  'POST',
195
197
  '/session/:sessionId/chromium/network_conditions');
198
+ executor.defineCommand(
199
+ Command.SEND_DEVTOOLS_COMMAND,
200
+ 'POST',
201
+ '/session/:sessionId/chromium/send_command');
202
+ }
203
+
204
+
205
+ /**
206
+ * _Synchronously_ attempts to locate the chromedriver executable on the current
207
+ * system.
208
+ *
209
+ * @return {?string} the located executable, or `null`.
210
+ */
211
+ function locateSynchronously() {
212
+ return io.findInPath(CHROMEDRIVER_EXE, true);
196
213
  }
197
214
 
198
215
 
@@ -210,7 +227,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
210
227
  * cannot be found on the PATH.
211
228
  */
212
229
  constructor(opt_exe) {
213
- let exe = opt_exe || io.findInPath(CHROMEDRIVER_EXE, true);
230
+ let exe = opt_exe || locateSynchronously();
214
231
  if (!exe) {
215
232
  throw Error(
216
233
  'The ChromeDriver could not be found on the current PATH. Please ' +
@@ -313,58 +330,19 @@ const OPTIONS_CAPABILITY_KEY = 'chromeOptions';
313
330
  /**
314
331
  * Class for managing ChromeDriver specific options.
315
332
  */
316
- class Options {
317
- constructor() {
318
- /** @private {!Object} */
319
- this.options_ = {};
320
-
321
- /** @private {!Array<(string|!Buffer)>} */
322
- this.extensions_ = [];
323
-
324
- /** @private {?logging.Preferences} */
325
- this.logPrefs_ = null;
326
-
327
- /** @private {?./lib/capabilities.ProxyConfig} */
328
- this.proxy_ = null;
329
- }
330
-
331
- /**
332
- * Extracts the ChromeDriver specific options from the given capabilities
333
- * object.
334
- * @param {!Capabilities} caps The capabilities object.
335
- * @return {!Options} The ChromeDriver options.
336
- */
337
- static fromCapabilities(caps) {
338
- let options = new Options();
339
-
340
- let o = caps.get(OPTIONS_CAPABILITY_KEY);
341
- if (o instanceof Options) {
342
- options = o;
343
- } else if (o) {
344
- options.
345
- addArguments(o.args || []).
346
- addExtensions(o.extensions || []).
347
- detachDriver(o.detach).
348
- excludeSwitches(o.excludeSwitches || []).
349
- setChromeBinaryPath(o.binary).
350
- setChromeLogFile(o.logPath).
351
- setChromeMinidumpPath(o.minidumpPath).
352
- setLocalState(o.localState).
353
- setMobileEmulation(o.mobileEmulation).
354
- setUserPreferences(o.prefs).
355
- setPerfLoggingPrefs(o.perfLoggingPrefs);
356
- }
357
-
358
- if (caps.has(Capability.PROXY)) {
359
- options.setProxy(caps.get(Capability.PROXY));
360
- }
333
+ class Options extends Capabilities {
334
+ /**
335
+ * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
336
+ * capabilities to initialize this instance from.
337
+ */
338
+ constructor(other = undefined) {
339
+ super(other);
361
340
 
362
- if (caps.has(Capability.LOGGING_PREFS)) {
363
- options.setLoggingPrefs(
364
- caps.get(Capability.LOGGING_PREFS));
365
- }
341
+ /** @private {!Object} */
342
+ this.options_ = this.get(OPTIONS_CAPABILITY_KEY) || {};
366
343
 
367
- return options;
344
+ this.setBrowserName(Browser.CHROME);
345
+ this.set(OPTIONS_CAPABILITY_KEY, this.options_);
368
346
  }
369
347
 
370
348
  /**
@@ -391,6 +369,12 @@ class Options {
391
369
  * > in Chrome 60. Users are encouraged to set an initial window size with
392
370
  * > the {@link #windowSize windowSize({width, height})} option.
393
371
  *
372
+ * > __NOTE__: For security, Chrome disables downloads by default when
373
+ * > in headless mode (to prevent sites from silently downloading files to
374
+ * > your machine). After creating a session, you may call
375
+ * > {@link ./chrome.Driver#setDownloadPath setDownloadPath} to re-enable
376
+ * > downloads, saving files in the specified directory.
377
+ *
394
378
  * @return {!Options} A self reference.
395
379
  */
396
380
  headless() {
@@ -442,7 +426,8 @@ class Options {
442
426
  * @return {!Options} A self reference.
443
427
  */
444
428
  addExtensions(...args) {
445
- this.extensions_ = this.extensions_.concat(...args);
429
+ let current = this.options_.extensions || [];
430
+ this.options_.extensions = current.concat(...args);
446
431
  return this;
447
432
  }
448
433
 
@@ -486,16 +471,6 @@ class Options {
486
471
  return this;
487
472
  }
488
473
 
489
- /**
490
- * Sets the logging preferences for the new session.
491
- * @param {!logging.Preferences} prefs The logging preferences.
492
- * @return {!Options} A self reference.
493
- */
494
- setLoggingPrefs(prefs) {
495
- this.logPrefs_ = prefs;
496
- return this;
497
- }
498
-
499
474
  /**
500
475
  * Sets the performance logging preferences. Options include:
501
476
  *
@@ -673,54 +648,25 @@ class Options {
673
648
  return this;
674
649
  }
675
650
 
676
- /**
677
- * Sets the proxy settings for the new session.
678
- * @param {./lib/capabilities.ProxyConfig} proxy The proxy configuration to
679
- * use.
680
- * @return {!Options} A self reference.
681
- */
682
- setProxy(proxy) {
683
- this.proxy_ = proxy;
684
- return this;
685
- }
686
-
687
- /**
688
- * Converts this options instance to a {@link Capabilities} object.
689
- * @param {Capabilities=} opt_capabilities The capabilities to merge
690
- * these options into, if any.
691
- * @return {!Capabilities} The capabilities.
692
- */
693
- toCapabilities(opt_capabilities) {
694
- let caps = opt_capabilities || Capabilities.chrome();
695
- caps.
696
- set(Capability.PROXY, this.proxy_).
697
- set(Capability.LOGGING_PREFS, this.logPrefs_).
698
- set(OPTIONS_CAPABILITY_KEY, this);
699
- return caps;
700
- }
701
-
702
651
  /**
703
652
  * Converts this instance to its JSON wire protocol representation. Note this
704
653
  * function is an implementation not intended for general use.
654
+ *
705
655
  * @return {!Object} The JSON wire protocol representation of this instance.
656
+ * @suppress {checkTypes} Suppress [] access on a struct.
706
657
  */
707
658
  [Symbols.serialize]() {
708
- let json = {};
709
- for (let key in this.options_) {
710
- if (this.options_[key] != null) {
711
- json[key] = this.options_[key];
712
- }
713
- }
714
- if (this.extensions_.length) {
715
- json.extensions = this.extensions_.map(function(extension) {
716
- if (Buffer.isBuffer(extension)) {
717
- return extension.toString('base64');
718
- }
719
- return io.read(/** @type {string} */(extension))
720
- .then(buffer => buffer.toString('base64'));
721
- });
659
+ if (this.options_.extensions && this.options_.extensions.length) {
660
+ this.options_.extensions =
661
+ this.options_.extensions.map(function(extension) {
662
+ if (Buffer.isBuffer(extension)) {
663
+ return extension.toString('base64');
664
+ }
665
+ return io.read(/** @type {string} */(extension))
666
+ .then(buffer => buffer.toString('base64'));
667
+ });
722
668
  }
723
- return json;
669
+ return super[Symbols.serialize]();
724
670
  }
725
671
  }
726
672
 
@@ -739,11 +685,9 @@ class Driver extends webdriver.WebDriver {
739
685
  * for an externally managed endpoint. If neither is provided, the
740
686
  * {@linkplain ##getDefaultService default service} will be used by
741
687
  * default.
742
- * @param {promise.ControlFlow=} opt_flow The control flow to use, or `null`
743
- * to use the currently active flow.
744
688
  * @return {!Driver} A new driver instance.
745
689
  */
746
- static createSession(opt_config, opt_serviceExecutor, opt_flow) {
690
+ static createSession(opt_config, opt_serviceExecutor) {
747
691
  let executor;
748
692
  if (opt_serviceExecutor instanceof http.Executor) {
749
693
  executor = opt_serviceExecutor;
@@ -753,12 +697,19 @@ class Driver extends webdriver.WebDriver {
753
697
  executor = createExecutor(service.start());
754
698
  }
755
699
 
756
- let caps =
757
- opt_config instanceof Options ? opt_config.toCapabilities() :
758
- (opt_config || Capabilities.chrome());
700
+ let caps = opt_config || Capabilities.chrome();
701
+
702
+ // W3C spec requires noProxy value to be an array of strings, but Chrome
703
+ // expects a single host as a string.
704
+ let proxy = caps.get(Capability.PROXY);
705
+ if (proxy && Array.isArray(proxy.noProxy)) {
706
+ proxy.noProxy = proxy.noProxy[0];
707
+ if (!proxy.noProxy) {
708
+ proxy.noProxy = undefined;
709
+ }
710
+ }
759
711
 
760
- return /** @type {!Driver} */(
761
- super.createSession(executor, caps, opt_flow));
712
+ return /** @type {!Driver} */(super.createSession(executor, caps));
762
713
  }
763
714
 
764
715
  /**
@@ -771,24 +722,21 @@ class Driver extends webdriver.WebDriver {
771
722
  /**
772
723
  * Schedules a command to launch Chrome App with given ID.
773
724
  * @param {string} id ID of the App to launch.
774
- * @return {!promise.Thenable<void>} A promise that will be resolved
725
+ * @return {!Promise<void>} A promise that will be resolved
775
726
  * when app is launched.
776
727
  */
777
728
  launchApp(id) {
778
- return this.schedule(
779
- new command.Command(Command.LAUNCH_APP).setParameter('id', id),
780
- 'Driver.launchApp()');
729
+ return this.execute(
730
+ new command.Command(Command.LAUNCH_APP).setParameter('id', id));
781
731
  }
782
732
 
783
733
  /**
784
734
  * Schedules a command to get Chrome network emulation settings.
785
- * @return {!promise.Thenable<T>} A promise that will be resolved
786
- * when network emulation settings are retrievied.
735
+ * @return {!Promise} A promise that will be resolved when network
736
+ * emulation settings are retrievied.
787
737
  */
788
738
  getNetworkConditions() {
789
- return this.schedule(
790
- new command.Command(Command.GET_NETWORK_CONDITIONS),
791
- 'Driver.getNetworkConditions()');
739
+ return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS));
792
740
  }
793
741
 
794
742
  /**
@@ -804,17 +752,54 @@ class Driver extends webdriver.WebDriver {
804
752
  * });
805
753
  *
806
754
  * @param {Object} spec Defines the network conditions to set
807
- * @return {!promise.Thenable<void>} A promise that will be resolved
808
- * when network emulation settings are set.
755
+ * @return {!Promise<void>} A promise that will be resolved when network
756
+ * emulation settings are set.
809
757
  */
810
758
  setNetworkConditions(spec) {
811
759
  if (!spec || typeof spec !== 'object') {
812
760
  throw TypeError('setNetworkConditions called with non-network-conditions parameter');
813
761
  }
762
+ return this.execute(
763
+ new command.Command(Command.SET_NETWORK_CONDITIONS)
764
+ .setParameter('network_conditions', spec));
765
+ }
766
+
767
+ /**
768
+ * Sends an arbitrary devtools command to the browser.
769
+ *
770
+ * @param {string} cmd The name of the command to send.
771
+ * @param {Object=} params The command parameters.
772
+ * @return {!Promise<void>} A promise that will be resolved when the command
773
+ * has finished.
774
+ * @see <https://chromedevtools.github.io/devtools-protocol/>
775
+ */
776
+ sendDevToolsCommand(cmd, params = {}) {
777
+ return this.execute(
778
+ new command.Command(Command.SEND_DEVTOOLS_COMMAND)
779
+ .setParameter('cmd', cmd)
780
+ .setParameter('params', params));
781
+ }
814
782
 
815
- return this.schedule(
816
- new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter('network_conditions', spec),
817
- 'Driver.setNetworkConditions(' + JSON.stringify(spec) + ')');
783
+ /**
784
+ * Sends a DevTools command to change Chrome's download directory.
785
+ *
786
+ * @param {string} path The desired download directory.
787
+ * @return {!Promise<void>} A promise that will be resolved when the command
788
+ * has finished.
789
+ * @see #sendDevToolsCommand
790
+ */
791
+ async setDownloadPath(path) {
792
+ if (!path || typeof path !== 'string') {
793
+ throw new error.InvalidArgumentError('invalid download path');
794
+ }
795
+ const stat = await io.stat(path);
796
+ if (!stat.isDirectory()) {
797
+ throw new error.InvalidArgumentError('not a directory: ' + path);
798
+ }
799
+ return this.sendDevToolsCommand('Page.setDownloadBehavior', {
800
+ 'behavior': 'allow',
801
+ 'downloadPath': path
802
+ });
818
803
  }
819
804
  }
820
805
 
@@ -827,3 +812,4 @@ exports.Options = Options;
827
812
  exports.ServiceBuilder = ServiceBuilder;
828
813
  exports.getDefaultService = getDefaultService;
829
814
  exports.setDefaultService = setDefaultService;
815
+ exports.locateSynchronously = locateSynchronously;