Skip to content

Commit e7b6071

Browse files
committed
[js] Use moz:firefoxOptions for geckodriver-specific capabilities.
For mozilla/geckodriver#228
1 parent 7194756 commit e7b6071

6 files changed

Lines changed: 116 additions & 38 deletions

File tree

javascript/node/selenium-webdriver/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77

88
To use Safari 9 or older, users will have to use an older version of Selenium.
99

10+
* geckodriver v0.11.0 or newer is now required for Firefox.
1011
* Fixed potential reference errors in `selenium-webdriver/testing` when users
1112
create a cycle with mocha by running with mocha's `--hook` flag.
1213
* Fixed `WebDriver.switchTo().activeElement()` to use the correct HTTP method
1314
for compatibility with the W3C spec.
15+
* Update the `selenium-webdriver/firefox` module to use geckodriver's
16+
"moz:firefoxOptions" dictionary for Firefox-specific configuration values.
1417

1518

1619
### API Changes

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ class Binary {
181181
this.devEdition_ = false;
182182
}
183183

184+
/**
185+
* @return {(string|undefined)} The path to the Firefox executable to use, or
186+
* `undefined` if WebDriver should attempt to locate Firefox automatically
187+
* on the current system.
188+
*/
189+
getExe() {
190+
return this.exe_;
191+
}
192+
184193
/**
185194
* Add arguments to the command line used to start Firefox.
186195
* @param {...(string|!Array.<string>)} var_args Either the arguments to add
@@ -196,6 +205,14 @@ class Binary {
196205
}
197206
}
198207

208+
/**
209+
* @return {!Array<string>} The command line arguments to use when starting
210+
* the browser.
211+
*/
212+
getArguments() {
213+
return this.args_;
214+
}
215+
199216
/**
200217
* Specifies whether to use Firefox Developer Edition instead of the normal
201218
* stable channel. Setting this option has no effect if this instance was

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,34 @@ var DriverSpec;
455455
*/
456456
function createGeckoDriver(
457457
executor, caps, profile, binary, flow) {
458+
let firefoxOptions = {};
459+
caps.set('moz:firefoxOptions', firefoxOptions);
460+
461+
if (binary) {
462+
if (binary.getExe()) {
463+
firefoxOptions['binary'] = binary.getExe();
464+
}
465+
466+
let args = binary.getArguments();
467+
if (args.length) {
468+
firefoxOptions['args'] = args;
469+
}
470+
}
471+
458472
if (profile) {
459-
caps.set(Capability.PROFILE, profile.encode());
473+
// If the user specified a template directory or any extensions to install,
474+
// we need to encode the profile as a base64 string (which requires writing
475+
// it to disk first). Otherwise, if the user just specified some custom
476+
// preferences, we can send those directly.
477+
if (profile.getTemplateDir() || profile.getExtensions().length) {
478+
firefoxOptions['profile'] = profile.encode();
479+
480+
} else {
481+
let prefs = profile.getPreferences();
482+
if (Object.keys(prefs).length) {
483+
firefoxOptions['prefs'] = prefs;
484+
}
485+
}
460486
}
461487

462488
let sessionCaps = caps;
@@ -578,7 +604,6 @@ class Driver extends webdriver.WebDriver {
578604
caps = new capabilities.Capabilities(opt_config);
579605
}
580606

581-
let hasBinary = caps.has(Capability.BINARY);
582607
let binary = caps.get(Capability.BINARY) || new Binary();
583608
caps.delete(Capability.BINARY);
584609
if (typeof binary === 'string') {
@@ -606,7 +631,7 @@ class Driver extends webdriver.WebDriver {
606631
opt_executor,
607632
caps,
608633
profile,
609-
hasBinary ? binary : null,
634+
binary,
610635
opt_flow);
611636
} else {
612637
if (opt_executor) {

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,6 @@ class Profile {
201201
/** @private {!Object} */
202202
this.preferences_ = {};
203203

204-
Object.assign(this.preferences_, getDefaultPreferences()['mutable']);
205-
Object.assign(this.preferences_, getDefaultPreferences()['frozen']);
206-
207204
/** @private {boolean} */
208205
this.nativeEventsEnabled_ = true;
209206

@@ -217,6 +214,14 @@ class Profile {
217214
this.extensions_ = [];
218215
}
219216

217+
/**
218+
* @return {(string|undefined)} Path to an existing Firefox profile directory
219+
* to use as a template when writing this Profile to disk.
220+
*/
221+
getTemplateDir() {
222+
return this.template_;
223+
}
224+
220225
/**
221226
* Registers an extension to be included with this profile.
222227
* @param {string} extension Path to the extension to include, as either an
@@ -226,6 +231,13 @@ class Profile {
226231
this.extensions_.push(extension);
227232
}
228233

234+
/**
235+
* @return {!Array<string>} A list of extensions to install in this profile.
236+
*/
237+
getExtensions() {
238+
return this.extensions_;
239+
}
240+
229241
/**
230242
* Sets a desired preference for this profile.
231243
* @param {string} key The preference key.
@@ -254,6 +266,13 @@ class Profile {
254266
return this.preferences_[key];
255267
}
256268

269+
/**
270+
* @return {!Object} A copy of all currently configured preferences.
271+
*/
272+
getPreferences() {
273+
return Object.assign({}, this.preferences_);
274+
}
275+
257276
/**
258277
* Specifies which host the driver should listen for commands on. If not
259278
* specified, the driver will default to "localhost". This option should be
@@ -353,6 +372,8 @@ class Profile {
353372

354373
// Freeze preferences for async operations.
355374
var prefs = {};
375+
Object.assign(prefs, getDefaultPreferences()['mutable']);
376+
Object.assign(prefs, getDefaultPreferences()['frozen']);
356377
Object.assign(prefs, this.preferences_);
357378

358379
// Freeze extensions for async operations.

javascript/node/selenium-webdriver/test/firefox/firefox_test.js

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ test.suite(function(env) {
4848
}
4949
});
5050

51+
/**
52+
* Runs a test that requires Firefox Developer Edition. The test will be
53+
* skipped if dev cannot be found on the current system.
54+
*/
55+
function runWithFirefoxDev(options, testFn) {
56+
let binary = new firefox.Binary();
57+
binary.useDevEdition();
58+
return binary.locate().then(exe => {
59+
options.setBinary(exe);
60+
driver = env.builder()
61+
.setFirefoxOptions(options)
62+
.build();
63+
return driver.call(testFn);
64+
}, err => {
65+
console.warn(
66+
'Skipping test: could not find Firefox Dev Edition: ' + err);
67+
});
68+
}
69+
5170
test.it('can start Firefox with custom preferences', function() {
5271
var profile = new firefox.Profile();
5372
profile.setPreference('general.useragent.override', 'foo;bar');
@@ -66,53 +85,47 @@ test.suite(function(env) {
6685
});
6786

6887
test.it('can start Firefox with a jetpack extension', function() {
69-
var profile = new firefox.Profile();
88+
let profile = new firefox.Profile();
7089
profile.addExtension(JETPACK_EXTENSION);
7190

72-
var options = new firefox.Options().setProfile(profile);
91+
let options = new firefox.Options().setProfile(profile);
7392

74-
driver = env.builder().
75-
setFirefoxOptions(options).
76-
build();
77-
78-
loadJetpackPage(driver,
79-
'data:text/html;charset=UTF-8,<html><div>content</div></html>');
80-
assert(driver.findElement({id: 'jetpack-sample-banner'}).getText())
81-
.equalTo('Hello, world!');
93+
return runWithFirefoxDev(options, function() {
94+
loadJetpackPage(driver,
95+
'data:text/html;charset=UTF-8,<html><div>content</div></html>');
96+
assert(driver.findElement({id: 'jetpack-sample-banner'}).getText())
97+
.equalTo('Hello, world!');
98+
});
8299
});
83100

84101
test.it('can start Firefox with a normal extension', function() {
85-
var profile = new firefox.Profile();
102+
let profile = new firefox.Profile();
86103
profile.addExtension(NORMAL_EXTENSION);
87104

88-
var options = new firefox.Options().setProfile(profile);
105+
let options = new firefox.Options().setProfile(profile);
89106

90-
driver = env.builder().
91-
setFirefoxOptions(options).
92-
build();
93-
94-
driver.get('data:text/html,<html><div>content</div></html>');
95-
assert(driver.findElement({id: 'sample-extension-footer'}).getText())
96-
.equalTo('Goodbye');
107+
return runWithFirefoxDev(options, function() {
108+
driver.get('data:text/html,<html><div>content</div></html>');
109+
assert(driver.findElement({id: 'sample-extension-footer'}).getText())
110+
.equalTo('Goodbye');
111+
});
97112
});
98113

99114
test.it('can start Firefox with multiple extensions', function() {
100-
var profile = new firefox.Profile();
115+
let profile = new firefox.Profile();
101116
profile.addExtension(JETPACK_EXTENSION);
102117
profile.addExtension(NORMAL_EXTENSION);
103118

104-
var options = new firefox.Options().setProfile(profile);
105-
106-
driver = env.builder().
107-
setFirefoxOptions(options).
108-
build();
119+
let options = new firefox.Options().setProfile(profile);
109120

110-
loadJetpackPage(driver,
111-
'data:text/html;charset=UTF-8,<html><div>content</div></html>');
112-
assert(driver.findElement({id: 'jetpack-sample-banner'}).getText())
113-
.equalTo('Hello, world!');
114-
assert(driver.findElement({id: 'sample-extension-footer'}).getText())
115-
.equalTo('Goodbye');
121+
return runWithFirefoxDev(options, function() {
122+
loadJetpackPage(driver,
123+
'data:text/html;charset=UTF-8,<html><div>content</div></html>');
124+
assert(driver.findElement({id: 'jetpack-sample-banner'}).getText())
125+
.equalTo('Hello, world!');
126+
assert(driver.findElement({id: 'sample-extension-footer'}).getText())
127+
.equalTo('Goodbye');
128+
});
116129
});
117130

118131
function loadJetpackPage(driver, url) {

javascript/node/selenium-webdriver/test/firefox/profile_test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ describe('Profile', function() {
5252

5353
it('allows overriding mutable properties', function() {
5454
var profile = new Profile();
55-
assert.equal('about:blank', profile.getPreference('browser.newtab.url'));
5655

5756
profile.setPreference('browser.newtab.url', 'http://www.example.com');
5857
assert.equal('http://www.example.com',

0 commit comments

Comments
 (0)