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/firefox.js CHANGED
@@ -79,7 +79,7 @@
79
79
  * .setFirefoxOptions(options)
80
80
  * .build();
81
81
  *
82
- * On all platforms, you may configrue WebDriver to use a Firefox specific
82
+ * On all platforms, you may configure WebDriver to use a Firefox specific
83
83
  * executable:
84
84
  *
85
85
  * let options = new firefox.Options()
@@ -89,7 +89,7 @@
89
89
  *
90
90
  * You may customize the Firefox binary and profile when running against a
91
91
  * remote Selenium server. Your custom profile will be packaged as a zip and
92
- * transfered to the remote host for use. The profile will be transferred
92
+ * transferred to the remote host for use. The profile will be transferred
93
93
  * _once for each new session_. The performance impact should be minimal if
94
94
  * you've only configured a few extra browser preferences. If you have a large
95
95
  * profile with several extensions, you should consider installing it on the
@@ -114,25 +114,19 @@
114
114
  * [PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
115
115
  */
116
116
 
117
- 'use strict';
118
-
119
- const path = require('path');
120
- const url = require('url');
121
-
122
- const Symbols = require('./lib/symbols');
123
- const command = require('./lib/command');
124
- const exec = require('./io/exec');
125
- const http = require('./http');
126
- const httpUtil = require('./http/util');
127
- const io = require('./io');
128
- const net = require('./net');
129
- const portprober = require('./net/portprober');
130
- const remote = require('./remote');
131
- const webdriver = require('./lib/webdriver');
132
- const zip = require('./io/zip');
133
- const {Browser, Capabilities} = require('./lib/capabilities');
134
- const {Zip} = require('./io/zip');
117
+ 'use strict'
135
118
 
119
+ const path = require('path')
120
+ const Symbols = require('./lib/symbols')
121
+ const command = require('./lib/command')
122
+ const http = require('./http')
123
+ const io = require('./io')
124
+ const remote = require('./remote')
125
+ const webdriver = require('./lib/webdriver')
126
+ const zip = require('./io/zip')
127
+ const cdp = require('./devtools/CDPConnection')
128
+ const { Browser, Capabilities } = require('./lib/capabilities')
129
+ const { Zip } = require('./io/zip')
136
130
 
137
131
  /**
138
132
  * Thrown when there an add-on is malformed.
@@ -141,13 +135,12 @@ const {Zip} = require('./io/zip');
141
135
  class AddonFormatError extends Error {
142
136
  /** @param {string} msg The error message. */
143
137
  constructor(msg) {
144
- super(msg);
138
+ super(msg)
145
139
  /** @override */
146
- this.name = this.constructor.name;
140
+ this.name = this.constructor.name
147
141
  }
148
142
  }
149
143
 
150
-
151
144
  /**
152
145
  * Installs an extension to the given directory.
153
146
  * @param {string} extension Path to the xpi extension file to install.
@@ -156,56 +149,53 @@ class AddonFormatError extends Error {
156
149
  * installed.
157
150
  */
158
151
  async function installExtension(extension, dir) {
159
- if (extension.slice(-4) !== '.xpi') {
160
- throw Error('Path ath is not a xpi file: ' + extension);
152
+ const ext = extension.slice(-4)
153
+ if (ext !== '.xpi' && ext !== '.zip') {
154
+ throw Error('File name does not end in ".zip" or ".xpi": ' + ext)
161
155
  }
162
156
 
163
- let archive = await zip.load(extension);
157
+ let archive = await zip.load(extension)
164
158
  if (!archive.has('manifest.json')) {
165
- throw new AddonFormatError(`Couldn't find manifest.json in ${extension}`);
159
+ throw new AddonFormatError(`Couldn't find manifest.json in ${extension}`)
166
160
  }
167
161
 
168
- let buf = await archive.getFile('manifest.json');
169
- let parsedJSON = JSON.parse(buf.toString('utf8'));
170
-
162
+ let buf = await archive.getFile('manifest.json')
163
+ let parsedJSON = JSON.parse(buf.toString('utf8'))
164
+
171
165
  let { browser_specific_settings } =
172
166
  /** @type {{browser_specific_settings:{gecko:{id:string}}}} */
173
- parsedJSON;
167
+ parsedJSON
174
168
 
175
- if (
176
- browser_specific_settings &&
177
- browser_specific_settings.gecko
178
- ) {
169
+ if (browser_specific_settings && browser_specific_settings.gecko) {
179
170
  /* browser_specific_settings is an alternative to applications
180
171
  * It is meant to facilitate cross-browser plugins since Firefox48
181
172
  * see https://bugzilla.mozilla.org/show_bug.cgi?id=1262005
182
173
  */
183
- parsedJSON.applications = browser_specific_settings;
174
+ parsedJSON.applications = browser_specific_settings
184
175
  }
185
176
 
186
177
  let { applications } =
187
178
  /** @type {{applications:{gecko:{id:string}}}} */
188
- parsedJSON;
179
+ parsedJSON
189
180
  if (!(applications && applications.gecko && applications.gecko.id)) {
190
- throw new AddonFormatError(`Could not find add-on ID for ${extension}`);
181
+ throw new AddonFormatError(`Could not find add-on ID for ${extension}`)
191
182
  }
192
183
 
193
- await io.copy(extension, `${path.join(dir, applications.gecko.id)}.xpi`);
194
- return applications.gecko.id;
184
+ await io.copy(extension, `${path.join(dir, applications.gecko.id)}.xpi`)
185
+ return applications.gecko.id
195
186
  }
196
187
 
197
-
198
188
  class Profile {
199
189
  constructor() {
200
190
  /** @private {?string} */
201
- this.template_ = null;
191
+ this.template_ = null
202
192
 
203
193
  /** @private {!Array<string>} */
204
- this.extensions_ = [];
194
+ this.extensions_ = []
205
195
  }
206
196
 
207
- addExtensions(/** !Array<string> */paths) {
208
- this.extensions_ = this.extensions_.concat(...paths);
197
+ addExtensions(/** !Array<string> */ paths) {
198
+ this.extensions_ = this.extensions_.concat(...paths)
209
199
  }
210
200
 
211
201
  /**
@@ -214,13 +204,12 @@ class Profile {
214
204
  */
215
205
  [Symbols.serialize]() {
216
206
  if (this.template_ || this.extensions_.length) {
217
- return buildProfile(this.template_, this.extensions_);
207
+ return buildProfile(this.template_, this.extensions_)
218
208
  }
219
- return undefined;
209
+ return undefined
220
210
  }
221
211
  }
222
212
 
223
-
224
213
  /**
225
214
  * @param {?string} template path to an existing profile to use as a template.
226
215
  * @param {!Array<string>} extensions paths to extensions to install in the new
@@ -228,31 +217,33 @@ class Profile {
228
217
  * @return {!Promise<string>} a promise for the base64 encoded profile.
229
218
  */
230
219
  async function buildProfile(template, extensions) {
231
- let dir = template;
220
+ let dir = template
232
221
 
233
222
  if (extensions.length) {
234
- dir = await io.tmpDir();
223
+ dir = await io.tmpDir()
235
224
  if (template) {
236
225
  await io.copyDir(
237
- /** @type {string} */(template),
238
- dir, /(parent\.lock|lock|\.parentlock)/);
226
+ /** @type {string} */(template),
227
+ dir,
228
+ /(parent\.lock|lock|\.parentlock)/
229
+ )
239
230
  }
240
231
 
241
- const extensionsDir = path.join(dir, 'extensions');
242
- await io.mkdir(extensionsDir);
232
+ const extensionsDir = path.join(dir, 'extensions')
233
+ await io.mkdir(extensionsDir)
243
234
 
244
235
  for (let i = 0; i < extensions.length; i++) {
245
- await installExtension(extensions[i], extensionsDir);
236
+ await installExtension(extensions[i], extensionsDir)
246
237
  }
247
238
  }
248
239
 
249
- let zip = new Zip;
250
- return zip.addDir(dir)
251
- .then(() => zip.toBuffer())
252
- .then(buf => buf.toString('base64'));
240
+ let zip = new Zip()
241
+ return zip
242
+ .addDir(dir)
243
+ .then(() => zip.toBuffer())
244
+ .then((buf) => buf.toString('base64'))
253
245
  }
254
246
 
255
-
256
247
  /**
257
248
  * Configuration options for the FirefoxDriver.
258
249
  */
@@ -262,8 +253,8 @@ class Options extends Capabilities {
262
253
  * capabilities to initialize this instance from.
263
254
  */
264
255
  constructor(other) {
265
- super(other);
266
- this.setBrowserName(Browser.FIREFOX);
256
+ super(other)
257
+ this.setBrowserName(Browser.FIREFOX)
267
258
  }
268
259
 
269
260
  /**
@@ -271,12 +262,12 @@ class Options extends Capabilities {
271
262
  * @private
272
263
  */
273
264
  firefoxOptions_() {
274
- let options = this.get('moz:firefoxOptions');
265
+ let options = this.get('moz:firefoxOptions')
275
266
  if (!options) {
276
- options = {};
277
- this.set('moz:firefoxOptions', options);
267
+ options = {}
268
+ this.set('moz:firefoxOptions', options)
278
269
  }
279
- return options;
270
+ return options
280
271
  }
281
272
 
282
273
  /**
@@ -284,11 +275,11 @@ class Options extends Capabilities {
284
275
  * @private
285
276
  */
286
277
  profile_() {
287
- let options = this.firefoxOptions_();
278
+ let options = this.firefoxOptions_()
288
279
  if (!options.profile) {
289
- options.profile = new Profile();
280
+ options.profile = new Profile()
290
281
  }
291
- return options.profile;
282
+ return options.profile
292
283
  }
293
284
 
294
285
  /**
@@ -300,10 +291,10 @@ class Options extends Capabilities {
300
291
  */
301
292
  addArguments(...args) {
302
293
  if (args.length) {
303
- let options = this.firefoxOptions_();
304
- options.args = options.args ? options.args.concat(...args) : args;
294
+ let options = this.firefoxOptions_()
295
+ options.args = options.args ? options.args.concat(...args) : args
305
296
  }
306
- return this;
297
+ return this
307
298
  }
308
299
 
309
300
  /**
@@ -312,7 +303,7 @@ class Options extends Capabilities {
312
303
  * @return {!Options} A self reference.
313
304
  */
314
305
  headless() {
315
- return this.addArguments('-headless');
306
+ return this.addArguments('-headless')
316
307
  }
317
308
 
318
309
  /**
@@ -324,15 +315,15 @@ class Options extends Capabilities {
324
315
  * @throws {TypeError} if width or height is unspecified, not a number, or
325
316
  * less than or equal to 0.
326
317
  */
327
- windowSize({width, height}) {
318
+ windowSize({ width, height }) {
328
319
  function checkArg(arg) {
329
320
  if (typeof arg !== 'number' || arg <= 0) {
330
- throw TypeError('Arguments must be {width, height} with numbers > 0');
321
+ throw TypeError('Arguments must be {width, height} with numbers > 0')
331
322
  }
332
323
  }
333
- checkArg(width);
334
- checkArg(height);
335
- return this.addArguments(`--width=${width}`, `--height=${height}`);
324
+ checkArg(width)
325
+ checkArg(height)
326
+ return this.addArguments(`--width=${width}`, `--height=${height}`)
336
327
  }
337
328
 
338
329
  /**
@@ -342,8 +333,8 @@ class Options extends Capabilities {
342
333
  * @return {!Options} A self reference.
343
334
  */
344
335
  addExtensions(...paths) {
345
- this.profile_().addExtensions(paths);
346
- return this;
336
+ this.profile_().addExtensions(paths)
337
+ return this
347
338
  }
348
339
 
349
340
  /**
@@ -354,18 +345,21 @@ class Options extends Capabilities {
354
345
  */
355
346
  setPreference(key, value) {
356
347
  if (typeof key !== 'string') {
357
- throw TypeError(`key must be a string, but got ${typeof key}`);
348
+ throw TypeError(`key must be a string, but got ${typeof key}`)
358
349
  }
359
- if (typeof value !== 'string'
360
- && typeof value !== 'number'
361
- && typeof value !== 'boolean') {
350
+ if (
351
+ typeof value !== 'string' &&
352
+ typeof value !== 'number' &&
353
+ typeof value !== 'boolean'
354
+ ) {
362
355
  throw TypeError(
363
- `value must be a string, number, or boolean, but got ${typeof value}`);
356
+ `value must be a string, number, or boolean, but got ${typeof value}`
357
+ )
364
358
  }
365
- let options = this.firefoxOptions_();
366
- options.prefs = options.prefs || {};
367
- options.prefs[key] = value;
368
- return this;
359
+ let options = this.firefoxOptions_()
360
+ options.prefs = options.prefs || {}
361
+ options.prefs[key] = value
362
+ return this
369
363
  }
370
364
 
371
365
  /**
@@ -379,10 +373,10 @@ class Options extends Capabilities {
379
373
  */
380
374
  setProfile(profile) {
381
375
  if (typeof profile !== 'string') {
382
- throw TypeError(`profile must be a string, but got ${typeof profile}`);
376
+ throw TypeError(`profile must be a string, but got ${typeof profile}`)
383
377
  }
384
- this.profile_().template_ = profile;
385
- return this;
378
+ this.profile_().template_ = profile
379
+ return this
386
380
  }
387
381
 
388
382
  /**
@@ -395,14 +389,13 @@ class Options extends Capabilities {
395
389
  */
396
390
  setBinary(binary) {
397
391
  if (binary instanceof Channel || typeof binary === 'string') {
398
- this.firefoxOptions_().binary = binary;
399
- return this;
392
+ this.firefoxOptions_().binary = binary
393
+ return this
400
394
  }
401
- throw TypeError('binary must be a string path or Channel object');
395
+ throw TypeError('binary must be a string path or Channel object')
402
396
  }
403
397
  }
404
398
 
405
-
406
399
  /**
407
400
  * Enum of available command contexts.
408
401
  *
@@ -414,14 +407,12 @@ class Options extends Capabilities {
414
407
  * @enum {string}
415
408
  */
416
409
  const Context = {
417
- CONTENT: "content",
418
- CHROME: "chrome",
419
- };
420
-
410
+ CONTENT: 'content',
411
+ CHROME: 'chrome',
412
+ }
421
413
 
422
414
  const GECKO_DRIVER_EXE =
423
- process.platform === 'win32' ? 'geckodriver.exe' : 'geckodriver';
424
-
415
+ process.platform === 'win32' ? 'geckodriver.exe' : 'geckodriver'
425
416
 
426
417
  /**
427
418
  * _Synchronously_ attempts to locate the geckodriver executable on the current
@@ -430,27 +421,28 @@ const GECKO_DRIVER_EXE =
430
421
  * @return {?string} the located executable, or `null`.
431
422
  */
432
423
  function locateSynchronously() {
433
- return io.findInPath(GECKO_DRIVER_EXE, true);
424
+ return io.findInPath(GECKO_DRIVER_EXE, true)
434
425
  }
435
426
 
436
-
437
427
  /**
438
428
  * @return {string} .
439
429
  * @throws {Error}
440
430
  */
441
431
  function findGeckoDriver() {
442
- let exe = locateSynchronously();
432
+ let exe = locateSynchronously()
443
433
  if (!exe) {
444
434
  throw Error(
445
- 'The ' + GECKO_DRIVER_EXE + ' executable could not be found on the current ' +
435
+ 'The ' +
436
+ GECKO_DRIVER_EXE +
437
+ ' executable could not be found on the current ' +
446
438
  'PATH. Please download the latest version from ' +
447
439
  'https://github.com/mozilla/geckodriver/releases/ ' +
448
- 'and ensure it can be found on your PATH.');
440
+ 'and ensure it can be found on your PATH.'
441
+ )
449
442
  }
450
- return exe;
443
+ return exe
451
444
  }
452
445
 
453
-
454
446
  /**
455
447
  * @param {string} file Path to the file to find, relative to the program files
456
448
  * root.
@@ -460,24 +452,24 @@ function findGeckoDriver() {
460
452
  function findInProgramFiles(file) {
461
453
  let files = [
462
454
  process.env['PROGRAMFILES'] || 'C:\\Program Files',
463
- process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)'
464
- ].map(prefix => path.join(prefix, file));
465
- return io.exists(files[0]).then(function(exists) {
466
- return exists ? files[0] : io.exists(files[1]).then(function(exists) {
467
- return exists ? files[1] : null;
468
- });
469
- });
455
+ process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)',
456
+ ].map((prefix) => path.join(prefix, file))
457
+ return io.exists(files[0]).then(function (exists) {
458
+ return exists
459
+ ? files[0]
460
+ : io.exists(files[1]).then(function (exists) {
461
+ return exists ? files[1] : null
462
+ })
463
+ })
470
464
  }
471
465
 
472
-
473
466
  /** @enum {string} */
474
467
  const ExtensionCommand = {
475
468
  GET_CONTEXT: 'getContext',
476
469
  SET_CONTEXT: 'setContext',
477
470
  INSTALL_ADDON: 'install addon',
478
471
  UNINSTALL_ADDON: 'uninstall addon',
479
- };
480
-
472
+ }
481
473
 
482
474
  /**
483
475
  * Creates a command executor with support for Marionette's custom commands.
@@ -485,40 +477,42 @@ const ExtensionCommand = {
485
477
  * @return {!command.Executor} The new command executor.
486
478
  */
487
479
  function createExecutor(serverUrl) {
488
- let client = serverUrl.then(url => new http.HttpClient(url));
489
- let executor = new http.Executor(client);
490
- configureExecutor(executor);
491
- return executor;
480
+ let client = serverUrl.then((url) => new http.HttpClient(url))
481
+ let executor = new http.Executor(client)
482
+ configureExecutor(executor)
483
+ return executor
492
484
  }
493
485
 
494
-
495
486
  /**
496
487
  * Configures the given executor with Firefox-specific commands.
497
488
  * @param {!http.Executor} executor the executor to configure.
498
489
  */
499
490
  function configureExecutor(executor) {
500
491
  executor.defineCommand(
501
- ExtensionCommand.GET_CONTEXT,
502
- 'GET',
503
- '/session/:sessionId/moz/context');
492
+ ExtensionCommand.GET_CONTEXT,
493
+ 'GET',
494
+ '/session/:sessionId/moz/context'
495
+ )
504
496
 
505
497
  executor.defineCommand(
506
- ExtensionCommand.SET_CONTEXT,
507
- 'POST',
508
- '/session/:sessionId/moz/context');
498
+ ExtensionCommand.SET_CONTEXT,
499
+ 'POST',
500
+ '/session/:sessionId/moz/context'
501
+ )
509
502
 
510
503
  executor.defineCommand(
511
- ExtensionCommand.INSTALL_ADDON,
512
- 'POST',
513
- '/session/:sessionId/moz/addon/install');
504
+ ExtensionCommand.INSTALL_ADDON,
505
+ 'POST',
506
+ '/session/:sessionId/moz/addon/install'
507
+ )
514
508
 
515
509
  executor.defineCommand(
516
- ExtensionCommand.UNINSTALL_ADDON,
517
- 'POST',
518
- '/session/:sessionId/moz/addon/uninstall');
510
+ ExtensionCommand.UNINSTALL_ADDON,
511
+ 'POST',
512
+ '/session/:sessionId/moz/addon/uninstall'
513
+ )
519
514
  }
520
515
 
521
-
522
516
  /**
523
517
  * Creates {@link selenium-webdriver/remote.DriverService} instances that manage
524
518
  * a [geckodriver](https://github.com/mozilla/geckodriver) server in a child
@@ -530,8 +524,8 @@ class ServiceBuilder extends remote.DriverService.Builder {
530
524
  * the builder will attempt to locate the geckodriver on the system PATH.
531
525
  */
532
526
  constructor(opt_exe) {
533
- super(opt_exe || findGeckoDriver());
534
- this.setLoopback(true); // Required.
527
+ super(opt_exe || findGeckoDriver())
528
+ this.setLoopback(true) // Required.
535
529
  }
536
530
 
537
531
  /**
@@ -542,11 +536,10 @@ class ServiceBuilder extends remote.DriverService.Builder {
542
536
  * @return {!ServiceBuilder} A self reference.
543
537
  */
544
538
  enableVerboseLogging(opt_trace) {
545
- return this.addArguments(opt_trace ? '-vv' : '-v');
539
+ return this.addArguments(opt_trace ? '-vv' : '-v')
546
540
  }
547
541
  }
548
542
 
549
-
550
543
  /**
551
544
  * A WebDriver client for Firefox.
552
545
  */
@@ -575,25 +568,24 @@ class Driver extends webdriver.WebDriver {
575
568
  */
576
569
  static createSession(opt_config, opt_executor) {
577
570
  let caps =
578
- opt_config instanceof Capabilities
579
- ? opt_config : new Options(opt_config);
571
+ opt_config instanceof Capabilities ? opt_config : new Options(opt_config)
580
572
 
581
- let executor;
582
- let onQuit;
573
+ let executor
574
+ let onQuit
583
575
 
584
576
  if (opt_executor instanceof http.Executor) {
585
- executor = opt_executor;
586
- configureExecutor(executor);
577
+ executor = opt_executor
578
+ configureExecutor(executor)
587
579
  } else if (opt_executor instanceof remote.DriverService) {
588
- executor = createExecutor(opt_executor.start());
589
- onQuit = () => opt_executor.kill();
580
+ executor = createExecutor(opt_executor.start())
581
+ onQuit = () => opt_executor.kill()
590
582
  } else {
591
- let service = new ServiceBuilder().build();
592
- executor = createExecutor(service.start());
593
- onQuit = () => service.kill();
583
+ let service = new ServiceBuilder().build()
584
+ executor = createExecutor(service.start())
585
+ onQuit = () => service.kill()
594
586
  }
595
587
 
596
- return /** @type {!Driver} */(super.createSession(executor, caps, onQuit));
588
+ return /** @type {!Driver} */ (super.createSession(executor, caps, onQuit))
597
589
  }
598
590
 
599
591
  /**
@@ -601,8 +593,7 @@ class Driver extends webdriver.WebDriver {
601
593
  * implementation.
602
594
  * @override
603
595
  */
604
- setFileDetector() {
605
- }
596
+ setFileDetector() { }
606
597
 
607
598
  /**
608
599
  * Get the context that is currently in effect.
@@ -610,7 +601,7 @@ class Driver extends webdriver.WebDriver {
610
601
  * @return {!Promise<Context>} Current context.
611
602
  */
612
603
  getContext() {
613
- return this.execute(new command.Command(ExtensionCommand.GET_CONTEXT));
604
+ return this.execute(new command.Command(ExtensionCommand.GET_CONTEXT))
614
605
  }
615
606
 
616
607
  /**
@@ -629,8 +620,11 @@ class Driver extends webdriver.WebDriver {
629
620
  */
630
621
  setContext(ctx) {
631
622
  return this.execute(
632
- new command.Command(ExtensionCommand.SET_CONTEXT)
633
- .setParameter("context", ctx));
623
+ new command.Command(ExtensionCommand.SET_CONTEXT).setParameter(
624
+ 'context',
625
+ ctx
626
+ )
627
+ )
634
628
  }
635
629
 
636
630
  /**
@@ -641,18 +635,19 @@ class Driver extends webdriver.WebDriver {
641
635
  *
642
636
  * @param {string} path Path on the local filesystem to the web extension to
643
637
  * install.
644
- * @param {boolean} temporary Flag indicating whether the extension should be
638
+ * @param {boolean} temporary Flag indicating whether the extension should be
645
639
  * installed temporarily - gets removed on restart
646
640
  * @return {!Promise<string>} A promise that will resolve to an ID for the
647
641
  * newly installed addon.
648
642
  * @see #uninstallAddon
649
643
  */
650
- async installAddon(path, temporary=false) {
651
- let buf = await io.read(path);
644
+ async installAddon(path, temporary = false) {
645
+ let buf = await io.read(path)
652
646
  return this.execute(
653
- new command.Command(ExtensionCommand.INSTALL_ADDON)
654
- .setParameter('addon', buf.toString('base64'))
655
- .setParameter('temporary', temporary));
647
+ new command.Command(ExtensionCommand.INSTALL_ADDON)
648
+ .setParameter('addon', buf.toString('base64'))
649
+ .setParameter('temporary', temporary)
650
+ )
656
651
  }
657
652
 
658
653
  /**
@@ -664,14 +659,16 @@ class Driver extends webdriver.WebDriver {
664
659
  * @see #installAddon
665
660
  */
666
661
  async uninstallAddon(id) {
667
- id = await Promise.resolve(id);
662
+ id = await Promise.resolve(id)
668
663
  return this.execute(
669
- new command.Command(ExtensionCommand.UNINSTALL_ADDON)
670
- .setParameter('id', id));
664
+ new command.Command(ExtensionCommand.UNINSTALL_ADDON).setParameter(
665
+ 'id',
666
+ id
667
+ )
668
+ )
671
669
  }
672
670
  }
673
671
 
674
-
675
672
  /**
676
673
  * Provides methods for locating the executable for a Firefox release channel
677
674
  * on Windows and MacOS. For other systems (i.e. Linux), Firefox will always
@@ -685,10 +682,10 @@ class Channel {
685
682
  * @param {string} win32 The path to check when running on Windows.
686
683
  */
687
684
  constructor(darwin, win32) {
688
- /** @private @const */ this.darwin_ = darwin;
689
- /** @private @const */ this.win32_ = win32;
685
+ /** @private @const */ this.darwin_ = darwin
686
+ /** @private @const */ this.win32_ = win32
690
687
  /** @private {Promise<string>} */
691
- this.found_ = null;
688
+ this.found_ = null
692
689
  }
693
690
 
694
691
  /**
@@ -702,43 +699,44 @@ class Channel {
702
699
  */
703
700
  locate() {
704
701
  if (this.found_) {
705
- return this.found_;
702
+ return this.found_
706
703
  }
707
704
 
708
- let found;
705
+ let found
709
706
  switch (process.platform) {
710
707
  case 'darwin':
711
- found = io.exists(this.darwin_)
712
- .then(exists => exists ? this.darwin_ : io.findInPath('firefox'));
713
- break;
708
+ found = io
709
+ .exists(this.darwin_)
710
+ .then((exists) => (exists ? this.darwin_ : io.findInPath('firefox')))
711
+ break
714
712
 
715
713
  case 'win32':
716
- found = findInProgramFiles(this.win32_)
717
- .then(found => found || io.findInPath('firefox.exe'));
718
- break;
714
+ found = findInProgramFiles(this.win32_).then(
715
+ (found) => found || io.findInPath('firefox.exe')
716
+ )
717
+ break
719
718
 
720
719
  default:
721
- found = Promise.resolve(io.findInPath('firefox'));
722
- break;
720
+ found = Promise.resolve(io.findInPath('firefox'))
721
+ break
723
722
  }
724
723
 
725
- this.found_ = found.then(found => {
724
+ this.found_ = found.then((found) => {
726
725
  if (found) {
727
726
  // TODO: verify version info.
728
- return found;
727
+ return found
729
728
  }
730
- throw Error('Could not locate Firefox on the current system');
731
- });
732
- return this.found_;
729
+ throw Error('Could not locate Firefox on the current system')
730
+ })
731
+ return this.found_
733
732
  }
734
733
 
735
734
  /** @return {!Promise<string>} */
736
735
  [Symbols.serialize]() {
737
- return this.locate();
736
+ return this.locate()
738
737
  }
739
738
  }
740
739
 
741
-
742
740
  /**
743
741
  * Firefox's developer channel.
744
742
  * @const
@@ -746,7 +744,8 @@ class Channel {
746
744
  */
747
745
  Channel.AURORA = new Channel(
748
746
  '/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox-bin',
749
- 'Firefox Developer Edition\\firefox.exe');
747
+ 'Firefox Developer Edition\\firefox.exe'
748
+ )
750
749
 
751
750
  /**
752
751
  * Firefox's beta channel. Note this is provided mainly for convenience as
@@ -757,7 +756,8 @@ Channel.AURORA = new Channel(
757
756
  */
758
757
  Channel.BETA = new Channel(
759
758
  '/Applications/Firefox.app/Contents/MacOS/firefox-bin',
760
- 'Mozilla Firefox\\firefox.exe');
759
+ 'Mozilla Firefox\\firefox.exe'
760
+ )
761
761
 
762
762
  /**
763
763
  * Firefox's release channel.
@@ -766,7 +766,8 @@ Channel.BETA = new Channel(
766
766
  */
767
767
  Channel.RELEASE = new Channel(
768
768
  '/Applications/Firefox.app/Contents/MacOS/firefox-bin',
769
- 'Mozilla Firefox\\firefox.exe');
769
+ 'Mozilla Firefox\\firefox.exe'
770
+ )
770
771
 
771
772
  /**
772
773
  * Firefox's nightly release channel.
@@ -775,15 +776,14 @@ Channel.RELEASE = new Channel(
775
776
  */
776
777
  Channel.NIGHTLY = new Channel(
777
778
  '/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin',
778
- 'Nightly\\firefox.exe');
779
-
779
+ 'Nightly\\firefox.exe'
780
+ )
780
781
 
781
782
  // PUBLIC API
782
783
 
783
-
784
- exports.Channel = Channel;
785
- exports.Context = Context;
786
- exports.Driver = Driver;
787
- exports.Options = Options;
788
- exports.ServiceBuilder = ServiceBuilder;
789
- exports.locateSynchronously = locateSynchronously;
784
+ exports.Channel = Channel
785
+ exports.Context = Context
786
+ exports.Driver = Driver
787
+ exports.Options = Options
788
+ exports.ServiceBuilder = ServiceBuilder
789
+ exports.locateSynchronously = locateSynchronously