Skip to content

Commit 6ad4b48

Browse files
andreasttjleyba
authored andcommitted
nodejs: add switch context extension command to marionette (#2407)
The Switch Context command allows running WebDriver commands against the chrome/XUL context in Firefox.
1 parent a9b485f commit 6ad4b48

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,11 @@ const Binary = require('./binary').Binary,
117117
Profile = require('./profile').Profile,
118118
decodeProfile = require('./profile').decode,
119119
executors = require('../executors'),
120+
http = require('../http'),
120121
httpUtil = require('../http/util'),
121122
io = require('../io'),
122123
capabilities = require('../lib/capabilities'),
124+
command = require('../lib/command'),
123125
logging = require('../lib/logging'),
124126
promise = require('../lib/promise'),
125127
webdriver = require('../lib/webdriver'),
@@ -266,6 +268,23 @@ class Options {
266268
}
267269
}
268270

271+
272+
/**
273+
* Enum of available command contexts.
274+
*
275+
* Command contexts are specific to Marionette, and may be used with the
276+
* {@link #context=} method. Contexts allow you to direct all subsequent
277+
* commands to either "content" (default) or "chrome". The latter gives
278+
* you elevated security permissions.
279+
*
280+
* @enum {string}
281+
*/
282+
const Context = {
283+
CONTENT: "content",
284+
CHROME: "chrome",
285+
};
286+
287+
269288
const GECKO_DRIVER_EXE =
270289
process.platform === 'win32' ? 'geckodriver.exe' : 'geckodriver';
271290

@@ -365,6 +384,36 @@ function normalizeProxyConfiguration(config) {
365384
}
366385

367386

387+
/** @enum {string} */
388+
const ExtensionCommand = {
389+
GET_CONTEXT: 'getContext',
390+
SET_CONTEXT: 'setContext',
391+
};
392+
393+
394+
/**
395+
* Creates a command executor with support for Marionette's custom commands.
396+
* @param {!Promise<string>} url The server's URL.
397+
* @param {!command.Executor} The new command executor.
398+
*/
399+
function createExecutor(url) {
400+
return new command.DeferredExecutor(url.then(url => {
401+
let client = new http.HttpClient(url);
402+
let executor = new http.Executor(client);
403+
404+
executor.defineCommand(
405+
ExtensionCommand.GET_CONTEXT,
406+
'GET',
407+
'/session/:sessionId/moz/context');
408+
executor.defineCommand(
409+
ExtensionCommand.SET_CONTEXT,
410+
'POST',
411+
'/session/:sessionId/moz/context');
412+
413+
return executor;
414+
}));
415+
}
416+
368417
/**
369418
* A WebDriver client for Firefox.
370419
*/
@@ -457,7 +506,7 @@ class Driver extends webdriver.WebDriver {
457506
};
458507
}
459508

460-
let executor = executors.createExecutor(serverUrl);
509+
let executor = createExecutor(serverUrl);
461510
let driver = webdriver.WebDriver.createSession(executor, caps, opt_flow);
462511
super(driver.getSession(), executor, driver.controlFlow());
463512

@@ -476,13 +525,46 @@ class Driver extends webdriver.WebDriver {
476525
*/
477526
setFileDetector() {
478527
}
528+
529+
/**
530+
* Get the context that is currently in effect.
531+
*
532+
* @return {!promise.Promise<Context>} Current context.
533+
*/
534+
getContext() {
535+
return this.schedule(
536+
new command.Command(ExtensionCommand.GET_CONTEXT),
537+
'get WebDriver.context');
538+
}
539+
540+
/**
541+
* Changes target context for commands between chrome- and content.
542+
*
543+
* Changing the current context has a stateful impact on all subsequent
544+
* commands. The {@link Context.CONTENT} context has normal web
545+
* platform document permissions, as if you would evaluate arbitrary
546+
* JavaScript. The {@link Context.CHROME} context gets elevated
547+
* permissions that lets you manipulate the browser chrome itself,
548+
* with full access to the XUL toolkit.
549+
*
550+
* Use your powers wisely.
551+
*
552+
* @param {!promise.Promise<void>} ctx The context to switch to.
553+
*/
554+
setContext(ctx) {
555+
return this.schedule(
556+
new command.Command(ExtensionCommand.SET_CONTEXT)
557+
.setParameter("context", ctx),
558+
'set WebDriver.context');
559+
}
479560
}
480561

481562

482563
// PUBLIC API
483564

484565

485566
exports.Binary = Binary;
567+
exports.Context = Context;
486568
exports.Driver = Driver;
487569
exports.Options = Options;
488570
exports.Profile = Profile;

javascript/node/selenium-webdriver/lib/test/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ function TestEnvironment(browserName, server) {
147147
return server || remoteUrl;
148148
};
149149

150+
this.isMarionette = function() {
151+
return !noMarionette;
152+
};
153+
150154
this.browsers = function(var_args) {
151155
var browsersToIgnore = Array.prototype.slice.apply(arguments, [0]);
152156
return browsers(browserName, browsersToIgnore);

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

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ var path = require('path');
2222
var firefox = require('../../firefox'),
2323
io = require('../../io'),
2424
test = require('../../lib/test'),
25-
assert = require('../../testing/assert');
25+
assert = require('../../testing/assert'),
26+
Context = require('../../firefox').Context,
27+
error = require('../..').error;
2628

2729

2830
var JETPACK_EXTENSION = path.join(__dirname,
@@ -148,5 +150,39 @@ test.suite(function(env) {
148150
});
149151
});
150152

153+
describe('context switching', function() {
154+
var driver;
155+
156+
test.beforeEach(function() {
157+
driver = env.builder().build();
158+
});
159+
160+
test.afterEach(function() {
161+
if (driver) {
162+
driver.quit();
163+
}
164+
});
165+
166+
test.ignore(() => !env.isMarionette).
167+
it('can get context', function() {
168+
assert(driver.getContext()).equalTo(Context.CONTENT);
169+
});
170+
171+
test.ignore(() => !env.isMarionette).
172+
it('can set context', function() {
173+
driver.setContext(Context.CHROME);
174+
assert(driver.getContext()).equalTo(Context.CHROME);
175+
driver.setContext(Context.CONTENT);
176+
assert(driver.getContext()).equalTo(Context.CONTENT);
177+
});
178+
179+
test.ignore(() => !env.isMarionette).
180+
it('throws on unknown context', function() {
181+
driver.setContext("foo").then(assert.fail, function(e) {
182+
assert(e).instanceOf(error.InvalidArgumentError);
183+
});
184+
});
185+
});
186+
151187
});
152188
}, {browsers: ['firefox']});

0 commit comments

Comments
 (0)