chrome.js

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 a {@linkplain Driver WebDriver} client for the Chrome
20 * web browser. Before using this module, you must download the latest
21 * [ChromeDriver release] and ensure it can be found on your system [PATH].
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 the [ChromeDriver] child process.
28 *
29 * 2. {@linkplain Options}: defines configuration options for each new Chrome
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 * __Customizing the ChromeDriver Server__ <a id="custom-server"></a>
40 *
41 * By default, every Chrome session will use a single driver service, which is
42 * started the first time a {@link Driver} instance is created and terminated
43 * when this process exits. The default service will inherit its environment
44 * from the current process and direct all output to /dev/null. You may obtain
45 * a handle to this default service using
46 * {@link #getDefaultService getDefaultService()} and change its configuration
47 * with {@link #setDefaultService setDefaultService()}.
48 *
49 * You may also create a {@link Driver} with its own driver service. This is
50 * useful if you need to capture the server's log output for a specific session:
51 *
52 * var chrome = require('selenium-webdriver/chrome');
53 *
54 * var service = new chrome.ServiceBuilder()
55 * .loggingTo('/my/log/file.txt')
56 * .enableVerboseLogging()
57 * .build();
58 *
59 * var options = new chrome.Options();
60 * // configure browser options ...
61 *
62 * var driver = new chrome.Driver(options, service);
63 *
64 * Users should only instantiate the {@link Driver} class directly when they
65 * need a custom driver service configuration (as shown above). For normal
66 * operation, users should start Chrome using the
67 * {@link selenium-webdriver.Builder}.
68 *
69 * __Working with Android__ <a id="android"></a>
70 *
71 * The [ChromeDriver][android] supports running tests on the Chrome browser as
72 * well as [WebView apps][webview] starting in Android 4.4 (KitKat). In order to
73 * work with Android, you must first start the adb
74 *
75 * adb start-server
76 *
77 * By default, adb will start on port 5037. You may change this port, but this
78 * will require configuring a [custom server](#custom-server) that will connect
79 * to adb on the {@linkplain ServiceBuilder#setAdbPort correct port}:
80 *
81 * var service = new chrome.ServiceBuilder()
82 * .setAdbPort(1234)
83 * build();
84 * // etc.
85 *
86 * The ChromeDriver may be configured to launch Chrome on Android using
87 * {@link Options#androidChrome()}:
88 *
89 * var driver = new Builder()
90 * .forBrowser('chrome')
91 * .setChromeOptions(new chrome.Options().androidChrome())
92 * .build();
93 *
94 * Alternatively, you can configure the ChromeDriver to launch an app with a
95 * Chrome-WebView by setting the {@linkplain Options#androidActivity
96 * androidActivity} option:
97 *
98 * var driver = new Builder()
99 * .forBrowser('chrome')
100 * .setChromeOptions(new chrome.Options()
101 * .androidPackage('com.example')
102 * .androidActivity('com.example.Activity'))
103 * .build();
104 *
105 * [Refer to the ChromeDriver site] for more information on using the
106 * [ChromeDriver with Android][android].
107 *
108 * [ChromeDriver]: https://sites.google.com/a/chromium.org/chromedriver/
109 * [ChromeDriver release]: http://chromedriver.storage.googleapis.com/index.html
110 * [PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
111 * [android]: https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android
112 * [webview]: https://developer.chrome.com/multidevice/webview/overview
113 */
114
115'use strict';
116
117var fs = require('fs'),
118 util = require('util');
119
120var webdriver = require('./index'),
121 executors = require('./executors'),
122 io = require('./io'),
123 portprober = require('./net/portprober'),
124 remote = require('./remote');
125
126
127/**
128 * Name of the ChromeDriver executable.
129 * @type {string}
130 * @const
131 */
132var CHROMEDRIVER_EXE =
133 process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver';
134
135
136/**
137 * Creates {@link selenium-webdriver/remote.DriverService} instances that manage
138 * a [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/)
139 * server in a child process.
140 *
141 * @param {string=} opt_exe Path to the server executable to use. If omitted,
142 * the builder will attempt to locate the chromedriver on the current
143 * PATH.
144 * @throws {Error} If provided executable does not exist, or the chromedriver
145 * cannot be found on the PATH.
146 * @constructor
147 */
148var ServiceBuilder = function(opt_exe) {
149 /** @private {string} */
150 this.exe_ = opt_exe || io.findInPath(CHROMEDRIVER_EXE, true);
151 if (!this.exe_) {
152 throw Error(
153 'The ChromeDriver could not be found on the current PATH. Please ' +
154 'download the latest version of the ChromeDriver from ' +
155 'http://chromedriver.storage.googleapis.com/index.html and ensure ' +
156 'it can be found on your PATH.');
157 }
158
159 if (!fs.existsSync(this.exe_)) {
160 throw Error('File does not exist: ' + this.exe_);
161 }
162
163 /** @private {!Array.<string>} */
164 this.args_ = [];
165 this.stdio_ = 'ignore';
166};
167
168
169/** @private {string} */
170ServiceBuilder.prototype.path_ = null;
171
172/** @private {number} */
173ServiceBuilder.prototype.port_ = 0;
174
175
176/** @private {(string|!Array.<string|number|!Stream|null|undefined>)} */
177ServiceBuilder.prototype.stdio_ = 'ignore';
178
179
180/** @private {Object.<string, string>} */
181ServiceBuilder.prototype.env_ = null;
182
183
184/**
185 * Sets the port to start the ChromeDriver on.
186 * @param {number} port The port to use, or 0 for any free port.
187 * @return {!ServiceBuilder} A self reference.
188 * @throws {Error} If the port is invalid.
189 */
190ServiceBuilder.prototype.usingPort = function(port) {
191 if (port < 0) {
192 throw Error('port must be >= 0: ' + port);
193 }
194 this.port_ = port;
195 return this;
196};
197
198
199/**
200 * Sets which port adb is listening to. _The ChromeDriver will connect to adb
201 * if an {@linkplain Options#androidPackage Android session} is requested, but
202 * adb **must** be started beforehand._
203 *
204 * @param {number} port Which port adb is running on.
205 * @return {!ServiceBuilder} A self reference.
206 */
207ServiceBuilder.prototype.setAdbPort = function(port) {
208 this.args_.push('--adb-port=' + port);
209 return this;
210};
211
212
213/**
214 * Sets the path of the log file the driver should log to. If a log file is
215 * not specified, the driver will log to stderr.
216 * @param {string} path Path of the log file to use.
217 * @return {!ServiceBuilder} A self reference.
218 */
219ServiceBuilder.prototype.loggingTo = function(path) {
220 this.args_.push('--log-path=' + path);
221 return this;
222};
223
224
225/**
226 * Enables verbose logging.
227 * @return {!ServiceBuilder} A self reference.
228 */
229ServiceBuilder.prototype.enableVerboseLogging = function() {
230 this.args_.push('--verbose');
231 return this;
232};
233
234
235/**
236 * Sets the number of threads the driver should use to manage HTTP requests.
237 * By default, the driver will use 4 threads.
238 * @param {number} n The number of threads to use.
239 * @return {!ServiceBuilder} A self reference.
240 */
241ServiceBuilder.prototype.setNumHttpThreads = function(n) {
242 this.args_.push('--http-threads=' + n);
243 return this;
244};
245
246
247/**
248 * Sets the base path for WebDriver REST commands (e.g. "/wd/hub").
249 * By default, the driver will accept commands relative to "/".
250 * @param {string} path The base path to use.
251 * @return {!ServiceBuilder} A self reference.
252 */
253ServiceBuilder.prototype.setUrlBasePath = function(path) {
254 this.args_.push('--url-base=' + path);
255 this.path_ = path;
256 return this;
257};
258
259
260/**
261 * Defines the stdio configuration for the driver service. See
262 * {@code child_process.spawn} for more information.
263 * @param {(string|!Array.<string|number|!Stream|null|undefined>)} config The
264 * configuration to use.
265 * @return {!ServiceBuilder} A self reference.
266 */
267ServiceBuilder.prototype.setStdio = function(config) {
268 this.stdio_ = config;
269 return this;
270};
271
272
273/**
274 * Defines the environment to start the server under. This settings will be
275 * inherited by every browser session started by the server.
276 * @param {!Object.<string, string>} env The environment to use.
277 * @return {!ServiceBuilder} A self reference.
278 */
279ServiceBuilder.prototype.withEnvironment = function(env) {
280 this.env_ = env;
281 return this;
282};
283
284
285/**
286 * Creates a new DriverService using this instance's current configuration.
287 * @return {remote.DriverService} A new driver service using this instance's
288 * current configuration.
289 * @throws {Error} If the driver exectuable was not specified and a default
290 * could not be found on the current PATH.
291 */
292ServiceBuilder.prototype.build = function() {
293 var port = this.port_ || portprober.findFreePort();
294 var args = this.args_.concat(); // Defensive copy.
295
296 return new remote.DriverService(this.exe_, {
297 loopback: true,
298 path: this.path_,
299 port: port,
300 args: webdriver.promise.when(port, function(port) {
301 return args.concat('--port=' + port);
302 }),
303 env: this.env_,
304 stdio: this.stdio_
305 });
306};
307
308
309/** @type {remote.DriverService} */
310var defaultService = null;
311
312
313/**
314 * Sets the default service to use for new ChromeDriver instances.
315 * @param {!remote.DriverService} service The service to use.
316 * @throws {Error} If the default service is currently running.
317 */
318function setDefaultService(service) {
319 if (defaultService && defaultService.isRunning()) {
320 throw Error(
321 'The previously configured ChromeDriver service is still running. ' +
322 'You must shut it down before you may adjust its configuration.');
323 }
324 defaultService = service;
325}
326
327
328/**
329 * Returns the default ChromeDriver service. If such a service has not been
330 * configured, one will be constructed using the default configuration for
331 * a ChromeDriver executable found on the system PATH.
332 * @return {!remote.DriverService} The default ChromeDriver service.
333 */
334function getDefaultService() {
335 if (!defaultService) {
336 defaultService = new ServiceBuilder().build();
337 }
338 return defaultService;
339}
340
341
342/**
343 * @type {string}
344 * @const
345 */
346var OPTIONS_CAPABILITY_KEY = 'chromeOptions';
347
348
349/**
350 * Class for managing ChromeDriver specific options.
351 * @constructor
352 * @extends {webdriver.Serializable}
353 */
354var Options = function() {
355 webdriver.Serializable.call(this);
356
357 /** @private {!Object} */
358 this.options_ = {};
359
360 /** @private {!Array.<(string|!Buffer)>} */
361 this.extensions_ = [];
362
363 /** @private {?webdriver.logging.Preferences} */
364 this.logPrefs_ = null;
365
366 /** @private {?webdriver.ProxyConfig} */
367 this.proxy_ = null;
368};
369util.inherits(Options, webdriver.Serializable);
370
371
372/**
373 * Extracts the ChromeDriver specific options from the given capabilities
374 * object.
375 * @param {!webdriver.Capabilities} capabilities The capabilities object.
376 * @return {!Options} The ChromeDriver options.
377 */
378Options.fromCapabilities = function(capabilities) {
379 var options = new Options();
380
381 var o = capabilities.get(OPTIONS_CAPABILITY_KEY);
382 if (o instanceof Options) {
383 options = o;
384 } else if (o) {
385 options.
386 addArguments(o.args || []).
387 addExtensions(o.extensions || []).
388 detachDriver(o.detach).
389 excludeSwitches(o.excludeSwitches || []).
390 setChromeBinaryPath(o.binary).
391 setChromeLogFile(o.logPath).
392 setChromeMinidumpPath(o.minidumpPath).
393 setLocalState(o.localState).
394 setMobileEmulation(o.mobileEmulation).
395 setUserPreferences(o.prefs).
396 setPerfLoggingPrefs(o.perfLoggingPrefs);
397 }
398
399 if (capabilities.has(webdriver.Capability.PROXY)) {
400 options.setProxy(capabilities.get(webdriver.Capability.PROXY));
401 }
402
403 if (capabilities.has(webdriver.Capability.LOGGING_PREFS)) {
404 options.setLoggingPrefs(
405 capabilities.get(webdriver.Capability.LOGGING_PREFS));
406 }
407
408 return options;
409};
410
411
412/**
413 * Add additional command line arguments to use when launching the Chrome
414 * browser. Each argument may be specified with or without the "--" prefix
415 * (e.g. "--foo" and "foo"). Arguments with an associated value should be
416 * delimited by an "=": "foo=bar".
417 * @param {...(string|!Array.<string>)} var_args The arguments to add.
418 * @return {!Options} A self reference.
419 */
420Options.prototype.addArguments = function(var_args) {
421 var args = this.options_.args || [];
422 args = args.concat.apply(args, arguments);
423 if (args.length) {
424 this.options_.args = args;
425 }
426 return this;
427};
428
429
430/**
431 * List of Chrome command line switches to exclude that ChromeDriver by default
432 * passes when starting Chrome. Do not prefix switches with "--".
433 *
434 * @param {...(string|!Array<string>)} var_args The switches to exclude.
435 * @return {!Options} A self reference.
436 */
437Options.prototype.excludeSwitches = function(var_args) {
438 var switches = this.options_.excludeSwitches || [];
439 switches = switches.concat.apply(switches, arguments);
440 if (switches.length) {
441 this.options_.excludeSwitches = switches;
442 }
443 return this;
444};
445
446
447/**
448 * Add additional extensions to install when launching Chrome. Each extension
449 * should be specified as the path to the packed CRX file, or a Buffer for an
450 * extension.
451 * @param {...(string|!Buffer|!Array.<(string|!Buffer)>)} var_args The
452 * extensions to add.
453 * @return {!Options} A self reference.
454 */
455Options.prototype.addExtensions = function(var_args) {
456 this.extensions_ = this.extensions_.concat.apply(this.extensions_, arguments);
457 return this;
458};
459
460
461/**
462 * Sets the path to the Chrome binary to use. On Mac OS X, this path should
463 * reference the actual Chrome executable, not just the application binary
464 * (e.g. "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome").
465 *
466 * The binary path be absolute or relative to the chromedriver server
467 * executable, but it must exist on the machine that will launch Chrome.
468 *
469 * @param {string} path The path to the Chrome binary to use.
470 * @return {!Options} A self reference.
471 */
472Options.prototype.setChromeBinaryPath = function(path) {
473 this.options_.binary = path;
474 return this;
475};
476
477
478/**
479 * Sets whether to leave the started Chrome browser running if the controlling
480 * ChromeDriver service is killed before {@link webdriver.WebDriver#quit()} is
481 * called.
482 * @param {boolean} detach Whether to leave the browser running if the
483 * chromedriver service is killed before the session.
484 * @return {!Options} A self reference.
485 */
486Options.prototype.detachDriver = function(detach) {
487 this.options_.detach = detach;
488 return this;
489};
490
491
492/**
493 * Sets the user preferences for Chrome's user profile. See the "Preferences"
494 * file in Chrome's user data directory for examples.
495 * @param {!Object} prefs Dictionary of user preferences to use.
496 * @return {!Options} A self reference.
497 */
498Options.prototype.setUserPreferences = function(prefs) {
499 this.options_.prefs = prefs;
500 return this;
501};
502
503
504/**
505 * Sets the logging preferences for the new session.
506 * @param {!webdriver.logging.Preferences} prefs The logging preferences.
507 * @return {!Options} A self reference.
508 */
509Options.prototype.setLoggingPrefs = function(prefs) {
510 this.logPrefs_ = prefs;
511 return this;
512};
513
514
515/**
516 * Sets the performance logging preferences. Options include:
517 *
518 * - `enableNetwork`: Whether or not to collect events from Network domain.
519 * - `enablePage`: Whether or not to collect events from Page domain.
520 * - `enableTimeline`: Whether or not to collect events from Timeline domain.
521 * Note: when tracing is enabled, Timeline domain is implicitly disabled,
522 * unless `enableTimeline` is explicitly set to true.
523 * - `tracingCategories`: A comma-separated string of Chrome tracing categories
524 * for which trace events should be collected. An unspecified or empty
525 * string disables tracing.
526 * - `bufferUsageReportingInterval`: The requested number of milliseconds
527 * between DevTools trace buffer usage events. For example, if 1000, then
528 * once per second, DevTools will report how full the trace buffer is. If a
529 * report indicates the buffer usage is 100%, a warning will be issued.
530 *
531 * @param {{enableNetwork: boolean,
532 * enablePage: boolean,
533 * enableTimeline: boolean,
534 * tracingCategories: string,
535 * bufferUsageReportingInterval: number}} prefs The performance
536 * logging preferences.
537 * @return {!Options} A self reference.
538 */
539Options.prototype.setPerfLoggingPrefs = function(prefs) {
540 this.options_.perfLoggingPrefs = prefs;
541 return this;
542};
543
544
545/**
546 * Sets preferences for the "Local State" file in Chrome's user data
547 * directory.
548 * @param {!Object} state Dictionary of local state preferences.
549 * @return {!Options} A self reference.
550 */
551Options.prototype.setLocalState = function(state) {
552 this.options_.localState = state;
553 return this;
554};
555
556
557/**
558 * Sets the name of the activity hosting a Chrome-based Android WebView. This
559 * option must be set to connect to an [Android WebView](
560 * https://sites.google.com/a/chromium.org/chromedriver/getting-started/getting-started---android)
561 *
562 * @param {string} name The activity name.
563 * @return {!Options} A self reference.
564 */
565Options.prototype.androidActivity = function(name) {
566 this.options_.androidActivity = name;
567 return this;
568};
569
570
571/**
572 * Sets the device serial number to connect to via ADB. If not specified, the
573 * ChromeDriver will select an unused device at random. An error will be
574 * returned if all devices already have active sessions.
575 *
576 * @param {string} serial The device serial number to connect to.
577 * @return {!Options} A self reference.
578 */
579Options.prototype.androidDeviceSerial = function(serial) {
580 this.options_.androidDeviceSerial = serial;
581 return this;
582};
583
584
585/**
586 * Configures the ChromeDriver to launch Chrome on Android via adb. This
587 * function is shorthand for
588 * {@link #androidPackage options.androidPackage('com.android.chrome')}.
589 * @return {!Options} A self reference.
590 */
591Options.prototype.androidChrome = function() {
592 return this.androidPackage('com.android.chrome');
593};
594
595
596/**
597 * Sets the package name of the Chrome or WebView app.
598 *
599 * @param {?string} pkg The package to connect to, or `null` to disable Android
600 * and switch back to using desktop Chrome.
601 * @return {!Options} A self reference.
602 */
603Options.prototype.androidPackage = function(pkg) {
604 this.options_.androidPackage = pkg;
605 return this;
606};
607
608
609/**
610 * Sets the process name of the Activity hosting the WebView (as given by `ps`).
611 * If not specified, the process name is assumed to be the same as
612 * {@link #androidPackage}.
613 *
614 * @param {string} processName The main activity name.
615 * @return {!Options} A self reference.
616 */
617Options.prototype.androidProcess = function(processName) {
618 this.options_.androidProcess = processName;
619 return this;
620};
621
622
623/**
624 * Sets whether to connect to an already-running instead of the specified
625 * {@linkplain #androidProcess app} instead of launching the app with a clean
626 * data directory.
627 *
628 * @param {boolean} useRunning Whether to connect to a running instance.
629 * @return {!Options} A self reference.
630 */
631Options.prototype.androidUseRunningApp = function(useRunning) {
632 this.options_.androidUseRunningApp = useRunning;
633 return this;
634};
635
636
637/**
638 * Sets the path to Chrome's log file. This path should exist on the machine
639 * that will launch Chrome.
640 * @param {string} path Path to the log file to use.
641 * @return {!Options} A self reference.
642 */
643Options.prototype.setChromeLogFile = function(path) {
644 this.options_.logPath = path;
645 return this;
646};
647
648
649/**
650 * Sets the directory to store Chrome minidumps in. This option is only
651 * supported when ChromeDriver is running on Linux.
652 * @param {string} path The directory path.
653 * @return {!Options} A self reference.
654 */
655Options.prototype.setChromeMinidumpPath = function(path) {
656 this.options_.minidumpPath = path;
657 return this;
658};
659
660
661/**
662 * Configures Chrome to emulate a mobile device. For more information, refer to
663 * the ChromeDriver project page on [mobile emulation][em]. Configuration
664 * options include:
665 *
666 * - `deviceName`: The name of a pre-configured [emulated device][devem]
667 * - `width`: screen width, in pixels
668 * - `height`: screen height, in pixels
669 * - `pixelRatio`: screen pixel ratio
670 *
671 * __Example 1: Using a Pre-configured Device__
672 *
673 * var options = new chrome.Options().setMobileEmulation(
674 * {deviceName: 'Google Nexus 5'});
675 *
676 * var driver = new chrome.Driver(options);
677 *
678 * __Example 2: Using Custom Screen Configuration__
679 *
680 * var options = new chrome.Options().setMobileEmulation({
681 * width: 360,
682 * height: 640,
683 * pixelRatio: 3.0
684 * });
685 *
686 * var driver = new chrome.Driver(options);
687 *
688 *
689 * [em]: https://sites.google.com/a/chromium.org/chromedriver/mobile-emulation
690 * [devem]: https://developer.chrome.com/devtools/docs/device-mode
691 *
692 * @param {?({deviceName: string}|
693 * {width: number, height: number, pixelRatio: number})} config The
694 * mobile emulation configuration, or `null` to disable emulation.
695 * @return {!Options} A self reference.
696 */
697Options.prototype.setMobileEmulation = function(config) {
698 this.options_.mobileEmulation = config;
699 return this;
700};
701
702
703/**
704 * Sets the proxy settings for the new session.
705 * @param {webdriver.ProxyConfig} proxy The proxy configuration to use.
706 * @return {!Options} A self reference.
707 */
708Options.prototype.setProxy = function(proxy) {
709 this.proxy_ = proxy;
710 return this;
711};
712
713
714/**
715 * Converts this options instance to a {@link webdriver.Capabilities} object.
716 * @param {webdriver.Capabilities=} opt_capabilities The capabilities to merge
717 * these options into, if any.
718 * @return {!webdriver.Capabilities} The capabilities.
719 */
720Options.prototype.toCapabilities = function(opt_capabilities) {
721 var capabilities = opt_capabilities || webdriver.Capabilities.chrome();
722 capabilities.
723 set(webdriver.Capability.PROXY, this.proxy_).
724 set(webdriver.Capability.LOGGING_PREFS, this.logPrefs_).
725 set(OPTIONS_CAPABILITY_KEY, this);
726 return capabilities;
727};
728
729
730/**
731 * Converts this instance to its JSON wire protocol representation. Note this
732 * function is an implementation not intended for general use.
733 * @return {{args: !Array.<string>,
734 * binary: (string|undefined),
735 * detach: boolean,
736 * extensions: !Array.<(string|!webdriver.promise.Promise.<string>)>,
737 * localState: (Object|undefined),
738 * logPath: (string|undefined),
739 * prefs: (Object|undefined)}} The JSON wire protocol representation
740 * of this instance.
741 * @override
742 */
743Options.prototype.serialize = function() {
744 var json = {};
745 for (var key in this.options_) {
746 if (this.options_[key] != null) {
747 json[key] = this.options_[key];
748 }
749 }
750 if (this.extensions_.length) {
751 json.extensions = this.extensions_.map(function(extension) {
752 if (Buffer.isBuffer(extension)) {
753 return extension.toString('base64');
754 }
755 return webdriver.promise.checkedNodeCall(
756 fs.readFile, extension, 'base64');
757 });
758 }
759 return json;
760};
761
762
763/**
764 * Creates a new WebDriver client for Chrome.
765 *
766 * @param {(webdriver.Capabilities|Options)=} opt_config The configuration
767 * options.
768 * @param {remote.DriverService=} opt_service The session to use; will use
769 * the {@linkplain #getDefaultService default service} by default.
770 * @param {webdriver.promise.ControlFlow=} opt_flow The control flow to use, or
771 * {@code null} to use the currently active flow.
772 * @constructor
773 * @extends {webdriver.WebDriver}
774 */
775var Driver = function(opt_config, opt_service, opt_flow) {
776 var service = opt_service || getDefaultService();
777 var executor = executors.createExecutor(service.start());
778
779 var capabilities =
780 opt_config instanceof Options ? opt_config.toCapabilities() :
781 (opt_config || webdriver.Capabilities.chrome());
782
783 var driver = webdriver.WebDriver.createSession(
784 executor, capabilities, opt_flow);
785
786 webdriver.WebDriver.call(
787 this, driver.getSession(), executor, driver.controlFlow());
788};
789util.inherits(Driver, webdriver.WebDriver);
790
791
792/**
793 * This function is a no-op as file detectors are not supported by this
794 * implementation.
795 * @override
796 */
797Driver.prototype.setFileDetector = function() {
798};
799
800
801// PUBLIC API
802
803
804exports.Driver = Driver;
805exports.Options = Options;
806exports.ServiceBuilder = ServiceBuilder;
807exports.getDefaultService = getDefaultService;
808exports.setDefaultService = setDefaultService;