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