selenium-webdriver 3.0.1 → 3.5.0
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.
- package/CHANGES.md +92 -0
- package/NOTICE +1 -1
- package/README.md +11 -14
- package/chrome.js +125 -36
- package/edge.js +3 -3
- package/example/async_await_test.js +68 -0
- package/example/chrome_headless.js +47 -0
- package/example/chrome_mobile_emulation.js +1 -1
- package/example/firefox_channels.js +73 -0
- package/example/google_search_test.js +1 -1
- package/firefox/binary.js +114 -57
- package/firefox/extension.js +118 -81
- package/firefox/index.js +67 -135
- package/firefox/profile.js +13 -49
- package/ie.js +2 -2
- package/index.js +6 -3
- package/io/index.js +59 -0
- package/io/zip.js +214 -0
- package/lib/README +2 -3
- package/lib/actions.js +4 -4
- package/lib/atoms/getAttribute.js +9 -11
- package/lib/atoms/is-displayed.js +102 -0
- package/lib/by.js +9 -1
- package/lib/capabilities.js +5 -5
- package/lib/command.js +2 -0
- package/lib/error.js +29 -4
- package/lib/events.js +1 -1
- package/lib/firefox/webdriver.json +2 -1
- package/lib/http.js +84 -69
- package/lib/input.js +1 -1
- package/lib/promise.js +205 -81
- package/lib/symbols.js +1 -1
- package/lib/test/data/click_tests/disabled_element.html +12 -0
- package/lib/test/data/firefox/webextension.xpi +0 -0
- package/lib/test/data/key_logger.html +34 -0
- package/lib/test/data/nestedElements.html +10 -1
- package/lib/test/data/single_text_input.html +12 -0
- package/lib/test/index.js +9 -35
- package/lib/until.js +1 -1
- package/lib/webdriver.js +130 -34
- package/net/portprober.js +1 -1
- package/opera.js +2 -2
- package/package.json +2 -2
- package/phantomjs.js +2 -2
- package/remote/index.js +17 -11
- package/safari.js +47 -8
- package/test/firefox/extension_test.js +41 -17
- package/test/firefox/firefox_test.js +70 -23
- package/test/firefox/profile_test.js +14 -59
- package/test/http/http_test.js +18 -0
- package/test/{io_test.js → io/io_test.js} +40 -1
- package/test/io/zip_test.js +128 -0
- package/test/lib/by_test.js +21 -0
- package/test/lib/error_test.js +20 -1
- package/test/lib/http_test.js +41 -2
- package/test/lib/promise_test.js +19 -0
- package/test/lib/until_test.js +28 -13
- package/test/lib/webdriver_test.js +107 -3
- package/test/page_loading_test.js +0 -6
- package/test/rect_test.js +60 -0
- package/test/remote_test.js +3 -3
- package/test/session_test.js +68 -23
- package/testing/index.js +16 -5
- package/lib/atoms/isDisplayed.js +0 -106
- package/lib/firefox/amd64/libnoblur64.so +0 -0
- package/lib/firefox/i386/libnoblur.so +0 -0
- package/lib/firefox/webdriver.xpi +0 -0
package/firefox/index.js
CHANGED
|
@@ -26,28 +26,31 @@
|
|
|
26
26
|
*
|
|
27
27
|
* __Customizing the Firefox Profile__
|
|
28
28
|
*
|
|
29
|
-
* The {@
|
|
30
|
-
* with WebDriver, with functions to install additional
|
|
29
|
+
* The {@linkplain Profile} class may be used to configure the browser profile
|
|
30
|
+
* used with WebDriver, with functions to install additional
|
|
31
31
|
* {@linkplain Profile#addExtension extensions}, configure browser
|
|
32
32
|
* {@linkplain Profile#setPreference preferences}, and more. For example, you
|
|
33
33
|
* may wish to include Firebug:
|
|
34
34
|
*
|
|
35
|
-
*
|
|
35
|
+
* const {Builder} = require('selenium-webdriver');
|
|
36
|
+
* const firefox = require('selenium-webdriver/firefox');
|
|
36
37
|
*
|
|
37
|
-
*
|
|
38
|
+
* let profile = new firefox.Profile();
|
|
38
39
|
* profile.addExtension('/path/to/firebug.xpi');
|
|
39
40
|
* profile.setPreference('extensions.firebug.showChromeErrors', true);
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
42
|
+
* let options = new firefox.Options().setProfile(profile);
|
|
43
|
+
* let driver = new Builder()
|
|
44
|
+
* .forBrowser('firefox')
|
|
45
|
+
* .setFirefoxOptions(options)
|
|
46
|
+
* .build();
|
|
43
47
|
*
|
|
44
|
-
* The {@
|
|
45
|
-
* pre-existing browser profile:
|
|
48
|
+
* The {@linkplain Profile} class may also be used to configure WebDriver based
|
|
49
|
+
* on a pre-existing browser profile:
|
|
46
50
|
*
|
|
47
|
-
*
|
|
51
|
+
* let profile = new firefox.Profile(
|
|
48
52
|
* '/usr/local/home/bob/.mozilla/firefox/3fgog75h.testing');
|
|
49
|
-
*
|
|
50
|
-
* var driver = new firefox.Driver(options);
|
|
53
|
+
* let options = new firefox.Options().setProfile(profile);
|
|
51
54
|
*
|
|
52
55
|
* The FirefoxDriver will _never_ modify a pre-existing profile; instead it will
|
|
53
56
|
* create a copy for it to modify. By extension, there are certain browser
|
|
@@ -56,21 +59,35 @@
|
|
|
56
59
|
*
|
|
57
60
|
* __Using a Custom Firefox Binary__
|
|
58
61
|
*
|
|
59
|
-
* On Windows and
|
|
62
|
+
* On Windows and MacOS, the FirefoxDriver will search for Firefox in its
|
|
60
63
|
* default installation location:
|
|
61
64
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
65
|
+
* - Windows: C:\Program Files and C:\Program Files (x86).
|
|
66
|
+
* - MacOS: /Applications/Firefox.app
|
|
64
67
|
*
|
|
65
|
-
* For Linux, Firefox will be located on the PATH: `$(where firefox)`.
|
|
68
|
+
* For Linux, Firefox will always be located on the PATH: `$(where firefox)`.
|
|
66
69
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
70
|
+
* Several methods are provided for starting Firefox with a custom executable.
|
|
71
|
+
* First, on Windows and MacOS, you may configure WebDriver to check the default
|
|
72
|
+
* install location for a non-release channel. If the requested channel cannot
|
|
73
|
+
* be found in its default location, WebDriver will fallback to searching your
|
|
74
|
+
* PATH. _Note:_ on Linux, Firefox is _always_ located on your path, regardless
|
|
75
|
+
* of the requested channel.
|
|
69
76
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
77
|
+
* const {Builder} = require('selenium-webdriver');
|
|
78
|
+
* const firefox = require('selenium-webdriver/firefox');
|
|
79
|
+
*
|
|
80
|
+
* let options = new firefox.Options().setBinary(firefox.Channel.NIGHTLY);
|
|
81
|
+
* let driver = new Builder()
|
|
82
|
+
* .forBrowser('firefox')
|
|
83
|
+
* .setFirefoxOptions(options)
|
|
84
|
+
* .build();
|
|
85
|
+
*
|
|
86
|
+
* On all platforms, you may configrue WebDriver to use a Firefox specific
|
|
87
|
+
* executable:
|
|
88
|
+
*
|
|
89
|
+
* let options = new firefox.Options()
|
|
90
|
+
* .setBinary('/my/firefox/install/dir/firefox-bin');
|
|
74
91
|
*
|
|
75
92
|
* __Remote Testing__
|
|
76
93
|
*
|
|
@@ -84,27 +101,19 @@
|
|
|
84
101
|
* binaries are never copied to remote machines and must be referenced by
|
|
85
102
|
* installation path.
|
|
86
103
|
*
|
|
87
|
-
*
|
|
104
|
+
* const {Builder} = require('selenium-webdriver');
|
|
105
|
+
* const firefox = require('selenium-webdriver/firefox');
|
|
106
|
+
*
|
|
107
|
+
* let options = new firefox.Options()
|
|
88
108
|
* .setProfile('/profile/path/on/remote/host')
|
|
89
109
|
* .setBinary('/install/dir/on/remote/host/firefox-bin');
|
|
90
110
|
*
|
|
91
|
-
*
|
|
111
|
+
* let driver = new Builder()
|
|
92
112
|
* .forBrowser('firefox')
|
|
93
113
|
* .usingServer('http://127.0.0.1:4444/wd/hub')
|
|
94
114
|
* .setFirefoxOptions(options)
|
|
95
115
|
* .build();
|
|
96
116
|
*
|
|
97
|
-
* __Testing Older Versions of Firefox__
|
|
98
|
-
*
|
|
99
|
-
* To test versions of Firefox prior to Firefox 47, you must disable the use of
|
|
100
|
-
* the geckodriver using the {@link Options} class.
|
|
101
|
-
*
|
|
102
|
-
* var options = new firefox.Options().useGeckoDriver(false);
|
|
103
|
-
* var driver = new firefox.Driver(options);
|
|
104
|
-
*
|
|
105
|
-
* Alternatively, you may disable the geckodriver at runtime by setting the
|
|
106
|
-
* environment variable `SELENIUM_MARIONETTE=false`.
|
|
107
|
-
*
|
|
108
117
|
* [geckodriver release]: https://github.com/mozilla/geckodriver/releases/
|
|
109
118
|
* [PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
|
|
110
119
|
*/
|
|
@@ -113,7 +122,7 @@
|
|
|
113
122
|
|
|
114
123
|
const url = require('url');
|
|
115
124
|
|
|
116
|
-
const Binary = require('./binary')
|
|
125
|
+
const {Binary, Channel} = require('./binary'),
|
|
117
126
|
Profile = require('./profile').Profile,
|
|
118
127
|
decodeProfile = require('./profile').decode,
|
|
119
128
|
http = require('../http'),
|
|
@@ -144,8 +153,8 @@ const Capability = {
|
|
|
144
153
|
BINARY: 'firefox_binary',
|
|
145
154
|
|
|
146
155
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
156
|
+
* @deprecated This will be removed in a future release. There is no
|
|
157
|
+
* replacement.
|
|
149
158
|
*/
|
|
150
159
|
MARIONETTE: 'marionette',
|
|
151
160
|
|
|
@@ -174,9 +183,6 @@ class Options {
|
|
|
174
183
|
|
|
175
184
|
/** @private {?capabilities.ProxyConfig} */
|
|
176
185
|
this.proxy_ = null;
|
|
177
|
-
|
|
178
|
-
/** @private {boolean} */
|
|
179
|
-
this.marionette_ = true;
|
|
180
186
|
}
|
|
181
187
|
|
|
182
188
|
/**
|
|
@@ -196,16 +202,24 @@ class Options {
|
|
|
196
202
|
}
|
|
197
203
|
|
|
198
204
|
/**
|
|
199
|
-
* Sets the binary to use. The binary may be specified as the path to a
|
|
200
|
-
* executable, or as a {@link Binary}
|
|
205
|
+
* Sets the binary to use. The binary may be specified as the path to a
|
|
206
|
+
* Firefox executable, a specific {@link Channel}, or as a {@link Binary}
|
|
207
|
+
* object.
|
|
201
208
|
*
|
|
202
|
-
* @param {(string|!Binary)} binary The binary to use.
|
|
209
|
+
* @param {(string|!Binary|!Channel)} binary The binary to use.
|
|
203
210
|
* @return {!Options} A self reference.
|
|
211
|
+
* @throws {TypeError} If `binary` is an invalid type.
|
|
204
212
|
*/
|
|
205
213
|
setBinary(binary) {
|
|
206
|
-
if (typeof binary === 'string') {
|
|
214
|
+
if (typeof binary === 'string' || binary instanceof Channel) {
|
|
207
215
|
binary = new Binary(binary);
|
|
208
216
|
}
|
|
217
|
+
|
|
218
|
+
if (!(binary instanceof Binary)) {
|
|
219
|
+
throw TypeError(
|
|
220
|
+
'binary must be a string path, Channel, or Binary object');
|
|
221
|
+
}
|
|
222
|
+
|
|
209
223
|
this.binary_ = binary;
|
|
210
224
|
return this;
|
|
211
225
|
}
|
|
@@ -232,14 +246,10 @@ class Options {
|
|
|
232
246
|
}
|
|
233
247
|
|
|
234
248
|
/**
|
|
235
|
-
*
|
|
236
|
-
* is
|
|
237
|
-
*
|
|
238
|
-
* @param {boolean} enable Whether to enable the geckodriver.
|
|
239
|
-
* @see https://github.com/mozilla/geckodriver
|
|
249
|
+
* @deprecated This method has been deprecated and will be removed in the next
|
|
250
|
+
* release. It is a no-op.
|
|
240
251
|
*/
|
|
241
252
|
useGeckoDriver(enable) {
|
|
242
|
-
this.marionette_ = enable;
|
|
243
253
|
return this;
|
|
244
254
|
}
|
|
245
255
|
|
|
@@ -262,7 +272,6 @@ class Options {
|
|
|
262
272
|
if (this.profile_) {
|
|
263
273
|
caps.set(Capability.PROFILE, this.profile_);
|
|
264
274
|
}
|
|
265
|
-
caps.set(Capability.MARIONETTE, this.marionette_);
|
|
266
275
|
return caps;
|
|
267
276
|
}
|
|
268
277
|
}
|
|
@@ -298,33 +307,13 @@ function findGeckoDriver() {
|
|
|
298
307
|
throw Error(
|
|
299
308
|
'The ' + GECKO_DRIVER_EXE + ' executable could not be found on the current ' +
|
|
300
309
|
'PATH. Please download the latest version from ' +
|
|
301
|
-
'https://github.com/mozilla/geckodriver/releases/' +
|
|
302
|
-
'
|
|
310
|
+
'https://github.com/mozilla/geckodriver/releases/ ' +
|
|
311
|
+
'and ensure it can be found on your PATH.');
|
|
303
312
|
}
|
|
304
313
|
return exe;
|
|
305
314
|
}
|
|
306
315
|
|
|
307
316
|
|
|
308
|
-
/**
|
|
309
|
-
* @param {(Profile|string)} profile The profile to prepare.
|
|
310
|
-
* @param {number} port The port the FirefoxDriver should listen on.
|
|
311
|
-
* @return {!Promise<string>} a promise for the path to the profile directory.
|
|
312
|
-
*/
|
|
313
|
-
function prepareProfile(profile, port) {
|
|
314
|
-
if (typeof profile === 'string') {
|
|
315
|
-
return decodeProfile(/** @type {string} */(profile)).then(dir => {
|
|
316
|
-
profile = new Profile(dir);
|
|
317
|
-
profile.setPreference('webdriver_firefox_port', port);
|
|
318
|
-
return profile.writeToDisk();
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
profile = profile || new Profile;
|
|
323
|
-
profile.setPreference('webdriver_firefox_port', port);
|
|
324
|
-
return profile.writeToDisk();
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
317
|
function normalizeProxyConfiguration(config) {
|
|
329
318
|
if ('manual' === config.proxyType) {
|
|
330
319
|
if (config.ftpProxy && !config.ftpProxyPort) {
|
|
@@ -457,7 +446,7 @@ var DriverSpec;
|
|
|
457
446
|
* @return {DriverSpec}
|
|
458
447
|
*/
|
|
459
448
|
function createGeckoDriver(executor, caps, profile, binary) {
|
|
460
|
-
let firefoxOptions = {};
|
|
449
|
+
let firefoxOptions = caps.get('moz:firefoxOptions') || {};
|
|
461
450
|
caps.set('moz:firefoxOptions', firefoxOptions);
|
|
462
451
|
|
|
463
452
|
if (binary) {
|
|
@@ -529,47 +518,6 @@ function createGeckoDriver(executor, caps, profile, binary) {
|
|
|
529
518
|
}
|
|
530
519
|
|
|
531
520
|
|
|
532
|
-
/**
|
|
533
|
-
* @param {!capabilities.Capabilities} caps
|
|
534
|
-
* @param {Profile} profile
|
|
535
|
-
* @param {!Binary} binary
|
|
536
|
-
* @return {DriverSpec}
|
|
537
|
-
*/
|
|
538
|
-
function createLegacyDriver(caps, profile, binary, flow) {
|
|
539
|
-
profile = profile || new Profile;
|
|
540
|
-
|
|
541
|
-
let freePort = portprober.findFreePort();
|
|
542
|
-
let preparedProfile =
|
|
543
|
-
freePort.then(port => prepareProfile(profile, port));
|
|
544
|
-
let command = preparedProfile.then(dir => binary.launch(dir));
|
|
545
|
-
|
|
546
|
-
let serverUrl = command.then(() => freePort)
|
|
547
|
-
.then(function(/** number */port) {
|
|
548
|
-
let serverUrl = url.format({
|
|
549
|
-
protocol: 'http',
|
|
550
|
-
hostname: net.getLoopbackAddress(),
|
|
551
|
-
port: port + '',
|
|
552
|
-
pathname: '/hub'
|
|
553
|
-
});
|
|
554
|
-
let ready = httpUtil.waitForServer(serverUrl, 45 * 1000);
|
|
555
|
-
return ready.then(() => serverUrl);
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
return {
|
|
559
|
-
executor: createExecutor(serverUrl),
|
|
560
|
-
capabilities: caps,
|
|
561
|
-
onQuit: function() {
|
|
562
|
-
return command.then(command => {
|
|
563
|
-
command.kill();
|
|
564
|
-
return preparedProfile.then(io.rmDir)
|
|
565
|
-
.then(() => command.result(),
|
|
566
|
-
() => command.result());
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
|
|
573
521
|
/**
|
|
574
522
|
* A WebDriver client for Firefox.
|
|
575
523
|
*/
|
|
@@ -619,26 +567,9 @@ class Driver extends webdriver.WebDriver {
|
|
|
619
567
|
caps.delete(Capability.PROFILE);
|
|
620
568
|
}
|
|
621
569
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
caps.get(Capability.MARIONETTE) === false
|
|
626
|
-
|| /^0|false$/i.test(process.env['SELENIUM_MARIONETTE']);
|
|
627
|
-
let useMarionette = !noMarionette;
|
|
628
|
-
|
|
629
|
-
let spec;
|
|
630
|
-
if (useMarionette) {
|
|
631
|
-
spec = createGeckoDriver(opt_executor, caps, profile, binary);
|
|
632
|
-
} else {
|
|
633
|
-
if (opt_executor) {
|
|
634
|
-
throw Error('You may not use a custom command executor with the legacy'
|
|
635
|
-
+ ' FirefoxDriver');
|
|
636
|
-
}
|
|
637
|
-
spec = createLegacyDriver(caps, profile, binary, opt_flow);
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
return /** @type {!Driver} */(webdriver.WebDriver.createSession(
|
|
641
|
-
spec.executor, spec.capabilities, opt_flow, this, spec.onQuit));
|
|
570
|
+
let spec = createGeckoDriver(opt_executor, caps, profile, binary);
|
|
571
|
+
return /** @type {!Driver} */(super.createSession(
|
|
572
|
+
spec.executor, spec.capabilities, opt_flow, spec.onQuit));
|
|
642
573
|
}
|
|
643
574
|
|
|
644
575
|
/**
|
|
@@ -687,6 +618,7 @@ class Driver extends webdriver.WebDriver {
|
|
|
687
618
|
|
|
688
619
|
|
|
689
620
|
exports.Binary = Binary;
|
|
621
|
+
exports.Channel = Channel;
|
|
690
622
|
exports.Context = Context;
|
|
691
623
|
exports.Driver = Driver;
|
|
692
624
|
exports.Options = Options;
|
package/firefox/profile.js
CHANGED
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
|
|
23
23
|
'use strict';
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
fs = require('fs'),
|
|
25
|
+
const fs = require('fs'),
|
|
27
26
|
path = require('path'),
|
|
28
27
|
vm = require('vm');
|
|
29
28
|
|
|
30
29
|
const isDevMode = require('../lib/devmode'),
|
|
31
30
|
Symbols = require('../lib/symbols'),
|
|
32
31
|
io = require('../io'),
|
|
32
|
+
{Zip, unzip} = require('../io/zip'),
|
|
33
33
|
extension = require('./extension');
|
|
34
34
|
|
|
35
35
|
|
|
@@ -38,17 +38,6 @@ const WEBDRIVER_PREFERENCES_PATH = isDevMode
|
|
|
38
38
|
? path.join(__dirname, '../../../firefox-driver/webdriver.json')
|
|
39
39
|
: path.join(__dirname, '../lib/firefox/webdriver.json');
|
|
40
40
|
|
|
41
|
-
/** @const */
|
|
42
|
-
const WEBDRIVER_EXTENSION_PATH = isDevMode
|
|
43
|
-
? path.join(__dirname,
|
|
44
|
-
'../../../../build/javascript/firefox-driver/webdriver.xpi')
|
|
45
|
-
: path.join(__dirname, '../lib/firefox/webdriver.xpi');
|
|
46
|
-
|
|
47
|
-
/** @const */
|
|
48
|
-
const WEBDRIVER_EXTENSION_NAME = 'fxdriver@googlecode.com';
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
41
|
/** @type {Object} */
|
|
53
42
|
var defaultPreferences = null;
|
|
54
43
|
|
|
@@ -130,13 +119,10 @@ function writeUserPrefs(prefs, dir) {
|
|
|
130
119
|
* @param {!Array.<string>} extensions The extensions to install, as a
|
|
131
120
|
* path to an unpacked extension directory or a path to a xpi file.
|
|
132
121
|
* @param {string} dir The profile directory to install to.
|
|
133
|
-
* @param {boolean=} opt_excludeWebDriverExt Whether to skip installation of
|
|
134
|
-
* the default WebDriver extension.
|
|
135
122
|
* @return {!Promise<string>} A promise for the main profile directory
|
|
136
123
|
* once all extensions have been installed.
|
|
137
124
|
*/
|
|
138
|
-
function installExtensions(extensions, dir
|
|
139
|
-
var hasWebDriver = !!opt_excludeWebDriverExt;
|
|
125
|
+
function installExtensions(extensions, dir) {
|
|
140
126
|
var next = 0;
|
|
141
127
|
var extensionDir = path.join(dir, 'extensions');
|
|
142
128
|
|
|
@@ -145,11 +131,7 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
|
|
|
145
131
|
|
|
146
132
|
function installNext() {
|
|
147
133
|
if (next >= extensions.length) {
|
|
148
|
-
|
|
149
|
-
fulfill(dir);
|
|
150
|
-
} else {
|
|
151
|
-
install(WEBDRIVER_EXTENSION_PATH);
|
|
152
|
-
}
|
|
134
|
+
fulfill(dir);
|
|
153
135
|
} else {
|
|
154
136
|
install(extensions[next++]);
|
|
155
137
|
}
|
|
@@ -157,7 +139,6 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
|
|
|
157
139
|
|
|
158
140
|
function install(ext) {
|
|
159
141
|
extension.install(ext, extensionDir).then(function(id) {
|
|
160
|
-
hasWebDriver = hasWebDriver || (id === WEBDRIVER_EXTENSION_NAME);
|
|
161
142
|
installNext();
|
|
162
143
|
}, reject);
|
|
163
144
|
}
|
|
@@ -173,14 +154,10 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
|
|
|
173
154
|
*/
|
|
174
155
|
function decode(data) {
|
|
175
156
|
return io.tmpFile().then(function(file) {
|
|
176
|
-
|
|
157
|
+
let buf = new Buffer(data, 'base64');
|
|
177
158
|
return io.write(file, buf)
|
|
178
159
|
.then(io.tmpDir)
|
|
179
|
-
.then(
|
|
180
|
-
var zip = new AdmZip(file);
|
|
181
|
-
zip.extractAllTo(dir); // Sync only? Why?? :-(
|
|
182
|
-
return dir;
|
|
183
|
-
});
|
|
160
|
+
.then(dir => unzip(file, dir));
|
|
184
161
|
});
|
|
185
162
|
}
|
|
186
163
|
|
|
@@ -353,14 +330,10 @@ class Profile {
|
|
|
353
330
|
|
|
354
331
|
/**
|
|
355
332
|
* Writes this profile to disk.
|
|
356
|
-
* @param {boolean=} opt_excludeWebDriverExt Whether to exclude the WebDriver
|
|
357
|
-
* extension from the generated profile. Used to reduce the size of an
|
|
358
|
-
* {@link #encode() encoded profile} since the server will always install
|
|
359
|
-
* the extension itself.
|
|
360
333
|
* @return {!Promise<string>} A promise for the path to the new profile
|
|
361
334
|
* directory.
|
|
362
335
|
*/
|
|
363
|
-
writeToDisk(
|
|
336
|
+
writeToDisk() {
|
|
364
337
|
var profileDir = io.tmpDir();
|
|
365
338
|
if (this.template_) {
|
|
366
339
|
profileDir = profileDir.then(function(dir) {
|
|
@@ -382,7 +355,7 @@ class Profile {
|
|
|
382
355
|
return profileDir.then(function(dir) {
|
|
383
356
|
return writeUserPrefs(prefs, dir);
|
|
384
357
|
}).then(function(dir) {
|
|
385
|
-
return installExtensions(extensions, dir
|
|
358
|
+
return installExtensions(extensions, dir);
|
|
386
359
|
});
|
|
387
360
|
}
|
|
388
361
|
|
|
@@ -395,20 +368,11 @@ class Profile {
|
|
|
395
368
|
*
|
|
396
369
|
*/
|
|
397
370
|
encode() {
|
|
398
|
-
return this.writeToDisk(
|
|
399
|
-
|
|
400
|
-
zip.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
entry.header.method = 0;
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
return io.tmpFile().then(function(file) {
|
|
407
|
-
zip.writeZip(file); // Sync! Why oh why :-(
|
|
408
|
-
return io.read(file);
|
|
409
|
-
});
|
|
410
|
-
}).then(function(data) {
|
|
411
|
-
return data.toString('base64');
|
|
371
|
+
return this.writeToDisk().then(function(dir) {
|
|
372
|
+
let zip = new Zip;
|
|
373
|
+
return zip.addDir(dir)
|
|
374
|
+
.then(() => zip.toBuffer())
|
|
375
|
+
.then(buf => buf.toString('base64'));
|
|
412
376
|
});
|
|
413
377
|
}
|
|
414
378
|
|
package/ie.js
CHANGED
|
@@ -420,8 +420,8 @@ class Driver extends webdriver.WebDriver {
|
|
|
420
420
|
var client = service.start().then(url => new http.HttpClient(url));
|
|
421
421
|
var executor = new http.Executor(client);
|
|
422
422
|
|
|
423
|
-
return /** @type {!Driver} */(
|
|
424
|
-
executor, caps, opt_flow,
|
|
423
|
+
return /** @type {!Driver} */(super.createSession(
|
|
424
|
+
executor, caps, opt_flow, () => service.kill()));
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
/**
|
package/index.js
CHANGED
|
@@ -58,7 +58,7 @@ var seleniumServer;
|
|
|
58
58
|
* Starts an instance of the Selenium server if not yet running.
|
|
59
59
|
* @param {string} jar Path to the server jar to use.
|
|
60
60
|
* @return {!Promise<string>} A promise for the server's
|
|
61
|
-
*
|
|
61
|
+
* address once started.
|
|
62
62
|
*/
|
|
63
63
|
function startSeleniumServer(jar) {
|
|
64
64
|
if (!seleniumServer) {
|
|
@@ -131,7 +131,10 @@ const THENABLE_DRIVERS = new Map;
|
|
|
131
131
|
function createDriver(ctor, ...args) {
|
|
132
132
|
let thenableWebDriverProxy = THENABLE_DRIVERS.get(ctor);
|
|
133
133
|
if (!thenableWebDriverProxy) {
|
|
134
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* @extends {WebDriver} // Needed since `ctor` is dynamically typed.
|
|
136
|
+
* @implements {ThenableWebDriver}
|
|
137
|
+
*/
|
|
135
138
|
thenableWebDriverProxy = class extends ctor {
|
|
136
139
|
/**
|
|
137
140
|
* @param {!IThenable<!Session>} session
|
|
@@ -160,7 +163,7 @@ function createDriver(ctor, ...args) {
|
|
|
160
163
|
/** @override */
|
|
161
164
|
this.catch = pd.then.bind(pd);
|
|
162
165
|
}
|
|
163
|
-
}
|
|
166
|
+
};
|
|
164
167
|
promise.CancellableThenable.addImplementation(thenableWebDriverProxy);
|
|
165
168
|
THENABLE_DRIVERS.set(ctor, thenableWebDriverProxy);
|
|
166
169
|
}
|
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
|
+
};
|