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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGES.md +35 -1
  2. package/LICENSE +1 -1
  3. package/NOTICE +1 -1
  4. package/README.md +4 -4
  5. package/chrome.js +72 -592
  6. package/chromium.js +829 -0
  7. package/devtools/CDPConnection.js +37 -0
  8. package/edge.js +124 -86
  9. package/example/chrome_android.js +16 -13
  10. package/example/chrome_mobile_emulation.js +18 -14
  11. package/example/firefox_channels.js +35 -28
  12. package/example/google_search.js +9 -9
  13. package/example/google_search_test.js +20 -22
  14. package/example/headless.js +27 -19
  15. package/example/logging.js +34 -38
  16. package/firefox.js +200 -200
  17. package/http/index.js +131 -115
  18. package/http/util.js +56 -64
  19. package/ie.js +180 -104
  20. package/index.js +246 -199
  21. package/io/exec.js +34 -39
  22. package/io/index.js +142 -152
  23. package/io/zip.js +75 -65
  24. package/lib/actions.js +140 -122
  25. package/lib/atoms/find-elements.js +124 -0
  26. package/lib/atoms/get-attribute.js +79 -59
  27. package/lib/atoms/is-displayed.js +72 -73
  28. package/lib/atoms/mutation-listener.js +38 -0
  29. package/lib/by.js +192 -65
  30. package/lib/capabilities.js +82 -78
  31. package/lib/command.js +20 -20
  32. package/lib/error.js +134 -168
  33. package/lib/http.js +337 -230
  34. package/lib/input.js +325 -302
  35. package/lib/logging.js +127 -138
  36. package/lib/promise.js +60 -66
  37. package/lib/proxy.js +31 -41
  38. package/lib/session.js +12 -15
  39. package/lib/symbols.js +3 -4
  40. package/lib/until.js +162 -160
  41. package/lib/webdriver.js +1024 -541
  42. package/net/index.js +30 -36
  43. package/net/portprober.js +31 -144
  44. package/opera.js +406 -0
  45. package/package.json +19 -12
  46. package/proxy.js +2 -2
  47. package/remote/index.js +190 -187
  48. package/safari.js +40 -49
  49. package/testing/index.js +166 -155
package/chromium.js ADDED
@@ -0,0 +1,829 @@
1
+ // Licensed to the Software Freedom Conservancy (SFC) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The SFC licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ /**
19
+ * @fileoverview Defines an abstract {@linkplain Driver WebDriver} client for
20
+ * Chromium-based web browsers. These classes should not be instantiated
21
+ * directly.
22
+ *
23
+ * There are three primary classes exported by this module:
24
+ *
25
+ * 1. {@linkplain ServiceBuilder}: configures the
26
+ * {@link selenium-webdriver/remote.DriverService remote.DriverService}
27
+ * that manages a WebDriver server child process.
28
+ *
29
+ * 2. {@linkplain Options}: defines configuration options for each new Chromium
30
+ * session, such as which {@linkplain Options#setProxy proxy} to use,
31
+ * what {@linkplain Options#addExtensions extensions} to install, or
32
+ * what {@linkplain Options#addArguments command-line switches} to use when
33
+ * starting the browser.
34
+ *
35
+ * 3. {@linkplain Driver}: the WebDriver client; each new instance will control
36
+ * a unique browser session with a clean user profile (unless otherwise
37
+ * configured through the {@link Options} class).
38
+ *
39
+ * __Headless Chromium__ <a id="headless"></a>
40
+ *
41
+ * To start the browser in headless mode, simply call
42
+ * {@linkplain Options#headless Options.headless()}.
43
+ *
44
+ * let chrome = require('selenium-webdriver/chrome');
45
+ * let {Builder} = require('selenium-webdriver');
46
+ *
47
+ * let driver = new Builder()
48
+ * .forBrowser('chrome')
49
+ * .setChromeOptions(new chrome.Options().headless())
50
+ * .build();
51
+ *
52
+ * __Customizing the Chromium WebDriver Server__ <a id="custom-server"></a>
53
+ *
54
+ * Subclasses of {@link Driver} are expected to provide a static
55
+ * getDefaultService method. By default, this method will be called every time
56
+ * a {@link Driver} instance is created to obtain the default driver service
57
+ * for that specific browser (e.g. Chrome or Chromium Edge). Subclasses are
58
+ * responsible for managing the lifetime of the default service.
59
+ *
60
+ * You may also create a {@link Driver} with its own driver service. This is
61
+ * useful if you need to capture the server's log output for a specific session:
62
+ *
63
+ * let chrome = require('selenium-webdriver/chrome');
64
+ *
65
+ * let service = new chrome.ServiceBuilder()
66
+ * .loggingTo('/my/log/file.txt')
67
+ * .enableVerboseLogging()
68
+ * .build();
69
+ *
70
+ * let options = new chrome.Options();
71
+ * // configure browser options ...
72
+ *
73
+ * let driver = chrome.Driver.createSession(options, service);
74
+ */
75
+
76
+ 'use strict'
77
+
78
+ const http = require('./http')
79
+ const io = require('./io')
80
+ const { Capabilities, Capability } = require('./lib/capabilities')
81
+ const command = require('./lib/command')
82
+ const error = require('./lib/error')
83
+ const Symbols = require('./lib/symbols')
84
+ const webdriver = require('./lib/webdriver')
85
+ const remote = require('./remote')
86
+
87
+ /**
88
+ * Custom command names supported by Chromium WebDriver.
89
+ * @enum {string}
90
+ */
91
+ const Command = {
92
+ LAUNCH_APP: 'launchApp',
93
+ GET_NETWORK_CONDITIONS: 'getNetworkConditions',
94
+ SET_NETWORK_CONDITIONS: 'setNetworkConditions',
95
+ SEND_DEVTOOLS_COMMAND: 'sendDevToolsCommand',
96
+ SEND_AND_GET_DEVTOOLS_COMMAND: 'sendAndGetDevToolsCommand',
97
+ SET_PERMISSION: 'setPermission',
98
+ GET_CAST_SINKS: 'getCastSinks',
99
+ SET_CAST_SINK_TO_USE: 'setCastSinkToUse',
100
+ START_CAST_TAB_MIRRORING: 'setCastTabMirroring',
101
+ GET_CAST_ISSUE_MESSAGE: 'getCastIssueMessage',
102
+ STOP_CASTING: 'stopCasting',
103
+ }
104
+
105
+ /**
106
+ * Creates a command executor with support for Chromium's custom commands.
107
+ * @param {!Promise<string>} url The server's URL.
108
+ * @return {!command.Executor} The new command executor.
109
+ */
110
+ function createExecutor(url, vendorPrefix) {
111
+ const agent = new http.Agent({ keepAlive: true })
112
+ const client = url.then((url) => new http.HttpClient(url, agent))
113
+ const executor = new http.Executor(client)
114
+ configureExecutor(executor, vendorPrefix)
115
+ return executor
116
+ }
117
+
118
+ /**
119
+ * Configures the given executor with Chromium-specific commands.
120
+ * @param {!http.Executor} executor the executor to configure.
121
+ */
122
+ function configureExecutor(executor, vendorPrefix) {
123
+ executor.defineCommand(
124
+ Command.LAUNCH_APP,
125
+ 'POST',
126
+ '/session/:sessionId/chromium/launch_app'
127
+ )
128
+ executor.defineCommand(
129
+ Command.GET_NETWORK_CONDITIONS,
130
+ 'GET',
131
+ '/session/:sessionId/chromium/network_conditions'
132
+ )
133
+ executor.defineCommand(
134
+ Command.SET_NETWORK_CONDITIONS,
135
+ 'POST',
136
+ '/session/:sessionId/chromium/network_conditions'
137
+ )
138
+ executor.defineCommand(
139
+ Command.SEND_DEVTOOLS_COMMAND,
140
+ 'POST',
141
+ '/session/:sessionId/chromium/send_command'
142
+ )
143
+ executor.defineCommand(
144
+ Command.SEND_AND_GET_DEVTOOLS_COMMAND,
145
+ 'POST',
146
+ '/session/:sessionId/chromium/send_command_and_get_result'
147
+ )
148
+ executor.defineCommand(
149
+ Command.SET_PERMISSION,
150
+ 'POST',
151
+ '/session/:sessionId/permissions'
152
+ )
153
+ executor.defineCommand(
154
+ Command.GET_CAST_SINKS,
155
+ 'GET',
156
+ `/session/:sessionId/${vendorPrefix}/cast/get_sinks`
157
+ )
158
+ executor.defineCommand(
159
+ Command.SET_CAST_SINK_TO_USE,
160
+ 'POST',
161
+ `/session/:sessionId/${vendorPrefix}/cast/set_sink_to_use`
162
+ )
163
+ executor.defineCommand(
164
+ Command.START_CAST_TAB_MIRRORING,
165
+ 'POST',
166
+ `/session/:sessionId/${vendorPrefix}/cast/start_tab_mirroring`
167
+ )
168
+ executor.defineCommand(
169
+ Command.GET_CAST_ISSUE_MESSAGE,
170
+ 'GET',
171
+ `/session/:sessionId/${vendorPrefix}/cast/get_issue_message`
172
+ )
173
+ executor.defineCommand(
174
+ Command.STOP_CASTING,
175
+ 'POST',
176
+ `/session/:sessionId/${vendorPrefix}/cast/stop_casting`
177
+ )
178
+ }
179
+
180
+ /**
181
+ * Creates {@link selenium-webdriver/remote.DriverService} instances that manage
182
+ * a WebDriver server in a child process.
183
+ */
184
+ class ServiceBuilder extends remote.DriverService.Builder {
185
+ /**
186
+ * @param {string=} exe Path to the server executable to use. Subclasses
187
+ * should ensure a valid path to the appropriate exe is provided.
188
+ */
189
+ constructor(exe) {
190
+ super(exe)
191
+ this.setLoopback(true) // Required
192
+ }
193
+
194
+ /**
195
+ * Sets which port adb is listening to. _The driver will connect to adb
196
+ * if an {@linkplain Options#androidPackage Android session} is requested, but
197
+ * adb **must** be started beforehand._
198
+ *
199
+ * @param {number} port Which port adb is running on.
200
+ * @return {!ServiceBuilder} A self reference.
201
+ */
202
+ setAdbPort(port) {
203
+ return this.addArguments('--adb-port=' + port)
204
+ }
205
+
206
+ /**
207
+ * Sets the path of the log file the driver should log to. If a log file is
208
+ * not specified, the driver will log to stderr.
209
+ * @param {string} path Path of the log file to use.
210
+ * @return {!ServiceBuilder} A self reference.
211
+ */
212
+ loggingTo(path) {
213
+ return this.addArguments('--log-path=' + path)
214
+ }
215
+
216
+ /**
217
+ * Enables verbose logging.
218
+ * @return {!ServiceBuilder} A self reference.
219
+ */
220
+ enableVerboseLogging() {
221
+ return this.addArguments('--verbose')
222
+ }
223
+
224
+ /**
225
+ * Sets the number of threads the driver should use to manage HTTP requests.
226
+ * By default, the driver will use 4 threads.
227
+ * @param {number} n The number of threads to use.
228
+ * @return {!ServiceBuilder} A self reference.
229
+ */
230
+ setNumHttpThreads(n) {
231
+ return this.addArguments('--http-threads=' + n)
232
+ }
233
+
234
+ /**
235
+ * @override
236
+ */
237
+ setPath(path) {
238
+ super.setPath(path)
239
+ return this.addArguments('--url-base=' + path)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Class for managing WebDriver options specific to a Chromium-based browser.
245
+ */
246
+ class Options extends Capabilities {
247
+ /**
248
+ * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
249
+ * capabilities to initialize this instance from.
250
+ */
251
+ constructor(other = undefined) {
252
+ super(other)
253
+
254
+ /** @private {!Object} */
255
+ this.options_ = this.get(this.CAPABILITY_KEY) || {}
256
+
257
+ this.setBrowserName(this.BROWSER_NAME_VALUE)
258
+ this.set(this.CAPABILITY_KEY, this.options_)
259
+ }
260
+
261
+ /**
262
+ * Add additional command line arguments to use when launching the browser.
263
+ * Each argument may be specified with or without the "--" prefix
264
+ * (e.g. "--foo" and "foo"). Arguments with an associated value should be
265
+ * delimited by an "=": "foo=bar".
266
+ *
267
+ * @param {...(string|!Array<string>)} args The arguments to add.
268
+ * @return {!Options} A self reference.
269
+ */
270
+ addArguments(...args) {
271
+ let newArgs = (this.options_.args || []).concat(...args)
272
+ if (newArgs.length) {
273
+ this.options_.args = newArgs
274
+ }
275
+ return this
276
+ }
277
+
278
+ /**
279
+ * Configures the driver to start the browser in headless mode.
280
+ *
281
+ * > __NOTE:__ Resizing the browser window in headless mode is only supported
282
+ * > in Chromium 60+. Users are encouraged to set an initial window size with
283
+ * > the {@link #windowSize windowSize({width, height})} option.
284
+ *
285
+ * > __NOTE__: For security, Chromium disables downloads by default when
286
+ * > in headless mode (to prevent sites from silently downloading files to
287
+ * > your machine). After creating a session, you may call
288
+ * > {@link ./chrome.Driver#setDownloadPath setDownloadPath} to re-enable
289
+ * > downloads, saving files in the specified directory.
290
+ *
291
+ * @return {!Options} A self reference.
292
+ */
293
+ headless() {
294
+ return this.addArguments('headless')
295
+ }
296
+
297
+ /**
298
+ * Sets the initial window size.
299
+ *
300
+ * @param {{width: number, height: number}} size The desired window size.
301
+ * @return {!Options} A self reference.
302
+ * @throws {TypeError} if width or height is unspecified, not a number, or
303
+ * less than or equal to 0.
304
+ */
305
+ windowSize({ width, height }) {
306
+ function checkArg(arg) {
307
+ if (typeof arg !== 'number' || arg <= 0) {
308
+ throw TypeError('Arguments must be {width, height} with numbers > 0')
309
+ }
310
+ }
311
+ checkArg(width)
312
+ checkArg(height)
313
+ return this.addArguments(`window-size=${width},${height}`)
314
+ }
315
+
316
+ /**
317
+ * List of Chrome command line switches to exclude that ChromeDriver by default
318
+ * passes when starting Chrome. Do not prefix switches with "--".
319
+ *
320
+ * @param {...(string|!Array<string>)} args The switches to exclude.
321
+ * @return {!Options} A self reference.
322
+ */
323
+ excludeSwitches(...args) {
324
+ let switches = (this.options_.excludeSwitches || []).concat(...args)
325
+ if (switches.length) {
326
+ this.options_.excludeSwitches = switches
327
+ }
328
+ return this
329
+ }
330
+
331
+ /**
332
+ * Add additional extensions to install when launching the browser. Each extension
333
+ * should be specified as the path to the packed CRX file, or a Buffer for an
334
+ * extension.
335
+ * @param {...(string|!Buffer|!Array<(string|!Buffer)>)} args The
336
+ * extensions to add.
337
+ * @return {!Options} A self reference.
338
+ */
339
+ addExtensions(...args) {
340
+ let current = this.options_.extensions || []
341
+ this.options_.extensions = current.concat(...args)
342
+ return this
343
+ }
344
+
345
+ /**
346
+ * Sets the path to the browser binary to use. On Mac OS X, this path should
347
+ * reference the actual Chromium executable, not just the application binary
348
+ * (e.g. "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").
349
+ *
350
+ * The binary path can be absolute or relative to the WebDriver server
351
+ * executable, but it must exist on the machine that will launch the browser.
352
+ *
353
+ * @param {string} path The path to the browser binary to use.
354
+ * @return {!Options} A self reference.
355
+ */
356
+ setBinaryPath(path) {
357
+ this.options_.binary = path
358
+ return this
359
+ }
360
+
361
+ /**
362
+ * Sets whether to leave the started browser process running if the controlling
363
+ * driver service is killed before {@link webdriver.WebDriver#quit()} is
364
+ * called.
365
+ * @param {boolean} detach Whether to leave the browser running if the
366
+ * driver service is killed before the session.
367
+ * @return {!Options} A self reference.
368
+ */
369
+ detachDriver(detach) {
370
+ this.options_.detach = detach
371
+ return this
372
+ }
373
+
374
+ /**
375
+ * Sets the user preferences for Chrome's user profile. See the "Preferences"
376
+ * file in Chrome's user data directory for examples.
377
+ * @param {!Object} prefs Dictionary of user preferences to use.
378
+ * @return {!Options} A self reference.
379
+ */
380
+ setUserPreferences(prefs) {
381
+ this.options_.prefs = prefs
382
+ return this
383
+ }
384
+
385
+ /**
386
+ * Sets the performance logging preferences. Options include:
387
+ *
388
+ * - `enableNetwork`: Whether or not to collect events from Network domain.
389
+ * - `enablePage`: Whether or not to collect events from Page domain.
390
+ * - `enableTimeline`: Whether or not to collect events from Timeline domain.
391
+ * Note: when tracing is enabled, Timeline domain is implicitly disabled,
392
+ * unless `enableTimeline` is explicitly set to true.
393
+ * - `traceCategories`: A comma-separated string of Chromium tracing
394
+ * categories for which trace events should be collected. An unspecified
395
+ * or empty string disables tracing.
396
+ * - `bufferUsageReportingInterval`: The requested number of milliseconds
397
+ * between DevTools trace buffer usage events. For example, if 1000, then
398
+ * once per second, DevTools will report how full the trace buffer is. If
399
+ * a report indicates the buffer usage is 100%, a warning will be issued.
400
+ *
401
+ * @param {{enableNetwork: boolean,
402
+ * enablePage: boolean,
403
+ * enableTimeline: boolean,
404
+ * traceCategories: string,
405
+ * bufferUsageReportingInterval: number}} prefs The performance
406
+ * logging preferences.
407
+ * @return {!Options} A self reference.
408
+ */
409
+ setPerfLoggingPrefs(prefs) {
410
+ this.options_.perfLoggingPrefs = prefs
411
+ return this
412
+ }
413
+
414
+ /**
415
+ * Sets preferences for the "Local State" file in Chrome's user data
416
+ * directory.
417
+ * @param {!Object} state Dictionary of local state preferences.
418
+ * @return {!Options} A self reference.
419
+ */
420
+ setLocalState(state) {
421
+ this.options_.localState = state
422
+ return this
423
+ }
424
+
425
+ /**
426
+ * Sets the name of the activity hosting a Chrome-based Android WebView. This
427
+ * option must be set to connect to an [Android WebView](
428
+ * https://chromedriver.chromium.org/getting-started/getting-started---android)
429
+ *
430
+ * @param {string} name The activity name.
431
+ * @return {!Options} A self reference.
432
+ */
433
+ androidActivity(name) {
434
+ this.options_.androidActivity = name
435
+ return this
436
+ }
437
+
438
+ /**
439
+ * Sets the device serial number to connect to via ADB. If not specified, the
440
+ * WebDriver server will select an unused device at random. An error will be
441
+ * returned if all devices already have active sessions.
442
+ *
443
+ * @param {string} serial The device serial number to connect to.
444
+ * @return {!Options} A self reference.
445
+ */
446
+ androidDeviceSerial(serial) {
447
+ this.options_.androidDeviceSerial = serial
448
+ return this
449
+ }
450
+
451
+ /**
452
+ * Sets the package name of the Chrome or WebView app.
453
+ *
454
+ * @param {?string} pkg The package to connect to, or `null` to disable Android
455
+ * and switch back to using desktop browser.
456
+ * @return {!Options} A self reference.
457
+ */
458
+ androidPackage(pkg) {
459
+ this.options_.androidPackage = pkg
460
+ return this
461
+ }
462
+
463
+ /**
464
+ * Sets the process name of the Activity hosting the WebView (as given by
465
+ * `ps`). If not specified, the process name is assumed to be the same as
466
+ * {@link #androidPackage}.
467
+ *
468
+ * @param {string} processName The main activity name.
469
+ * @return {!Options} A self reference.
470
+ */
471
+ androidProcess(processName) {
472
+ this.options_.androidProcess = processName
473
+ return this
474
+ }
475
+
476
+ /**
477
+ * Sets whether to connect to an already-running instead of the specified
478
+ * {@linkplain #androidProcess app} instead of launching the app with a clean
479
+ * data directory.
480
+ *
481
+ * @param {boolean} useRunning Whether to connect to a running instance.
482
+ * @return {!Options} A self reference.
483
+ */
484
+ androidUseRunningApp(useRunning) {
485
+ this.options_.androidUseRunningApp = useRunning
486
+ return this
487
+ }
488
+
489
+ /**
490
+ * Sets the path to the browser's log file. This path should exist on the machine
491
+ * that will launch the browser.
492
+ * @param {string} path Path to the log file to use.
493
+ * @return {!Options} A self reference.
494
+ */
495
+ setBrowserLogFile(path) {
496
+ this.options_.logPath = path
497
+ return this
498
+ }
499
+
500
+ /**
501
+ * Sets the directory to store browser minidumps in. This option is only
502
+ * supported when the driver is running on Linux.
503
+ * @param {string} path The directory path.
504
+ * @return {!Options} A self reference.
505
+ */
506
+ setBrowserMinidumpPath(path) {
507
+ this.options_.minidumpPath = path
508
+ return this
509
+ }
510
+
511
+ /**
512
+ * Configures the browser to emulate a mobile device. For more information, refer
513
+ * to the ChromeDriver project page on [mobile emulation][em]. Configuration
514
+ * options include:
515
+ *
516
+ * - `deviceName`: The name of a pre-configured [emulated device][devem]
517
+ * - `width`: screen width, in pixels
518
+ * - `height`: screen height, in pixels
519
+ * - `pixelRatio`: screen pixel ratio
520
+ *
521
+ * __Example 1: Using a Pre-configured Device__
522
+ *
523
+ * let options = new chrome.Options().setMobileEmulation(
524
+ * {deviceName: 'Google Nexus 5'});
525
+ *
526
+ * let driver = chrome.Driver.createSession(options);
527
+ *
528
+ * __Example 2: Using Custom Screen Configuration__
529
+ *
530
+ * let options = new chrome.Options().setMobileEmulation({deviceMetrics: {
531
+ * width: 360,
532
+ * height: 640,
533
+ * pixelRatio: 3.0
534
+ * }});
535
+ *
536
+ * let driver = chrome.Driver.createSession(options);
537
+ *
538
+ *
539
+ * [em]: https://chromedriver.chromium.org/mobile-emulation
540
+ * [devem]: https://developer.chrome.com/devtools/docs/device-mode
541
+ *
542
+ * @param {?({deviceName: string}|
543
+ * {width: number, height: number, pixelRatio: number})} config The
544
+ * mobile emulation configuration, or `null` to disable emulation.
545
+ * @return {!Options} A self reference.
546
+ */
547
+ setMobileEmulation(config) {
548
+ this.options_.mobileEmulation = config
549
+ return this
550
+ }
551
+
552
+ /**
553
+ * Converts this instance to its JSON wire protocol representation. Note this
554
+ * function is an implementation not intended for general use.
555
+ *
556
+ * @return {!Object} The JSON wire protocol representation of this instance.
557
+ * @suppress {checkTypes} Suppress [] access on a struct.
558
+ */
559
+ [Symbols.serialize]() {
560
+ if (this.options_.extensions && this.options_.extensions.length) {
561
+ this.options_.extensions = this.options_.extensions.map(function (
562
+ extension
563
+ ) {
564
+ if (Buffer.isBuffer(extension)) {
565
+ return extension.toString('base64')
566
+ }
567
+ return io
568
+ .read(/** @type {string} */(extension))
569
+ .then((buffer) => buffer.toString('base64'))
570
+ })
571
+ }
572
+ return super[Symbols.serialize]()
573
+ }
574
+ }
575
+
576
+ /**
577
+ * Creates a new WebDriver client for Chromium-based browsers.
578
+ */
579
+ class Driver extends webdriver.WebDriver {
580
+ /**
581
+ * Creates a new session with the WebDriver server.
582
+ *
583
+ * @param {(Capabilities|Options)=} opt_config The configuration options.
584
+ * @param {(remote.DriverService|http.Executor)=} opt_serviceExecutor Either
585
+ * a DriverService to use for the remote end, or a preconfigured executor
586
+ * for an externally managed endpoint. If neither is provided, the
587
+ * {@linkplain ##getDefaultService default service} will be used by
588
+ * default.
589
+ * @return {!Driver} A new driver instance.
590
+ */
591
+ static createSession(caps, opt_serviceExecutor) {
592
+ let executor
593
+ let onQuit
594
+ if (opt_serviceExecutor instanceof http.Executor) {
595
+ executor = opt_serviceExecutor
596
+ configureExecutor(executor, this.VENDOR_COMMAND_PREFIX)
597
+ } else {
598
+ let service = opt_serviceExecutor || this.getDefaultService()
599
+ executor = createExecutor(service.start(), this.VENDOR_COMMAND_PREFIX)
600
+ onQuit = () => service.kill()
601
+ }
602
+
603
+ // W3C spec requires noProxy value to be an array of strings, but Chromium
604
+ // expects a single host as a string.
605
+ let proxy = caps.get(Capability.PROXY)
606
+ if (proxy && Array.isArray(proxy.noProxy)) {
607
+ proxy.noProxy = proxy.noProxy[0]
608
+ if (!proxy.noProxy) {
609
+ proxy.noProxy = undefined
610
+ }
611
+ }
612
+
613
+ return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit))
614
+ }
615
+
616
+ /**
617
+ * This function is a no-op as file detectors are not supported by this
618
+ * implementation.
619
+ * @override
620
+ */
621
+ setFileDetector() { }
622
+
623
+ /**
624
+ * Schedules a command to launch Chrome App with given ID.
625
+ * @param {string} id ID of the App to launch.
626
+ * @return {!Promise<void>} A promise that will be resolved
627
+ * when app is launched.
628
+ */
629
+ launchApp(id) {
630
+ return this.execute(
631
+ new command.Command(Command.LAUNCH_APP).setParameter('id', id)
632
+ )
633
+ }
634
+
635
+ /**
636
+ * Schedules a command to get Chromium network emulation settings.
637
+ * @return {!Promise} A promise that will be resolved when network
638
+ * emulation settings are retrievied.
639
+ */
640
+ getNetworkConditions() {
641
+ return this.execute(new command.Command(Command.GET_NETWORK_CONDITIONS))
642
+ }
643
+
644
+ /**
645
+ * Schedules a command to set Chromium network emulation settings.
646
+ *
647
+ * __Sample Usage:__
648
+ *
649
+ * driver.setNetworkConditions({
650
+ * offline: false,
651
+ * latency: 5, // Additional latency (ms).
652
+ * download_throughput: 500 * 1024, // Maximal aggregated download throughput.
653
+ * upload_throughput: 500 * 1024 // Maximal aggregated upload throughput.
654
+ * });
655
+ *
656
+ * @param {Object} spec Defines the network conditions to set
657
+ * @return {!Promise<void>} A promise that will be resolved when network
658
+ * emulation settings are set.
659
+ */
660
+ setNetworkConditions(spec) {
661
+ if (!spec || typeof spec !== 'object') {
662
+ throw TypeError(
663
+ 'setNetworkConditions called with non-network-conditions parameter'
664
+ )
665
+ }
666
+ return this.execute(
667
+ new command.Command(Command.SET_NETWORK_CONDITIONS).setParameter(
668
+ 'network_conditions',
669
+ spec
670
+ )
671
+ )
672
+ }
673
+
674
+ /**
675
+ * Sends an arbitrary devtools command to the browser.
676
+ *
677
+ * @param {string} cmd The name of the command to send.
678
+ * @param {Object=} params The command parameters.
679
+ * @return {!Promise<void>} A promise that will be resolved when the command
680
+ * has finished.
681
+ * @see <https://chromedevtools.github.io/devtools-protocol/>
682
+ */
683
+ sendDevToolsCommand(cmd, params = {}) {
684
+ return this.execute(
685
+ new command.Command(Command.SEND_DEVTOOLS_COMMAND)
686
+ .setParameter('cmd', cmd)
687
+ .setParameter('params', params)
688
+ )
689
+ }
690
+
691
+ /**
692
+ * ends an arbitrary devtools command to the browser and get the result.
693
+ *
694
+ * @param {string} cmd The name of the command to send.
695
+ * @param {Object=} params The command parameters.
696
+ * @return {!Promise<void>} A promise that will be resolved when the command
697
+ * has finished.
698
+ * @see <https://chromedevtools.github.io/devtools-protocol/>
699
+ */
700
+ sendAndGetDevToolsCommand(cmd, params = {}) {
701
+ return this.execute(
702
+ new command.Command(Command.SEND_AND_GET_DEVTOOLS_COMMAND)
703
+ .setParameter('cmd', cmd)
704
+ .setParameter('params', params)
705
+ )
706
+ }
707
+
708
+ /**
709
+ * Set a permission state to the given value.
710
+ *
711
+ * @param {string} name A name of the permission to update.
712
+ * @param {('granted'|'denied'|'prompt')} state State to set permission to.
713
+ * @returns {!Promise<Object>} A promise that will be resolved when the
714
+ * command has finished.
715
+ * @see <https://w3c.github.io/permissions/#permission-registry> for valid
716
+ * names
717
+ */
718
+ setPermission(name, state) {
719
+ return this.execute(
720
+ new command.Command(Command.SET_PERMISSION)
721
+ .setParameter('descriptor', { name })
722
+ .setParameter('state', state)
723
+ )
724
+ }
725
+
726
+ /**
727
+ * Sends a DevTools command to change the browser's download directory.
728
+ *
729
+ * @param {string} path The desired download directory.
730
+ * @return {!Promise<void>} A promise that will be resolved when the command
731
+ * has finished.
732
+ * @see #sendDevToolsCommand
733
+ */
734
+ async setDownloadPath(path) {
735
+ if (!path || typeof path !== 'string') {
736
+ throw new error.InvalidArgumentError('invalid download path')
737
+ }
738
+ const stat = await io.stat(path)
739
+ if (!stat.isDirectory()) {
740
+ throw new error.InvalidArgumentError('not a directory: ' + path)
741
+ }
742
+ return this.sendDevToolsCommand('Page.setDownloadBehavior', {
743
+ behavior: 'allow',
744
+ downloadPath: path,
745
+ })
746
+ }
747
+
748
+ /**
749
+ * Returns the list of cast sinks (Cast devices) available to the Chrome media router.
750
+ *
751
+ * @return {!promise.Thenable<void>} A promise that will be resolved with an array of Strings
752
+ * containing the friendly device names of available cast sink targets.
753
+ */
754
+ getCastSinks() {
755
+ return this.schedule(
756
+ new command.Command(Command.GET_CAST_SINKS),
757
+ 'Driver.getCastSinks()'
758
+ )
759
+ }
760
+
761
+ /**
762
+ * Selects a cast sink (Cast device) as the recipient of media router intents (connect or play).
763
+ *
764
+ * @param {String} deviceName name of the target device.
765
+ * @return {!promise.Thenable<void>} A promise that will be resolved
766
+ * when the target device has been selected to respond further webdriver commands.
767
+ */
768
+ setCastSinkToUse(deviceName) {
769
+ return this.schedule(
770
+ new command.Command(Command.SET_CAST_SINK_TO_USE).setParameter(
771
+ 'sinkName',
772
+ deviceName
773
+ ),
774
+ 'Driver.setCastSinkToUse(' + deviceName + ')'
775
+ )
776
+ }
777
+
778
+ /**
779
+ * Initiates tab mirroring for the current browser tab on the specified device.
780
+ *
781
+ * @param {String} deviceName name of the target device.
782
+ * @return {!promise.Thenable<void>} A promise that will be resolved
783
+ * when the mirror command has been issued to the device.
784
+ */
785
+ startCastTabMirroring(deviceName) {
786
+ return this.schedule(
787
+ new command.Command(Command.START_CAST_TAB_MIRRORING).setParameter(
788
+ 'sinkName',
789
+ deviceName
790
+ ),
791
+ 'Driver.startCastTabMirroring(' + deviceName + ')'
792
+ )
793
+ }
794
+
795
+ /**
796
+ * Returns an error message when there is any issue in a Cast session.
797
+ * @return {!promise.Thenable<void>} A promise that will be resolved
798
+ * when the mirror command has been issued to the device.
799
+ */
800
+ getCastIssueMessage() {
801
+ return this.schedule(
802
+ new command.Command(Command.GET_CAST_ISSUE_MESSAGE),
803
+ 'Driver.getCastIssueMessage()'
804
+ )
805
+ }
806
+
807
+ /**
808
+ * Stops casting from media router to the specified device, if connected.
809
+ *
810
+ * @param {String} deviceName name of the target device.
811
+ * @return {!promise.Thenable<void>} A promise that will be resolved
812
+ * when the stop command has been issued to the device.
813
+ */
814
+ stopCasting(deviceName) {
815
+ return this.schedule(
816
+ new command.Command(Command.STOP_CASTING).setParameter(
817
+ 'sinkName',
818
+ deviceName
819
+ ),
820
+ 'Driver.stopCasting(' + deviceName + ')'
821
+ )
822
+ }
823
+ }
824
+
825
+ // PUBLIC API
826
+
827
+ exports.Driver = Driver
828
+ exports.Options = Options
829
+ exports.ServiceBuilder = ServiceBuilder