Skip to content

Commit 185755a

Browse files
committed
[js] Preliminary support for marionette.
Marionette may be enabled through the API, or by setting the SELENIUM_MARIONETTE environment variable. When enabled, seleniuv-webdriver will default to looking for Firefox's Developer Edition instead of the stable channel (since marionette doesn't support stable channel yet). Users can still manually configure the path to Firefox through the API. I still need to work through the test suite to identify features that don't work in marionette (lack of profile support is one known issue)
1 parent a300b45 commit 185755a

File tree

6 files changed

+277
-87
lines changed

6 files changed

+277
-87
lines changed

javascript/node/selenium-webdriver/CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
### Change Summary
44

5+
* Added preliminary support for Marionette, Mozilla's WebDriver implementation
6+
for Firefox. Marionette may be enabled via the API,
7+
`firefox.Options#useMarionette`, or by setting the `SELENIUM_MARIONETTE`
8+
environment variable.
59
* Moved all logic for parsing and interpreting responses from the remote end
610
into the individual `command.Executor` implementations.
711
* For consistency with the other Selenium language bindings,

javascript/node/selenium-webdriver/firefox/binary.js

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,26 @@ const NO_FOCUS_LIB_AMD64 = isDevMode ?
4747

4848
const X_IGNORE_NO_FOCUS_LIB = 'x_ignore_nofocus.so';
4949

50-
var foundBinary = null;
50+
51+
let foundBinary = null;
52+
let foundDevBinary = null;
5153

5254

5355
/**
5456
* Checks the default Windows Firefox locations in Program Files.
57+
*
58+
* @param {boolean=} opt_dev Whether to find the Developer Edition.
5559
* @return {!Promise<?string>} A promise for the located executable.
5660
* The promise will resolve to {@code null} if Firefox was not found.
5761
*/
58-
function defaultWindowsLocation() {
62+
function defaultWindowsLocation(opt_dev) {
5963
var files = [
6064
process.env['PROGRAMFILES'] || 'C:\\Program Files',
6165
process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)'
6266
].map(function(prefix) {
67+
if (opt_dev) {
68+
return path.join(prefix, 'Firefox Developer Edition\\firefox.exe');
69+
}
6370
return path.join(prefix, 'Mozilla Firefox\\firefox.exe');
6471
});
6572
return io.exists(files[0]).then(function(exists) {
@@ -72,31 +79,47 @@ function defaultWindowsLocation() {
7279

7380
/**
7481
* Locates the Firefox binary for the current system.
75-
* @return {!promise.Promise.<string>} A promise for the located binary. The
76-
* promise will be rejected if Firefox cannot be located.
82+
*
83+
* @param {boolean=} opt_dev Whether to find the Developer Edition. This only
84+
* used on Windows and OSX.
85+
* @return {!Promise<string>} A promise for the located binary. The promise will
86+
* be rejected if Firefox cannot be located.
7787
*/
78-
function findFirefox() {
79-
if (foundBinary) {
88+
function findFirefox(opt_dev) {
89+
if (opt_dev && foundDevBinary) {
90+
return foundDevBinary;
91+
}
92+
93+
if (!opt_dev && foundBinary) {
8094
return foundBinary;
8195
}
8296

97+
let found;
8398
if (process.platform === 'darwin') {
84-
var osxExe = '/Applications/Firefox.app/Contents/MacOS/firefox-bin';
85-
foundBinary = io.exists(osxExe).then(function(exists) {
86-
return exists ? osxExe : null;
87-
});
99+
let exe = opt_dev
100+
? '/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox-bin'
101+
: '/Applications/Firefox.app/Contents/MacOS/firefox-bin';
102+
found = io.exists(exe).then(exists => exists ? exe : null);
103+
88104
} else if (process.platform === 'win32') {
89-
foundBinary = defaultWindowsLocation();
105+
found = defaultWindowsLocation(opt_dev);
106+
90107
} else {
91-
foundBinary = promise.fulfilled(io.findInPath('firefox'));
108+
found = Promise.resolve(io.findInPath('firefox'));
92109
}
93110

94-
return foundBinary = foundBinary.then(function(found) {
111+
found = found.then(found => {
95112
if (found) {
96113
return found;
97114
}
98115
throw Error('Could not locate Firefox on the current system');
99116
});
117+
118+
if (opt_dev) {
119+
return foundDevBinary = found;
120+
} else {
121+
return foundBinary = found;
122+
}
100123
}
101124

102125

@@ -136,12 +159,17 @@ function installNoFocusLibs(profileDir) {
136159
* Provides a mechanism to configure and launch Firefox in a subprocess for
137160
* use with WebDriver.
138161
*
162+
* If created _without_ a path for the Firefox binary to use, this class will
163+
* attempt to find Firefox when {@link #launch()} is called. For OSX and
164+
* Windows, this class will look for Firefox in the current platform's default
165+
* installation location (e.g. /Applications/Firefox.app on OSX). For all other
166+
* platforms, the Firefox executable must be available on your system `PATH`.
167+
*
139168
* @final
140169
*/
141170
class Binary {
142171
/**
143-
* @param {string=} opt_exe Path to the Firefox binary to use. If not
144-
* specified, will attempt to locate Firefox on the current system.
172+
* @param {string=} opt_exe Path to the Firefox binary to use.
145173
*/
146174
constructor(opt_exe) {
147175
/** @private {(string|undefined)} */
@@ -157,6 +185,9 @@ class Binary {
157185
MOZ_NO_REMOTE: '1',
158186
NO_EM_RESTART: '1'
159187
});
188+
189+
/** @private {boolean} */
190+
this.devEdition_ = false;
160191
}
161192

162193
/**
@@ -174,6 +205,34 @@ class Binary {
174205
}
175206
}
176207

208+
/**
209+
* Specifies whether to use Firefox Developer Edition instead of the normal
210+
* stable channel. Setting this option has no effect if this instance was
211+
* created with a path to a specific Firefox binary.
212+
*
213+
* This method has no effect on Unix systems where the Firefox application
214+
* has the same (default) name regardless of version.
215+
*
216+
* @param {boolean=} opt_use Whether to use the developer edition. Defaults to
217+
* true.
218+
*/
219+
useDevEdition(opt_use) {
220+
this.devEdition_ = opt_use === undefined || !!opt_use;
221+
}
222+
223+
/**
224+
* Returns a promise for the Firefox executable used by this instance. The
225+
* returned promise will be immediately resolved if the user supplied an
226+
* executable path when this instance was created. Otherwise, an attempt will
227+
* be made to find Firefox on the current system.
228+
*
229+
* @return {!promise.Promise<string>} a promise for the path to the Firefox
230+
* executable used by this instance.
231+
*/
232+
locate() {
233+
return promise.fulfilled(this.exe_ || findFirefox(this.devEdition_));
234+
}
235+
177236
/**
178237
* Launches Firefox and returns a promise that will be fulfilled when the
179238
* process terminates.
@@ -187,7 +246,7 @@ class Binary {
187246

188247
let args = ['-foreground'].concat(this.args_);
189248

190-
return promise.when(this.exe_ || findFirefox(), function(firefox) {
249+
return this.locate().then(function(firefox) {
191250
if (process.platform === 'win32' || process.platform === 'darwin') {
192251
return exec(firefox, {args: args, env: env});
193252
}
@@ -209,7 +268,7 @@ class Binary {
209268
* representation.
210269
*/
211270
[Symbols.serialize]() {
212-
return promise.fulfilled(this.exe_ || findFirefox());
271+
return this.locate();
213272
}
214273
}
215274

0 commit comments

Comments
 (0)