selenium-webdriver 3.3.0 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGES.md +273 -0
  2. package/NOTICE +1 -1
  3. package/README.md +28 -36
  4. package/chrome.js +221 -146
  5. package/edge.js +43 -118
  6. package/example/chrome_android.js +8 -9
  7. package/example/chrome_mobile_emulation.js +9 -10
  8. package/example/firefox_channels.js +23 -19
  9. package/example/google_search.js +3 -3
  10. package/example/google_search_test.js +39 -27
  11. package/example/headless.js +55 -0
  12. package/example/logging.js +40 -7
  13. package/firefox.js +769 -0
  14. package/http/index.js +41 -4
  15. package/http/util.js +11 -6
  16. package/ie.js +57 -98
  17. package/index.js +182 -115
  18. package/io/index.js +59 -0
  19. package/io/zip.js +214 -0
  20. package/jasmine.json +11 -0
  21. package/lib/actions.js +68 -63
  22. package/lib/atoms/get-attribute.js +9 -0
  23. package/lib/atoms/is-displayed.js +73 -78
  24. package/lib/by.js +9 -1
  25. package/lib/capabilities.js +303 -201
  26. package/lib/command.js +28 -50
  27. package/lib/error.js +113 -42
  28. package/lib/http.js +167 -135
  29. package/lib/input.js +1044 -8
  30. package/lib/promise.js +222 -3331
  31. package/lib/proxy.js +134 -39
  32. package/lib/test/bootstrap_jasmine.js +28 -0
  33. package/lib/test/data/actions/click.html +24 -0
  34. package/lib/test/data/actions/drag.html +77 -0
  35. package/lib/test/data/actions/record_click.html +21 -0
  36. package/lib/test/data/chrome/download.html +2 -0
  37. package/lib/test/data/click_tests/disabled_element.html +12 -0
  38. package/lib/test/data/content-editable.html +10 -0
  39. package/lib/test/data/firefox/webextension.xpi +0 -0
  40. package/lib/test/data/inputs.html +42 -0
  41. package/lib/test/data/key_logger.html +34 -0
  42. package/lib/test/data/nestedElements.html +10 -1
  43. package/lib/test/data/scrolling_tests/page_with_partially_hidden_element.html +14 -0
  44. package/lib/test/data/selectPage.html +12 -0
  45. package/lib/test/data/simpleTest.html +5 -0
  46. package/lib/test/data/single_text_input.html +12 -0
  47. package/lib/test/data/upload_invisible.html +45 -0
  48. package/lib/test/fileserver.js +23 -19
  49. package/lib/test/index.js +30 -244
  50. package/lib/test/resources.js +0 -1
  51. package/lib/webdriver.js +770 -939
  52. package/net/index.js +21 -25
  53. package/net/portprober.js +51 -68
  54. package/package.json +6 -4
  55. package/remote/index.js +18 -30
  56. package/safari.js +42 -129
  57. package/test/actions_test.js +173 -18
  58. package/test/builder_test.js +106 -0
  59. package/test/chrome/devtools_test.js +93 -0
  60. package/test/chrome/options_test.js +48 -154
  61. package/test/chrome/service_test.js +7 -7
  62. package/test/cookie_test.js +77 -63
  63. package/test/element_finding_test.js +206 -201
  64. package/test/execute_script_test.js +115 -114
  65. package/test/fingerprint_test.js +16 -15
  66. package/test/firefox_test.js +251 -0
  67. package/test/http/http_test.js +18 -1
  68. package/test/http/util_test.js +2 -2
  69. package/test/{io_test.js → io/io_test.js} +40 -1
  70. package/test/io/zip_test.js +127 -0
  71. package/test/lib/by_test.js +21 -0
  72. package/test/lib/error_test.js +55 -8
  73. package/test/lib/http_test.js +18 -130
  74. package/test/lib/input_test.js +1379 -0
  75. package/test/lib/promise_test.js +473 -908
  76. package/test/lib/webdriver_test.js +357 -825
  77. package/test/logging_test.js +37 -43
  78. package/test/page_loading_test.js +70 -86
  79. package/test/proxy_test.js +64 -72
  80. package/test/rect_test.js +14 -25
  81. package/test/remote_test.js +13 -32
  82. package/test/safari_test.js +7 -71
  83. package/test/stale_element_test.js +20 -23
  84. package/test/tag_name_test.js +10 -9
  85. package/test/upload_test.js +27 -35
  86. package/test/window_test.js +72 -85
  87. package/testing/index.js +386 -315
  88. package/.npmignore +0 -2
  89. package/example/async_await_test.js +0 -68
  90. package/example/google_search_generator.js +0 -50
  91. package/example/parallel_flows.js +0 -54
  92. package/firefox/binary.js +0 -344
  93. package/firefox/extension.js +0 -187
  94. package/firefox/index.js +0 -722
  95. package/firefox/profile.js +0 -430
  96. package/lib/atoms/getAttribute.js +0 -12
  97. package/lib/events.js +0 -210
  98. package/lib/firefox/webdriver.json +0 -70
  99. package/lib/firefox/webdriver.xpi +0 -0
  100. package/lib/test/data/firefox/jetpack-sample.xpi +0 -0
  101. package/lib/test/data/firefox/sample.xpi +0 -0
  102. package/lib/test/promise.js +0 -79
  103. package/opera.js +0 -405
  104. package/phantomjs.js +0 -282
  105. package/test/firefox/extension_test.js +0 -96
  106. package/test/firefox/firefox_test.js +0 -226
  107. package/test/firefox/profile_test.js +0 -185
  108. package/test/lib/events_test.js +0 -177
  109. package/test/lib/promise_aplus_test.js +0 -78
  110. package/test/lib/promise_error_test.js +0 -884
  111. package/test/lib/promise_flow_test.js +0 -2288
  112. package/test/lib/promise_generator_test.js +0 -310
  113. package/test/phantomjs/execute_phantomjs_test.js +0 -59
  114. package/test/session_test.js +0 -54
  115. package/test/testing/assert_test.js +0 -373
  116. package/test/testing/index_test.js +0 -224
  117. package/testing/assert.js +0 -378
package/index.js CHANGED
@@ -22,27 +22,23 @@
22
22
 
23
23
  'use strict';
24
24
 
25
- const chrome = require('./chrome');
26
- const edge = require('./edge');
27
- const firefox = require('./firefox');
28
25
  const _http = require('./http');
29
- const ie = require('./ie');
30
- const actions = require('./lib/actions');
31
26
  const by = require('./lib/by');
32
27
  const capabilities = require('./lib/capabilities');
28
+ const chrome = require('./chrome');
33
29
  const command = require('./lib/command');
30
+ const edge = require('./edge');
34
31
  const error = require('./lib/error');
35
- const events = require('./lib/events');
32
+ const firefox = require('./firefox');
33
+ const ie = require('./ie');
36
34
  const input = require('./lib/input');
37
35
  const logging = require('./lib/logging');
38
36
  const promise = require('./lib/promise');
37
+ const remote = require('./remote');
38
+ const safari = require('./safari');
39
39
  const session = require('./lib/session');
40
40
  const until = require('./lib/until');
41
41
  const webdriver = require('./lib/webdriver');
42
- const opera = require('./opera');
43
- const phantomjs = require('./phantomjs');
44
- const remote = require('./remote');
45
- const safari = require('./safari');
46
42
 
47
43
  const Browser = capabilities.Browser;
48
44
  const Capabilities = capabilities.Capabilities;
@@ -107,7 +103,7 @@ function ensureFileDetectorsAreEnabled(ctor) {
107
103
  * every issued command will fail.
108
104
  *
109
105
  * @extends {webdriver.IWebDriver}
110
- * @extends {promise.CancellableThenable<!webdriver.IWebDriver>}
106
+ * @extends {IThenable<!webdriver.IWebDriver>}
111
107
  * @interface
112
108
  */
113
109
  class ThenableWebDriver {
@@ -131,7 +127,10 @@ const THENABLE_DRIVERS = new Map;
131
127
  function createDriver(ctor, ...args) {
132
128
  let thenableWebDriverProxy = THENABLE_DRIVERS.get(ctor);
133
129
  if (!thenableWebDriverProxy) {
134
- /** @implements {ThenableWebDriver} */
130
+ /**
131
+ * @extends {WebDriver} // Needed since `ctor` is dynamically typed.
132
+ * @implements {ThenableWebDriver}
133
+ */
135
134
  thenableWebDriverProxy = class extends ctor {
136
135
  /**
137
136
  * @param {!IThenable<!Session>} session
@@ -144,24 +143,13 @@ function createDriver(ctor, ...args) {
144
143
  return new ctor(session, ...rest);
145
144
  });
146
145
 
147
- /**
148
- * @param {(string|Error)=} opt_reason
149
- * @override
150
- */
151
- this.cancel = function(opt_reason) {
152
- if (promise.CancellableThenable.isImplementation(pd)) {
153
- /** @type {!promise.CancellableThenable} */(pd).cancel(opt_reason);
154
- }
155
- };
156
-
157
146
  /** @override */
158
147
  this.then = pd.then.bind(pd);
159
148
 
160
149
  /** @override */
161
- this.catch = pd.then.bind(pd);
150
+ this.catch = pd.catch.bind(pd);
162
151
  }
163
152
  };
164
- promise.CancellableThenable.addImplementation(thenableWebDriverProxy);
165
153
  THENABLE_DRIVERS.set(ctor, thenableWebDriverProxy);
166
154
  }
167
155
  return thenableWebDriverProxy.createSession(...args);
@@ -212,9 +200,6 @@ class Builder {
212
200
  /** @private @const */
213
201
  this.log_ = logging.getLogger('webdriver.Builder');
214
202
 
215
- /** @private {promise.ControlFlow} */
216
- this.flow_ = null;
217
-
218
203
  /** @private {string} */
219
204
  this.url_ = '';
220
205
 
@@ -227,11 +212,14 @@ class Builder {
227
212
  /** @private {chrome.Options} */
228
213
  this.chromeOptions_ = null;
229
214
 
215
+ /** @private {chrome.ServiceBuilder} */
216
+ this.chromeService_ = null;
217
+
230
218
  /** @private {firefox.Options} */
231
219
  this.firefoxOptions_ = null;
232
220
 
233
- /** @private {opera.Options} */
234
- this.operaOptions_ = null;
221
+ /** @private {firefox.ServiceBuilder} */
222
+ this.firefoxService_ = null;
235
223
 
236
224
  /** @private {ie.Options} */
237
225
  this.ieOptions_ = null;
@@ -242,6 +230,9 @@ class Builder {
242
230
  /** @private {edge.Options} */
243
231
  this.edgeOptions_ = null;
244
232
 
233
+ /** @private {remote.DriverService.Builder} */
234
+ this.edgeService_ = null;
235
+
245
236
  /** @private {boolean} */
246
237
  this.ignoreEnv_ = false;
247
238
 
@@ -355,18 +346,22 @@ class Builder {
355
346
  * environment variable. If set, this environment variable should be of the
356
347
  * form `browser[:[version][:platform]]`.
357
348
  *
358
- * @param {(string|Browser)} name The name of the target browser;
349
+ * @param {(string|!Browser)} name The name of the target browser;
359
350
  * common defaults are available on the {@link webdriver.Browser} enum.
360
351
  * @param {string=} opt_version A desired version; may be omitted if any
361
352
  * version should be used.
362
- * @param {string=} opt_platform The desired platform; may be omitted if any
363
- * version may be used.
353
+ * @param {(string|!capabilities.Platform)=} opt_platform
354
+ * The desired platform; may be omitted if any platform may be used.
364
355
  * @return {!Builder} A self reference.
365
356
  */
366
357
  forBrowser(name, opt_version, opt_platform) {
367
- this.capabilities_.set(Capability.BROWSER_NAME, name);
368
- this.capabilities_.set(Capability.VERSION, opt_version || null);
369
- this.capabilities_.set(Capability.PLATFORM, opt_platform || null);
358
+ this.capabilities_.setBrowserName(name);
359
+ if (opt_version) {
360
+ this.capabilities_.setBrowserVersion(opt_version);
361
+ }
362
+ if (opt_platform) {
363
+ this.capabilities_.setPlatform(opt_platform);
364
+ }
370
365
  return this;
371
366
  }
372
367
 
@@ -375,7 +370,7 @@ class Builder {
375
370
  * Any calls to {@link #withCapabilities} after this function will
376
371
  * overwrite these settings.
377
372
  *
378
- * @param {!capabilities.ProxyConfig} config The configuration to use.
373
+ * @param {!./lib/proxy.Config} config The configuration to use.
379
374
  * @return {!Builder} A self reference.
380
375
  */
381
376
  setProxy(config) {
@@ -395,33 +390,13 @@ class Builder {
395
390
  return this;
396
391
  }
397
392
 
398
- /**
399
- * Sets whether native events should be used.
400
- * @param {boolean} enabled Whether to enable native events.
401
- * @return {!Builder} A self reference.
402
- */
403
- setEnableNativeEvents(enabled) {
404
- this.capabilities_.setEnableNativeEvents(enabled);
405
- return this;
406
- }
407
-
408
- /**
409
- * Sets how elements should be scrolled into view for interaction.
410
- * @param {number} behavior The desired scroll behavior: either 0 to align
411
- * with the top of the viewport or 1 to align with the bottom.
412
- * @return {!Builder} A self reference.
413
- */
414
- setScrollBehavior(behavior) {
415
- this.capabilities_.setScrollBehavior(behavior);
416
- return this;
417
- }
418
-
419
393
  /**
420
394
  * Sets the default action to take with an unexpected alert before returning
421
395
  * an error.
422
- * @param {string} behavior The desired behavior; should be "accept",
423
- * "dismiss", or "ignore". Defaults to "dismiss".
396
+ *
397
+ * @param {?capabilities.UserPromptHandler} behavior The desired behavior.
424
398
  * @return {!Builder} A self reference.
399
+ * @see capabilities.Capabilities#setAlertBehavior
425
400
  */
426
401
  setAlertBehavior(behavior) {
427
402
  this.capabilities_.setAlertBehavior(behavior);
@@ -442,6 +417,29 @@ class Builder {
442
417
  return this;
443
418
  }
444
419
 
420
+ /**
421
+ * @return {chrome.Options} the Chrome specific options currently configured
422
+ * for this builder.
423
+ */
424
+ getChromeOptions() {
425
+ return this.chromeOptions_;
426
+ }
427
+
428
+ /**
429
+ * Sets the service builder to use for managing the chromedriver child process
430
+ * when creating new Chrome sessions.
431
+ *
432
+ * @param {chrome.ServiceBuilder} service the service to use.
433
+ * @return {!Builder} A self reference.
434
+ */
435
+ setChromeService(service) {
436
+ if (service && !(service instanceof chrome.ServiceBuilder)) {
437
+ throw TypeError('not a chrome.ServiceBuilder object');
438
+ }
439
+ this.chromeService_ = service;
440
+ return this;
441
+ }
442
+
445
443
  /**
446
444
  * Sets Firefox specific {@linkplain firefox.Options options} for drivers
447
445
  * created by this builder. Any logging or proxy settings defined on the given
@@ -465,16 +463,17 @@ class Builder {
465
463
  }
466
464
 
467
465
  /**
468
- * Sets Opera specific {@linkplain opera.Options options} for drivers created
469
- * by this builder. Any logging or proxy settings defined on the given options
470
- * will take precedence over those set through {@link #setLoggingPrefs} and
471
- * {@link #setProxy}, respectively.
466
+ * Sets the {@link firefox.ServiceBuilder} to use to manage the geckodriver
467
+ * child process when creating Firefox sessions locally.
472
468
  *
473
- * @param {!opera.Options} options The OperaDriver options to use.
474
- * @return {!Builder} A self reference.
469
+ * @param {firefox.ServiceBuilder} service the service to use.
470
+ * @return {!Builder} a self reference.
475
471
  */
476
- setOperaOptions(options) {
477
- this.operaOptions_ = options;
472
+ setFirefoxService(service) {
473
+ if (service && !(service instanceof firefox.ServiceBuilder)) {
474
+ throw TypeError('not a firefox.ServiceBuilder object');
475
+ }
476
+ this.firefoxService_ = service;
478
477
  return this;
479
478
  }
480
479
 
@@ -505,6 +504,21 @@ class Builder {
505
504
  return this;
506
505
  }
507
506
 
507
+ /**
508
+ * Sets the {@link edge.ServiceBuilder} to use to manage the
509
+ * MicrosoftEdgeDriver child process when creating sessions locally.
510
+ *
511
+ * @param {edge.ServiceBuilder} service the service to use.
512
+ * @return {!Builder} a self reference.
513
+ */
514
+ setEdgeService(service) {
515
+ if (service && !(service instanceof edge.ServiceBuilder)) {
516
+ throw TypeError('not a edge.ServiceBuilder object');
517
+ }
518
+ this.edgeService_ = service;
519
+ return this;
520
+ }
521
+
508
522
  /**
509
523
  * Sets Safari specific {@linkplain safari.Options options} for drivers
510
524
  * created by this builder. Any logging settings defined on the given options
@@ -526,19 +540,6 @@ class Builder {
526
540
  return this.safariOptions_;
527
541
  }
528
542
 
529
- /**
530
- * Sets the control flow that created drivers should execute actions in. If
531
- * the flow is never set, or is set to {@code null}, it will use the active
532
- * flow at the time {@link #build()} is called.
533
- * @param {promise.ControlFlow} flow The control flow to use, or
534
- * {@code null} to
535
- * @return {!Builder} A self reference.
536
- */
537
- setControlFlow(flow) {
538
- this.flow_ = flow;
539
- return this;
540
- }
541
-
542
543
  /**
543
544
  * Creates a new WebDriver client based on this builder's current
544
545
  * configuration.
@@ -561,9 +562,10 @@ class Builder {
561
562
  if (!this.ignoreEnv_ && process.env.SELENIUM_BROWSER) {
562
563
  this.log_.fine(`SELENIUM_BROWSER=${process.env.SELENIUM_BROWSER}`);
563
564
  browser = process.env.SELENIUM_BROWSER.split(/:/, 3);
564
- capabilities.set(Capability.BROWSER_NAME, browser[0]);
565
- capabilities.set(Capability.VERSION, browser[1] || null);
566
- capabilities.set(Capability.PLATFORM, browser[2] || null);
565
+ capabilities.setBrowserName(browser[0]);
566
+
567
+ browser[1] && capabilities.setBrowserVersion(browser[1]);
568
+ browser[2] && capabilities.setPlatform(browser[2]);
567
569
  }
568
570
 
569
571
  browser = capabilities.get(Capability.BROWSER_NAME);
@@ -580,24 +582,29 @@ class Builder {
580
582
 
581
583
  // Apply browser specific overrides.
582
584
  if (browser === Browser.CHROME && this.chromeOptions_) {
583
- capabilities.merge(this.chromeOptions_.toCapabilities());
585
+ capabilities.merge(this.chromeOptions_);
584
586
 
585
587
  } else if (browser === Browser.FIREFOX && this.firefoxOptions_) {
586
- capabilities.merge(this.firefoxOptions_.toCapabilities());
588
+ capabilities.merge(this.firefoxOptions_);
587
589
 
588
590
  } else if (browser === Browser.INTERNET_EXPLORER && this.ieOptions_) {
589
- capabilities.merge(this.ieOptions_.toCapabilities());
590
-
591
- } else if (browser === Browser.OPERA && this.operaOptions_) {
592
- capabilities.merge(this.operaOptions_.toCapabilities());
591
+ capabilities.merge(this.ieOptions_);
593
592
 
594
593
  } else if (browser === Browser.SAFARI && this.safariOptions_) {
595
- capabilities.merge(this.safariOptions_.toCapabilities());
594
+ capabilities.merge(this.safariOptions_);
596
595
 
597
596
  } else if (browser === Browser.EDGE && this.edgeOptions_) {
598
- capabilities.merge(this.edgeOptions_.toCapabilities());
597
+ capabilities.merge(this.edgeOptions_);
599
598
  }
600
599
 
600
+ checkOptions(
601
+ capabilities, 'chromeOptions', chrome.Options, 'setChromeOptions');
602
+ checkOptions(
603
+ capabilities, 'moz:firefoxOptions', firefox.Options,
604
+ 'setFirefoxOptions');
605
+ checkOptions(
606
+ capabilities, 'safari.options', safari.Options, 'setSafariOptions');
607
+
601
608
  // Check for a remote browser.
602
609
  let url = this.url_;
603
610
  if (!this.ignoreEnv_) {
@@ -620,41 +627,47 @@ class Builder {
620
627
 
621
628
  if (browser === Browser.CHROME) {
622
629
  const driver = ensureFileDetectorsAreEnabled(chrome.Driver);
623
- return createDriver(
624
- driver, capabilities, executor, this.flow_);
630
+ return createDriver(driver, capabilities, executor);
625
631
  }
626
632
 
627
633
  if (browser === Browser.FIREFOX) {
628
634
  const driver = ensureFileDetectorsAreEnabled(firefox.Driver);
629
- return createDriver(
630
- driver, capabilities, executor, this.flow_);
635
+ return createDriver(driver, capabilities, executor);
631
636
  }
632
- return createDriver(
633
- WebDriver, executor, capabilities, this.flow_);
637
+ return createDriver(WebDriver, executor, capabilities);
634
638
  }
635
639
 
636
640
  // Check for a native browser.
637
641
  switch (browser) {
638
- case Browser.CHROME:
639
- return createDriver(chrome.Driver, capabilities, null, this.flow_);
642
+ case Browser.CHROME: {
643
+ let service = null;
644
+ if (this.chromeService_) {
645
+ service = this.chromeService_.build();
646
+ }
647
+ return createDriver(chrome.Driver, capabilities, service);
648
+ }
640
649
 
641
- case Browser.FIREFOX:
642
- return createDriver(firefox.Driver, capabilities, null, this.flow_);
650
+ case Browser.FIREFOX: {
651
+ let service = null;
652
+ if (this.firefoxService_) {
653
+ service = this.firefoxService_.build();
654
+ }
655
+ return createDriver(firefox.Driver, capabilities, service);
656
+ }
643
657
 
644
658
  case Browser.INTERNET_EXPLORER:
645
- return createDriver(ie.Driver, capabilities, this.flow_);
646
-
647
- case Browser.EDGE:
648
- return createDriver(edge.Driver, capabilities, null, this.flow_);
649
-
650
- case Browser.OPERA:
651
- return createDriver(opera.Driver, capabilities, null, this.flow_);
652
-
653
- case Browser.PHANTOM_JS:
654
- return createDriver(phantomjs.Driver, capabilities, this.flow_);
659
+ return createDriver(ie.Driver, capabilities);
660
+
661
+ case Browser.EDGE: {
662
+ let service = null;
663
+ if (this.edgeService_) {
664
+ service = this.edgeService_.build();
665
+ }
666
+ return createDriver(edge.Driver, capabilities, service);
667
+ }
655
668
 
656
669
  case Browser.SAFARI:
657
- return createDriver(safari.Driver, capabilities, this.flow_);
670
+ return createDriver(safari.Driver, capabilities);
658
671
 
659
672
  default:
660
673
  throw new Error('Do not know how to build driver: ' + browser
@@ -664,10 +677,66 @@ class Builder {
664
677
  }
665
678
 
666
679
 
680
+ /**
681
+ * In the 3.x releases, the various browser option classes
682
+ * (e.g. firefox.Options) had to be manually set as an option using the
683
+ * Capabilties class:
684
+ *
685
+ * let ffo = new firefox.Options();
686
+ * // Configure firefox options...
687
+ *
688
+ * let caps = new Capabilities();
689
+ * caps.set('moz:firefoxOptions', ffo);
690
+ *
691
+ * let driver = new Builder()
692
+ * .withCapabilities(caps)
693
+ * .build();
694
+ *
695
+ * The options are now subclasses of Capabilities and can be used directly. A
696
+ * direct translation of the above is:
697
+ *
698
+ * let ffo = new firefox.Options();
699
+ * // Configure firefox options...
700
+ *
701
+ * let driver = new Builder()
702
+ * .withCapabilities(ffo)
703
+ * .build();
704
+ *
705
+ * You can also set the options for various browsers at once and let the builder
706
+ * choose the correct set at runtime (see Builder docs above):
707
+ *
708
+ * let ffo = new firefox.Options();
709
+ * // Configure ...
710
+ *
711
+ * let co = new chrome.Options();
712
+ * // Configure ...
713
+ *
714
+ * let driver = new Builder()
715
+ * .setChromeOptions(co)
716
+ * .setFirefoxOptions(ffo)
717
+ * .build();
718
+ *
719
+ * @param {!Capabilities} caps
720
+ * @param {string} key
721
+ * @param {function(new: Capabilities)} optionType
722
+ * @param {string} setMethod
723
+ * @throws {error.InvalidArgumentError}
724
+ */
725
+ function checkOptions(caps, key, optionType, setMethod) {
726
+ let val = caps.get(key);
727
+ if (val instanceof optionType) {
728
+ throw new error.InvalidArgumentError(
729
+ 'Options class extends Capabilities and should not be set as key '
730
+ + `"${key}"; set browser-specific options with `
731
+ + `Builder.${setMethod}(). For more information, see the `
732
+ + 'documentation attached to the function that threw this error');
733
+ }
734
+ }
735
+
736
+
667
737
  // PUBLIC API
668
738
 
669
739
 
670
- exports.ActionSequence = actions.ActionSequence;
671
740
  exports.Browser = capabilities.Browser;
672
741
  exports.Builder = Builder;
673
742
  exports.Button = input.Button;
@@ -675,12 +744,10 @@ exports.By = by.By;
675
744
  exports.Capabilities = capabilities.Capabilities;
676
745
  exports.Capability = capabilities.Capability;
677
746
  exports.Condition = webdriver.Condition;
678
- exports.EventEmitter = events.EventEmitter;
679
747
  exports.FileDetector = input.FileDetector;
680
748
  exports.Key = input.Key;
681
749
  exports.Session = session.Session;
682
750
  exports.ThenableWebDriver = ThenableWebDriver;
683
- exports.TouchSequence = actions.TouchSequence;
684
751
  exports.WebDriver = webdriver.WebDriver;
685
752
  exports.WebElement = webdriver.WebElement;
686
753
  exports.WebElementCondition = webdriver.WebElementCondition;
package/io/index.js CHANGED
@@ -298,3 +298,62 @@ exports.mkdir = function(aPath) {
298
298
  });
299
299
  });
300
300
  };
301
+
302
+
303
+ /**
304
+ * Recursively creates a directory and any ancestors that do not yet exist.
305
+ *
306
+ * @param {string} dir The directory path to create.
307
+ * @return {!Promise<string>} A promise that will resolve with the path of the
308
+ * created directory.
309
+ */
310
+ exports.mkdirp = function mkdirp(dir) {
311
+ return checkedCall(callback => {
312
+ fs.mkdir(dir, undefined, err => {
313
+ if (!err) {
314
+ callback(null, dir);
315
+ return;
316
+ }
317
+
318
+ switch (err.code) {
319
+ case 'EEXIST':
320
+ callback(null, dir);
321
+ return;
322
+ case 'ENOENT':
323
+ return mkdirp(path.dirname(dir))
324
+ .then(() => mkdirp(dir))
325
+ .then(() => callback(null, dir), err => callback(err));
326
+ default:
327
+ callback(err);
328
+ return;
329
+ }
330
+ });
331
+ });
332
+ };
333
+
334
+
335
+ /**
336
+ * Recursively walks a directory, returning a promise that will resolve with
337
+ * a list of all files/directories seen.
338
+ *
339
+ * @param {string} rootPath the directory to walk.
340
+ * @return {!Promise<!Array<{path: string, dir: boolean}>>} a promise that will
341
+ * resolve with a list of entries seen. For each entry, the recorded path
342
+ * will be relative to `rootPath`.
343
+ */
344
+ exports.walkDir = function(rootPath) {
345
+ let seen = [];
346
+ return (function walk(dir) {
347
+ return checkedCall(callback => fs.readdir(dir, callback))
348
+ .then(files => Promise.all(files.map(file => {
349
+ file = path.join(dir, file);
350
+ return checkedCall(cb => fs.stat(file, cb)).then(stats => {
351
+ seen.push({
352
+ path: path.relative(rootPath, file),
353
+ dir: stats.isDirectory()
354
+ });
355
+ return stats.isDirectory() && walk(file);
356
+ });
357
+ })));
358
+ })(rootPath).then(() => seen);
359
+ };