2015-03-20 00:12:58 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2015-10-07 15:03:21 +03:00
|
|
|
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-10-07 15:03:21 +03:00
|
|
|
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
2015-03-20 00:12:58 +03:00
|
|
|
.getService(Ci.mozIJSSubScriptLoader);
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/Log.jsm");
|
2016-01-19 01:05:30 +03:00
|
|
|
Cu.import("resource://gre/modules/Preferences.jsm");
|
2015-03-20 00:12:58 +03:00
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
2015-07-16 01:51:51 +03:00
|
|
|
this, "cookieManager", "@mozilla.org/cookiemanager;1", "nsICookieManager2");
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2016-02-03 22:25:28 +03:00
|
|
|
Cu.import("chrome://marionette/content/action.js");
|
2016-02-03 22:00:46 +03:00
|
|
|
Cu.import("chrome://marionette/content/atom.js");
|
2016-05-10 15:29:21 +03:00
|
|
|
Cu.import("chrome://marionette/content/browser.js");
|
2016-02-03 22:14:10 +03:00
|
|
|
Cu.import("chrome://marionette/content/element.js");
|
2016-02-29 21:52:30 +03:00
|
|
|
Cu.import("chrome://marionette/content/error.js");
|
|
|
|
Cu.import("chrome://marionette/content/evaluate.js");
|
2016-02-03 21:56:02 +03:00
|
|
|
Cu.import("chrome://marionette/content/event.js");
|
2016-02-29 21:52:30 +03:00
|
|
|
Cu.import("chrome://marionette/content/interaction.js");
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
Cu.import("chrome://marionette/content/logging.js");
|
2015-03-20 18:46:46 +03:00
|
|
|
Cu.import("chrome://marionette/content/modal.js");
|
2015-04-28 16:25:37 +03:00
|
|
|
Cu.import("chrome://marionette/content/proxy.js");
|
2015-03-24 00:32:03 +03:00
|
|
|
Cu.import("chrome://marionette/content/simpletest.js");
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.EXPORTED_SYMBOLS = ["GeckoDriver", "Context"];
|
|
|
|
|
2015-10-07 15:03:21 +03:00
|
|
|
var FRAME_SCRIPT = "chrome://marionette/content/listener.js";
|
2015-03-20 00:12:58 +03:00
|
|
|
const BROWSER_STARTUP_FINISHED = "browser-delayed-startup-finished";
|
|
|
|
const CLICK_TO_START_PREF = "marionette.debugging.clicktostart";
|
|
|
|
const CONTENT_LISTENER_PREF = "marionette.contentListener";
|
|
|
|
|
2016-05-20 15:28:27 +03:00
|
|
|
const SUPPORTED_STRATEGIES = new Set([
|
|
|
|
element.Strategy.ClassName,
|
|
|
|
element.Strategy.Selector,
|
|
|
|
element.Strategy.ID,
|
|
|
|
element.Strategy.TagName,
|
|
|
|
element.Strategy.XPath,
|
|
|
|
element.Strategy.Anon,
|
|
|
|
element.Strategy.AnonAttribute,
|
|
|
|
]);
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
const logger = Log.repository.getLogger("Marionette");
|
|
|
|
const globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"]
|
|
|
|
.getService(Ci.nsIMessageBroadcaster);
|
|
|
|
|
|
|
|
// This is used to prevent newSession from returning before the telephony
|
|
|
|
// API's are ready; see bug 792647. This assumes that marionette-server.js
|
|
|
|
// will be loaded before the 'system-message-listener-ready' message
|
|
|
|
// is fired. If this stops being true, this approach will have to change.
|
2015-09-15 21:19:45 +03:00
|
|
|
var systemMessageListenerReady = false;
|
2015-03-20 00:12:58 +03:00
|
|
|
Services.obs.addObserver(function() {
|
|
|
|
systemMessageListenerReady = true;
|
|
|
|
}, "system-message-listener-ready", false);
|
|
|
|
|
|
|
|
// This is used on desktop to prevent newSession from returning before a page
|
|
|
|
// load initiated by the Firefox command line has completed.
|
2015-09-15 21:19:45 +03:00
|
|
|
var delayedBrowserStarted = false;
|
2015-03-20 00:12:58 +03:00
|
|
|
Services.obs.addObserver(function () {
|
|
|
|
delayedBrowserStarted = true;
|
|
|
|
}, BROWSER_STARTUP_FINISHED, false);
|
|
|
|
|
|
|
|
this.Context = {
|
|
|
|
CHROME: "chrome",
|
|
|
|
CONTENT: "content",
|
|
|
|
};
|
|
|
|
|
|
|
|
this.Context.fromString = function(s) {
|
|
|
|
s = s.toUpperCase();
|
2015-03-23 23:43:18 +03:00
|
|
|
if (s in this) {
|
2015-03-20 00:12:58 +03:00
|
|
|
return this[s];
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements (parts of) the W3C WebDriver protocol. GeckoDriver lives
|
2015-04-28 16:25:37 +03:00
|
|
|
* in chrome space and mediates calls to the message listener of the current
|
|
|
|
* browsing context's content frame message listener via ListenerProxy.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
|
|
|
* Throughout this prototype, functions with the argument {@code cmd}'s
|
|
|
|
* documentation refers to the contents of the {@code cmd.parameters}
|
|
|
|
* object.
|
|
|
|
*
|
|
|
|
* @param {string} appName
|
|
|
|
* Description of the product, for example "B2G" or "Firefox".
|
|
|
|
* @param {string} device
|
|
|
|
* Device this driver should assume.
|
2015-09-26 19:12:01 +03:00
|
|
|
* @param {function()} stopSignal
|
|
|
|
* Signal to stop the Marionette server.
|
2015-03-20 00:12:58 +03:00
|
|
|
*/
|
2016-05-24 12:22:54 +03:00
|
|
|
this.GeckoDriver = function(appName, device, stopSignal) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.appName = appName;
|
2015-09-26 19:12:01 +03:00
|
|
|
this.stopSignal_ = stopSignal;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.sessionId = null;
|
2016-05-23 12:21:15 +03:00
|
|
|
this.wins = new browser.Windows();
|
2015-03-20 00:12:58 +03:00
|
|
|
this.browsers = {};
|
|
|
|
// points to current browser
|
|
|
|
this.curBrowser = null;
|
|
|
|
this.context = Context.CONTENT;
|
|
|
|
this.scriptTimeout = null;
|
|
|
|
this.searchTimeout = null;
|
|
|
|
this.pageTimeout = null;
|
|
|
|
this.timer = null;
|
|
|
|
this.inactivityTimer = null;
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.marionetteLog = new logging.ContentLogger();
|
2015-03-20 00:12:58 +03:00
|
|
|
// topmost chrome frame
|
|
|
|
this.mainFrame = null;
|
|
|
|
// chrome iframe that currently has focus
|
|
|
|
this.curFrame = null;
|
|
|
|
this.mainContentFrameId = null;
|
2016-02-29 21:52:30 +03:00
|
|
|
this.importedScripts = new evaluate.ScriptStorageService([Context.CHROME, Context.CONTENT]);
|
2015-03-20 00:12:58 +03:00
|
|
|
this.currentFrameElement = null;
|
|
|
|
this.testName = null;
|
|
|
|
this.mozBrowserClose = null;
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.sandboxes = new Sandboxes(() => this.getCurrentWindow());
|
2015-03-20 00:12:58 +03:00
|
|
|
// frame ID of the current remote frame, used for mozbrowserclose events
|
|
|
|
this.oopFrameId = null;
|
|
|
|
this.observing = null;
|
|
|
|
this._browserIds = new WeakMap();
|
2016-02-03 22:25:28 +03:00
|
|
|
this.actions = new action.Chain();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.sessionCapabilities = {
|
2015-11-10 18:43:58 +03:00
|
|
|
// mandated capabilities
|
|
|
|
"browserName": Services.appinfo.name,
|
2015-03-20 00:12:58 +03:00
|
|
|
"browserVersion": Services.appinfo.version,
|
2015-11-10 18:43:58 +03:00
|
|
|
"platformName": Services.sysinfo.getProperty("name"),
|
|
|
|
"platformVersion": Services.sysinfo.getProperty("version"),
|
2016-03-04 21:00:17 +03:00
|
|
|
"specificationLevel": 0,
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-11-10 18:43:58 +03:00
|
|
|
// supported features
|
2015-03-20 00:12:58 +03:00
|
|
|
"raisesAccessibilityExceptions": false,
|
|
|
|
"rotatable": this.appName == "B2G",
|
2015-06-19 17:42:04 +03:00
|
|
|
"acceptSslCerts": false,
|
2015-03-20 00:12:58 +03:00
|
|
|
"takesElementScreenshot": true,
|
|
|
|
"takesScreenshot": true,
|
2015-07-14 02:51:58 +03:00
|
|
|
"proxy": {},
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
// Selenium 2 compat
|
2015-11-10 18:43:58 +03:00
|
|
|
"platform": Services.sysinfo.getProperty("name").toUpperCase(),
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-11-10 18:43:58 +03:00
|
|
|
// proprietary extensions
|
2015-03-20 00:12:58 +03:00
|
|
|
"XULappId" : Services.appinfo.ID,
|
|
|
|
"appBuildId" : Services.appinfo.appBuildID,
|
|
|
|
"device": device,
|
2015-11-10 18:43:58 +03:00
|
|
|
"version": Services.appinfo.version,
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
this.mm = globalMessageManager;
|
2015-04-28 16:25:37 +03:00
|
|
|
this.listener = proxy.toListener(() => this.mm, this.sendAsync.bind(this));
|
2015-03-20 18:46:46 +03:00
|
|
|
|
2015-09-26 19:12:01 +03:00
|
|
|
// always keep weak reference to current dialogue
|
2015-03-20 18:46:46 +03:00
|
|
|
this.dialog = null;
|
|
|
|
let handleDialog = (subject, topic) => {
|
|
|
|
let winr;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (topic == modal.COMMON_DIALOG_LOADED) {
|
2015-03-20 18:46:46 +03:00
|
|
|
winr = Cu.getWeakReference(subject);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 18:46:46 +03:00
|
|
|
this.dialog = new modal.Dialog(() => this.curBrowser, winr);
|
|
|
|
};
|
|
|
|
modal.addHandler(handleDialog);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.QueryInterface = XPCOMUtils.generateQI([
|
|
|
|
Ci.nsIMessageListener,
|
|
|
|
Ci.nsIObserver,
|
|
|
|
Ci.nsISupportsWeakReference
|
|
|
|
]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Switches to the global ChromeMessageBroadcaster, potentially replacing
|
|
|
|
* a frame-specific ChromeMessageSender. Has no effect if the global
|
|
|
|
* ChromeMessageBroadcaster is already in use. If this replaces a
|
|
|
|
* frame-specific ChromeMessageSender, it removes the message listeners
|
|
|
|
* from that sender, and then puts the corresponding frame script "to
|
|
|
|
* sleep", which removes most of the message listeners from it as well.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.switchToGlobalMessageManager = function() {
|
|
|
|
if (this.curBrowser && this.curBrowser.frameManager.currentRemoteFrame !== null) {
|
|
|
|
this.curBrowser.frameManager.removeMessageManagerListeners(this.mm);
|
|
|
|
this.sendAsync("sleepSession");
|
|
|
|
this.curBrowser.frameManager.currentRemoteFrame = null;
|
|
|
|
}
|
|
|
|
this.mm = globalMessageManager;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to send async messages to the content listener.
|
2015-03-24 00:32:03 +03:00
|
|
|
* Correct usage is to pass in the name of a function in listener.js,
|
2015-03-20 00:12:58 +03:00
|
|
|
* a message object consisting of JSON serialisable primitives,
|
|
|
|
* and the current command's ID.
|
|
|
|
*
|
|
|
|
* @param {string} name
|
|
|
|
* Suffix of the targetted message listener ({@code Marionette:<suffix>}).
|
|
|
|
* @param {Object=} msg
|
|
|
|
* JSON serialisable object to send to the listener.
|
|
|
|
* @param {number=} cmdId
|
|
|
|
* Command ID to ensure synchronisity.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.sendAsync = function(name, msg, cmdId) {
|
2016-05-25 17:04:40 +03:00
|
|
|
logger.info(`sendAsync ${this.sessionId}`)
|
2015-03-20 00:12:58 +03:00
|
|
|
let curRemoteFrame = this.curBrowser.frameManager.currentRemoteFrame;
|
2015-04-28 16:34:55 +03:00
|
|
|
name = "Marionette:" + name;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2016-01-29 15:57:46 +03:00
|
|
|
// TODO(ato): When proxy.AsyncMessageChannel
|
|
|
|
// is used for all chrome <-> content communication
|
|
|
|
// this can be removed.
|
2015-03-23 23:43:18 +03:00
|
|
|
if (cmdId) {
|
2015-03-20 00:12:58 +03:00
|
|
|
msg.command_id = cmdId;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
if (curRemoteFrame === null) {
|
|
|
|
this.curBrowser.executeWhenReady(() => {
|
2015-09-16 22:54:46 +03:00
|
|
|
if (this.curBrowser.curFrameId) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.mm.broadcastAsyncMessage(name + this.curBrowser.curFrameId, msg);
|
|
|
|
} else {
|
2016-05-23 19:55:03 +03:00
|
|
|
throw new NoSuchWindowError(
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
"No such content frame; perhaps the listener was not registered?");
|
2015-09-16 22:54:46 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let remoteFrameId = curRemoteFrame.targetFrameId;
|
|
|
|
try {
|
|
|
|
this.mm.sendAsyncMessage(name + remoteFrameId, msg);
|
|
|
|
} catch (e) {
|
|
|
|
switch(e.result) {
|
2016-01-29 15:57:46 +03:00
|
|
|
case Cr.NS_ERROR_FAILURE:
|
|
|
|
case Cr.NS_ERROR_NOT_INITIALIZED:
|
2015-04-29 14:00:43 +03:00
|
|
|
throw new NoSuchWindowError();
|
2015-03-20 00:12:58 +03:00
|
|
|
default:
|
|
|
|
throw new WebDriverError(e.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the current active window.
|
|
|
|
*
|
|
|
|
* @return {nsIDOMWindow}
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getCurrentWindow = function() {
|
|
|
|
let typ = null;
|
2015-04-24 15:55:52 +03:00
|
|
|
if (this.curFrame === null) {
|
|
|
|
if (this.curBrowser === null) {
|
2015-03-20 00:12:58 +03:00
|
|
|
if (this.context == Context.CONTENT) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
typ = "navigator:browser";
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
return Services.wm.getMostRecentWindow(typ);
|
|
|
|
} else {
|
|
|
|
return this.curBrowser.window;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return this.curFrame;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.addFrameCloseListener = function(action) {
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
this.mozBrowserClose = e => {
|
|
|
|
if (e.target.id == this.oopFrameId) {
|
|
|
|
win.removeEventListener("mozbrowserclose", this.mozBrowserClose, true);
|
|
|
|
this.switchToGlobalMessageManager();
|
2015-04-29 14:00:43 +03:00
|
|
|
throw new NoSuchWindowError("The window closed during action: " + action);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
win.addEventListener("mozbrowserclose", this.mozBrowserClose, true);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2016-05-10 15:29:21 +03:00
|
|
|
* Create a new browsing context for window and add to known browsers.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
|
|
|
* @param {nsIDOMWindow} win
|
2016-05-10 15:29:21 +03:00
|
|
|
* Window for which we will create a browsing context.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
|
|
|
* @return {string}
|
|
|
|
* Returns the unique server-assigned ID of the window.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.addBrowser = function(win) {
|
2016-05-10 15:29:21 +03:00
|
|
|
let bc = new browser.Context(win, this);
|
2015-03-20 00:12:58 +03:00
|
|
|
let winId = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
|
|
|
winId = winId + ((this.appName == "B2G") ? "-b2g" : "");
|
2016-05-10 15:29:21 +03:00
|
|
|
this.browsers[winId] = bc;
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curBrowser = this.browsers[winId];
|
2016-05-23 12:21:15 +03:00
|
|
|
if (!this.wins.has(winId)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
// add this to seenItems so we can guarantee
|
|
|
|
// the user will get winId as this window's id
|
2016-05-23 12:21:15 +03:00
|
|
|
this.wins.set(winId, win);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers a new browser, win, with Marionette.
|
|
|
|
*
|
|
|
|
* If we have not seen the browser content window before, the listener
|
|
|
|
* frame script will be loaded into it. If isNewSession is true, we will
|
|
|
|
* switch focus to the start frame when it registers.
|
|
|
|
*
|
|
|
|
* @param {nsIDOMWindow} win
|
|
|
|
* Window whose browser we need to access.
|
|
|
|
* @param {boolean=false} isNewSession
|
|
|
|
* True if this is the first time we're talking to this browser.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.startBrowser = function(win, isNewSession=false) {
|
2016-05-25 17:04:40 +03:00
|
|
|
logger.info(`startBrowser ${this.sessionId}`)
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mainFrame = win;
|
|
|
|
this.curFrame = null;
|
|
|
|
this.addBrowser(win);
|
|
|
|
this.curBrowser.isNewSession = isNewSession;
|
|
|
|
this.curBrowser.startSession(isNewSession, win, this.whenBrowserStarted.bind(this));
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback invoked after a new session has been started in a browser.
|
|
|
|
* Loads the Marionette frame script into the browser if needed.
|
|
|
|
*
|
|
|
|
* @param {nsIDOMWindow} win
|
|
|
|
* Window whose browser we need to access.
|
|
|
|
* @param {boolean} isNewSession
|
|
|
|
* True if this is the first time we're talking to this browser.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.whenBrowserStarted = function(win, isNewSession) {
|
|
|
|
try {
|
|
|
|
let mm = win.window.messageManager;
|
|
|
|
if (!isNewSession) {
|
|
|
|
// Loading the frame script corresponds to a situation we need to
|
|
|
|
// return to the server. If the messageManager is a message broadcaster
|
|
|
|
// with no children, we don't have a hope of coming back from this call,
|
|
|
|
// so send the ack here. Otherwise, make a note of how many child scripts
|
|
|
|
// will be loaded so we known when it's safe to return.
|
2015-04-24 15:55:52 +03:00
|
|
|
if (mm.childCount !== 0) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curBrowser.frameRegsPending = mm.childCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-19 01:05:30 +03:00
|
|
|
if (!Preferences.get(CONTENT_LISTENER_PREF) || !isNewSession) {
|
2015-03-20 00:12:58 +03:00
|
|
|
mm.loadFrameScript(FRAME_SCRIPT, true, true);
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set(CONTENT_LISTENER_PREF, true);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
// there may not always be a content process
|
|
|
|
logger.error(
|
|
|
|
`Could not load listener into content for page ${win.location.href}: ${e}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recursively get all labeled text.
|
|
|
|
*
|
|
|
|
* @param {nsIDOMElement} el
|
|
|
|
* The parent element.
|
|
|
|
* @param {Array.<string>} lines
|
|
|
|
* Array that holds the text lines.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getVisibleText = function(el, lines) {
|
|
|
|
try {
|
2016-02-03 21:56:02 +03:00
|
|
|
if (atom.isElementDisplayed(el, this.getCurrentWindow())) {
|
2015-03-20 00:12:58 +03:00
|
|
|
if (el.value) {
|
|
|
|
lines.push(el.value);
|
|
|
|
}
|
|
|
|
for (let child in el.childNodes) {
|
|
|
|
this.getVisibleText(el.childNodes[child], lines);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
if (el.nodeName == "#text") {
|
|
|
|
lines.push(el.textContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles registration of new content listener browsers. Depending on
|
|
|
|
* their type they are either accepted or ignored.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.registerBrowser = function(id, be) {
|
2015-04-24 15:55:52 +03:00
|
|
|
let nullPrevious = this.curBrowser.curFrameId === null;
|
2015-03-20 00:12:58 +03:00
|
|
|
let listenerWindow = Services.wm.getOuterWindowWithId(id);
|
|
|
|
|
|
|
|
// go in here if we're already in a remote frame
|
|
|
|
if (this.curBrowser.frameManager.currentRemoteFrame !== null &&
|
|
|
|
(!listenerWindow || this.mm == this.curBrowser.frameManager
|
|
|
|
.currentRemoteFrame.messageManager.get())) {
|
|
|
|
// The outerWindowID from an OOP frame will not be meaningful to
|
|
|
|
// the parent process here, since each process maintains its own
|
|
|
|
// independent window list. So, it will either be null (!listenerWindow)
|
|
|
|
// if we're already in a remote frame, or it will point to some
|
|
|
|
// random window, which will hopefully cause an href mismatch.
|
|
|
|
// Currently this only happens in B2G for OOP frames registered in
|
|
|
|
// Marionette:switchToFrame, so we'll acknowledge the switchToFrame
|
|
|
|
// message here.
|
|
|
|
//
|
|
|
|
// TODO: Should have a better way of determining that this message
|
|
|
|
// is from a remote frame.
|
|
|
|
this.curBrowser.frameManager.currentRemoteFrame.targetFrameId =
|
|
|
|
this.generateFrameId(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
let reg = {};
|
|
|
|
// this will be sent to tell the content process if it is the main content
|
2015-04-24 15:55:52 +03:00
|
|
|
let mainContent = this.curBrowser.mainContentId === null;
|
2015-03-20 00:12:58 +03:00
|
|
|
if (be.getAttribute("type") != "content") {
|
|
|
|
// curBrowser holds all the registered frames in knownFrames
|
|
|
|
let uid = this.generateFrameId(id);
|
|
|
|
reg.id = uid;
|
|
|
|
reg.remotenessChange = this.curBrowser.register(uid, be);
|
|
|
|
}
|
|
|
|
|
|
|
|
// set to true if we updated mainContentId
|
2015-04-24 15:55:52 +03:00
|
|
|
mainContent = mainContent && this.curBrowser.mainContentId !== null;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (mainContent) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mainContentFrameId = this.curBrowser.curFrameId;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2016-05-23 12:21:15 +03:00
|
|
|
this.wins.set(reg.id, listenerWindow);
|
2015-04-24 15:55:52 +03:00
|
|
|
if (nullPrevious && (this.curBrowser.curFrameId !== null)) {
|
2016-03-04 21:02:56 +03:00
|
|
|
this.sendAsync("newSession", this.sessionCapabilities, this.newSessionCommandId);
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.curBrowser.isNewSession) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.newSessionCommandId = null;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
|
2016-03-04 21:02:56 +03:00
|
|
|
return [reg, mainContent, this.sessionCapabilities];
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.registerPromise = function() {
|
|
|
|
const li = "Marionette:register";
|
|
|
|
|
|
|
|
return new Promise((resolve) => {
|
2015-06-24 10:10:10 +03:00
|
|
|
let cb = (msg) => {
|
2015-03-20 00:12:58 +03:00
|
|
|
let wid = msg.json.value;
|
|
|
|
let be = msg.target;
|
|
|
|
let rv = this.registerBrowser(wid, be);
|
|
|
|
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.curBrowser.frameRegsPending > 0) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curBrowser.frameRegsPending--;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-04-24 15:55:52 +03:00
|
|
|
if (this.curBrowser.frameRegsPending === 0) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mm.removeMessageListener(li, cb);
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is a sync message and listeners expect the ID back
|
|
|
|
return rv;
|
2015-06-24 10:10:10 +03:00
|
|
|
};
|
|
|
|
this.mm.addMessageListener(li, cb);
|
2015-03-20 00:12:58 +03:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.listeningPromise = function() {
|
|
|
|
const li = "Marionette:listenersAttached";
|
|
|
|
return new Promise((resolve) => {
|
2015-06-24 10:10:10 +03:00
|
|
|
let cb = () => {
|
|
|
|
this.mm.removeMessageListener(li, cb);
|
2015-03-20 00:12:58 +03:00
|
|
|
resolve();
|
2015-06-24 10:10:10 +03:00
|
|
|
};
|
|
|
|
this.mm.addMessageListener(li, cb);
|
2015-03-20 00:12:58 +03:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Create a new session. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.newSession = function*(cmd, resp) {
|
2016-05-25 17:04:40 +03:00
|
|
|
if (this.sessionId) {
|
|
|
|
throw new SessionNotCreatedError("Maximum number of active sessions.")
|
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
this.sessionId = cmd.parameters.sessionId ||
|
|
|
|
cmd.parameters.session_id ||
|
2016-02-23 18:01:12 +03:00
|
|
|
element.generateUUID();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.newSessionCommandId = cmd.id;
|
|
|
|
this.setSessionCapabilities(cmd.parameters.capabilities);
|
|
|
|
this.scriptTimeout = 10000;
|
|
|
|
|
|
|
|
let registerBrowsers = this.registerPromise();
|
|
|
|
let browserListening = this.listeningPromise();
|
|
|
|
|
|
|
|
let waitForWindow = function() {
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
if (!win) {
|
|
|
|
// if the window isn't even created, just poll wait for it
|
|
|
|
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
checkTimer.initWithCallback(waitForWindow.bind(this), 100,
|
|
|
|
Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
} else if (win.document.readyState != "complete") {
|
|
|
|
// otherwise, wait for it to be fully loaded before proceeding
|
|
|
|
let listener = ev => {
|
|
|
|
// ensure that we proceed, on the top level document load event
|
|
|
|
// (not an iframe one...)
|
2015-03-23 23:43:18 +03:00
|
|
|
if (ev.target != win.document) {
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
win.removeEventListener("load", listener);
|
|
|
|
waitForWindow.call(this);
|
|
|
|
};
|
|
|
|
win.addEventListener("load", listener, true);
|
|
|
|
} else {
|
2016-01-19 01:05:30 +03:00
|
|
|
let clickToStart = Preferences.get(CLICK_TO_START_PREF);
|
2015-03-20 00:12:58 +03:00
|
|
|
if (clickToStart && (this.appName != "B2G")) {
|
|
|
|
let pService = Cc["@mozilla.org/embedcomp/prompt-service;1"]
|
|
|
|
.getService(Ci.nsIPromptService);
|
|
|
|
pService.alert(win, "", "Click to start execution of marionette tests");
|
|
|
|
}
|
|
|
|
this.startBrowser(win, true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let runSessionStart = function() {
|
2016-01-19 01:05:30 +03:00
|
|
|
if (!Preferences.get(CONTENT_LISTENER_PREF)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
waitForWindow.call(this);
|
|
|
|
} else if (this.appName != "Firefox" && this.curBrowser === null) {
|
|
|
|
// if there is a content listener, then we just wake it up
|
|
|
|
this.addBrowser(this.getCurrentWindow());
|
|
|
|
this.curBrowser.startSession(this.whenBrowserStarted.bind(this));
|
|
|
|
this.mm.broadcastAsyncMessage("Marionette:restart", {});
|
|
|
|
} else {
|
|
|
|
throw new WebDriverError("Session already running");
|
|
|
|
}
|
|
|
|
this.switchToGlobalMessageManager();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!delayedBrowserStarted && this.appName != "B2G") {
|
|
|
|
let self = this;
|
|
|
|
Services.obs.addObserver(function onStart() {
|
|
|
|
Services.obs.removeObserver(onStart, BROWSER_STARTUP_FINISHED);
|
|
|
|
runSessionStart.call(self);
|
|
|
|
}, BROWSER_STARTUP_FINISHED, false);
|
|
|
|
} else {
|
|
|
|
runSessionStart.call(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
yield registerBrowsers;
|
|
|
|
yield browserListening;
|
|
|
|
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.sessionId = this.sessionId;
|
|
|
|
resp.body.capabilities = this.sessionCapabilities;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send the current session's capabilities to the client.
|
|
|
|
*
|
|
|
|
* Capabilities informs the client of which WebDriver features are
|
|
|
|
* supported by Firefox and Marionette. They are immutable for the
|
|
|
|
* length of the session.
|
|
|
|
*
|
|
|
|
* The return value is an immutable map of string keys
|
|
|
|
* ("capabilities") to values, which may be of types boolean,
|
|
|
|
* numerical or string.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getSessionCapabilities = function(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.capabilities = this.sessionCapabilities;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the sessionCapabilities object with the keys that have been
|
|
|
|
* passed in when a new session is created.
|
|
|
|
*
|
|
|
|
* This is not a public API, only available when a new session is
|
|
|
|
* created.
|
|
|
|
*
|
|
|
|
* @param {Object} newCaps
|
|
|
|
* Key/value dictionary to overwrite session's current capabilities.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setSessionCapabilities = function(newCaps) {
|
|
|
|
const copy = (from, to={}) => {
|
2015-06-19 17:44:25 +03:00
|
|
|
let errors = [];
|
|
|
|
|
|
|
|
// Remove any duplicates between required and desired in favour of the
|
|
|
|
// required capabilities
|
|
|
|
if (from !== null && from.desiredCapabilities) {
|
|
|
|
for (let cap in from.requiredCapabilities) {
|
|
|
|
if (from.desiredCapabilities[cap]) {
|
|
|
|
delete from.desiredCapabilities[cap];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's remove the sessionCapabilities from desired capabilities
|
|
|
|
for (let cap in this.sessionCapabilities) {
|
|
|
|
if (from.desiredCapabilities && from.desiredCapabilities[cap]) {
|
|
|
|
delete from.desiredCapabilities[cap];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
for (let key in from) {
|
2015-06-19 17:45:46 +03:00
|
|
|
switch (key) {
|
|
|
|
case "desiredCapabilities":
|
|
|
|
to = copy(from[key], to);
|
|
|
|
break;
|
2016-03-04 21:03:28 +03:00
|
|
|
|
2015-06-19 17:45:46 +03:00
|
|
|
case "requiredCapabilities":
|
2016-02-06 21:19:25 +03:00
|
|
|
if (from[key].proxy) {
|
|
|
|
this.setUpProxy(from[key].proxy);
|
|
|
|
to.proxy = from[key].proxy;
|
|
|
|
delete from[key].proxy;
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
2015-06-19 17:45:46 +03:00
|
|
|
for (let caps in from[key]) {
|
|
|
|
if (from[key][caps] !== this.sessionCapabilities[caps]) {
|
|
|
|
errors.push(from[key][caps] + " does not equal " +
|
2016-03-04 21:03:28 +03:00
|
|
|
this.sessionCapabilities[caps]);
|
2015-06-19 17:45:46 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
2015-06-19 17:45:46 +03:00
|
|
|
break;
|
2016-03-04 21:03:28 +03:00
|
|
|
|
2015-06-19 17:45:46 +03:00
|
|
|
default:
|
|
|
|
to[key] = from[key];
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-04 21:03:28 +03:00
|
|
|
if (Object.keys(errors).length == 0) {
|
2015-03-20 00:12:58 +03:00
|
|
|
return to;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
throw new SessionNotCreatedError(
|
|
|
|
`Not all requiredCapabilities could be met: ${JSON.stringify(errors)}`);
|
|
|
|
};
|
|
|
|
|
|
|
|
// clone, overwrite, and set
|
|
|
|
let caps = copy(this.sessionCapabilities);
|
|
|
|
caps = copy(newCaps, caps);
|
2016-01-03 20:19:59 +03:00
|
|
|
logger.config("Changing capabilities: " + JSON.stringify(caps));
|
2015-03-20 00:12:58 +03:00
|
|
|
this.sessionCapabilities = caps;
|
|
|
|
};
|
|
|
|
|
2016-01-03 20:19:59 +03:00
|
|
|
GeckoDriver.prototype.setUpProxy = function(proxy) {
|
2016-01-19 01:05:30 +03:00
|
|
|
logger.config("User-provided proxy settings: " + JSON.stringify(proxy));
|
2015-07-14 02:51:58 +03:00
|
|
|
|
2016-01-03 20:19:59 +03:00
|
|
|
if (typeof proxy == "object" && proxy.hasOwnProperty("proxyType")) {
|
2015-07-14 02:51:58 +03:00
|
|
|
switch (proxy.proxyType.toUpperCase()) {
|
|
|
|
case "MANUAL":
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.type", 1);
|
2015-07-14 02:51:58 +03:00
|
|
|
if (proxy.httpProxy && proxy.httpProxyPort){
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.http", proxy.httpProxy);
|
|
|
|
Preferences.set("network.proxy.http_port", proxy.httpProxyPort);
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
if (proxy.sslProxy && proxy.sslProxyPort){
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.ssl", proxy.sslProxy);
|
|
|
|
Preferences.set("network.proxy.ssl_port", proxy.sslProxyPort);
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
if (proxy.ftpProxy && proxy.ftpProxyPort) {
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.ftp", proxy.ftpProxy);
|
|
|
|
Preferences.set("network.proxy.ftp_port", proxy.ftpProxyPort);
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
if (proxy.socksProxy) {
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.socks", proxy.socksProxy);
|
|
|
|
Preferences.set("network.proxy.socks_port", proxy.socksProxyPort);
|
2015-07-14 02:51:58 +03:00
|
|
|
if (proxy.socksVersion) {
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.socks_version", proxy.socksVersion);
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-01-19 01:05:30 +03:00
|
|
|
|
2015-07-14 02:51:58 +03:00
|
|
|
case "PAC":
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.type", 2);
|
|
|
|
Preferences.set("network.proxy.autoconfig_url", proxy.pacUrl);
|
2015-07-14 02:51:58 +03:00
|
|
|
break;
|
2016-01-19 01:05:30 +03:00
|
|
|
|
2015-07-14 02:51:58 +03:00
|
|
|
case "AUTODETECT":
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.type", 4);
|
2015-07-14 02:51:58 +03:00
|
|
|
break;
|
2016-01-19 01:05:30 +03:00
|
|
|
|
2015-07-14 02:51:58 +03:00
|
|
|
case "SYSTEM":
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.type", 5);
|
2015-07-14 02:51:58 +03:00
|
|
|
break;
|
2016-01-19 01:05:30 +03:00
|
|
|
|
2015-07-14 02:51:58 +03:00
|
|
|
case "NOPROXY":
|
|
|
|
default:
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set("network.proxy.type", 0);
|
2016-02-06 21:19:46 +03:00
|
|
|
break;
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
} else {
|
2016-01-03 20:19:59 +03:00
|
|
|
throw new InvalidArgumentError("Value of 'proxy' should be an object");
|
2015-07-14 02:51:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
/**
|
|
|
|
* Log message. Accepts user defined log-level.
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* Log message.
|
|
|
|
* @param {string} level
|
|
|
|
* Arbitrary log level.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.log = function(cmd, resp) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
// if level is null, we want to use ContentLogger#send's default
|
|
|
|
this.marionetteLog.log(
|
|
|
|
cmd.parameters.value,
|
|
|
|
cmd.parameters.level || undefined);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Return all logged messages. */
|
|
|
|
GeckoDriver.prototype.getLogs = function(cmd, resp) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
resp.body = this.marionetteLog.get();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the context of the subsequent commands to be either "chrome" or
|
|
|
|
* "content".
|
|
|
|
*
|
|
|
|
* @param {string} value
|
|
|
|
* Name of the context to be switched to. Must be one of "chrome" or
|
|
|
|
* "content".
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setContext = function(cmd, resp) {
|
|
|
|
let val = cmd.parameters.value;
|
|
|
|
let ctx = Context.fromString(val);
|
2015-03-23 23:43:18 +03:00
|
|
|
if (ctx === null) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new WebDriverError(`Invalid context: ${val}`);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
this.context = ctx;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Gets the context of the server, either "chrome" or "content". */
|
|
|
|
GeckoDriver.prototype.getContext = function(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = this.context.toString();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Executes a JavaScript function in the context of the current browsing
|
|
|
|
* context, if in content space, or in chrome space otherwise, and returns
|
|
|
|
* the return value of the function.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* It is important to note that if the {@code sandboxName} parameter
|
|
|
|
* is left undefined, the script will be evaluated in a mutable sandbox,
|
|
|
|
* causing any change it makes on the global state of the document to have
|
|
|
|
* lasting side-effects.
|
|
|
|
*
|
|
|
|
* @param {string} script
|
|
|
|
* Script to evaluate as a function body.
|
|
|
|
* @param {Array.<(string|boolean|number|object|WebElement)>} args
|
|
|
|
* Arguments exposed to the script in {@code arguments}. The array
|
|
|
|
* items must be serialisable to the WebDriver protocol.
|
|
|
|
* @param {number} scriptTimeout
|
|
|
|
* Duration in milliseconds of when to interrupt and abort the
|
|
|
|
* script evaluation.
|
|
|
|
* @param {string=} sandbox
|
|
|
|
* Name of the sandbox to evaluate the script in. The sandbox is
|
|
|
|
* cached for later re-use on the same Window object if
|
|
|
|
* {@code newSandbox} is false. If he parameter is undefined,
|
|
|
|
* the script is evaluated in a mutable sandbox. If the parameter
|
|
|
|
* is "system", it will be evaluted in a sandbox with elevated system
|
|
|
|
* privileges, equivalent to chrome space.
|
|
|
|
* @param {boolean=} newSandbox
|
|
|
|
* Forces the script to be evaluated in a fresh sandbox. Note that if
|
|
|
|
* it is undefined, the script will normally be evaluted in a fresh
|
|
|
|
* sandbox.
|
|
|
|
* @param {string=} filename
|
|
|
|
* Filename of the client's program where this script is evaluated.
|
|
|
|
* @param {number=} line
|
|
|
|
* Line in the client's program where this script is evaluated.
|
|
|
|
* @param {boolean=} debug_script
|
|
|
|
* Attach an {@code onerror} event handler on the Window object.
|
|
|
|
* It does not differentiate content errors from chrome errors.
|
|
|
|
* @param {boolean=} directInject
|
|
|
|
* Evaluate the script without wrapping it in a function.
|
|
|
|
*
|
|
|
|
* @return {(string|boolean|number|object|WebElement)}
|
|
|
|
* Return value from the script, or null which signifies either the
|
|
|
|
* JavaScript notion of null or undefined.
|
|
|
|
*
|
|
|
|
* @throws ScriptTimeoutError
|
|
|
|
* If the script was interrupted due to reaching the {@code
|
|
|
|
* scriptTimeout} or default timeout.
|
|
|
|
* @throws JavaScriptError
|
|
|
|
* If an Error was thrown whilst evaluating the script.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.executeScript = function*(cmd, resp) {
|
|
|
|
let {script, args, scriptTimeout} = cmd.parameters;
|
|
|
|
scriptTimeout = scriptTimeout || this.scriptTimeout;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let opts = {
|
|
|
|
sandboxName: cmd.parameters.sandbox,
|
|
|
|
newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
|
|
|
|
cmd.parameters.newSandbox,
|
|
|
|
filename: cmd.parameters.filename,
|
|
|
|
line: cmd.parameters.line,
|
|
|
|
debug: cmd.parameters.debug_script,
|
|
|
|
};
|
2015-03-20 00:12:58 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
--HG--
extra : rebase_source : 38cc7b1e374fd42afb213133fd1a5e11bf8bdd95
2016-02-26 17:36:39 +03:00
|
|
|
};
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2016-05-07 01:12:14 +03:00
|
|
|
/**
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Executes a JavaScript function in the context of the current browsing
|
|
|
|
* context, if in content space, or in chrome space otherwise, and returns
|
|
|
|
* the object passed to the callback.
|
|
|
|
*
|
|
|
|
* The callback is always the last argument to the {@code arguments}
|
|
|
|
* list passed to the function scope of the script. It can be retrieved
|
|
|
|
* as such:
|
|
|
|
*
|
|
|
|
* let callback = arguments[arguments.length - 1];
|
|
|
|
* callback("foo");
|
|
|
|
* // "foo" is returned
|
|
|
|
*
|
|
|
|
* It is important to note that if the {@code sandboxName} parameter
|
|
|
|
* is left undefined, the script will be evaluated in a mutable sandbox,
|
|
|
|
* causing any change it makes on the global state of the document to have
|
|
|
|
* lasting side-effects.
|
2016-05-07 01:12:14 +03:00
|
|
|
*
|
|
|
|
* @param {string} script
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Script to evaluate as a function body.
|
|
|
|
* @param {Array.<(string|boolean|number|object|WebElement)>} args
|
|
|
|
* Arguments exposed to the script in {@code arguments}. The array
|
|
|
|
* items must be serialisable to the WebDriver protocol.
|
|
|
|
* @param {number} scriptTimeout
|
|
|
|
* Duration in milliseconds of when to interrupt and abort the
|
|
|
|
* script evaluation.
|
|
|
|
* @param {string=} sandbox
|
|
|
|
* Name of the sandbox to evaluate the script in. The sandbox is
|
|
|
|
* cached for later re-use on the same Window object if
|
|
|
|
* {@code newSandbox} is false. If he parameter is undefined,
|
|
|
|
* the script is evaluated in a mutable sandbox. If the parameter
|
|
|
|
* is "system", it will be evaluted in a sandbox with elevated system
|
|
|
|
* privileges, equivalent to chrome space.
|
|
|
|
* @param {boolean=} newSandbox
|
|
|
|
* Forces the script to be evaluated in a fresh sandbox. Note that if
|
|
|
|
* it is undefined, the script will normally be evaluted in a fresh
|
|
|
|
* sandbox.
|
|
|
|
* @param {string=} filename
|
|
|
|
* Filename of the client's program where this script is evaluated.
|
|
|
|
* @param {number=} line
|
|
|
|
* Line in the client's program where this script is evaluated.
|
|
|
|
* @param {boolean=} debug_script
|
|
|
|
* Attach an {@code onerror} event handler on the Window object.
|
|
|
|
* It does not differentiate content errors from chrome errors.
|
|
|
|
* @param {boolean=} directInject
|
|
|
|
* Evaluate the script without wrapping it in a function.
|
|
|
|
*
|
|
|
|
* @return {(string|boolean|number|object|WebElement)}
|
|
|
|
* Return value from the script, or null which signifies either the
|
|
|
|
* JavaScript notion of null or undefined.
|
|
|
|
*
|
|
|
|
* @throws ScriptTimeoutError
|
|
|
|
* If the script was interrupted due to reaching the {@code
|
|
|
|
* scriptTimeout} or default timeout.
|
|
|
|
* @throws JavaScriptError
|
|
|
|
* If an Error was thrown whilst evaluating the script.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.executeAsyncScript = function(cmd, resp) {
|
|
|
|
let {script, args, scriptTimeout} = cmd.parameters;
|
|
|
|
scriptTimeout = scriptTimeout || this.scriptTimeout;
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
--HG--
extra : rebase_source : 38cc7b1e374fd42afb213133fd1a5e11bf8bdd95
2016-02-26 17:36:39 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let opts = {
|
|
|
|
sandboxName: cmd.parameters.sandbox,
|
|
|
|
newSandbox: !!(typeof cmd.parameters.newSandbox == "undefined") ||
|
|
|
|
cmd.parameters.newSandbox,
|
|
|
|
filename: cmd.parameters.filename,
|
|
|
|
line: cmd.parameters.line,
|
|
|
|
debug: cmd.parameters.debug_script,
|
|
|
|
async: true,
|
|
|
|
};
|
2015-03-20 00:12:58 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
resp.body.value = yield this.execute_(script, args, scriptTimeout, opts);
|
|
|
|
};
|
2016-05-07 01:12:14 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
GeckoDriver.prototype.execute_ = function(script, args, timeout, opts = {}) {
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CONTENT:
|
|
|
|
// evaluate in content with lasting side-effects
|
|
|
|
if (!opts.sandboxName) {
|
|
|
|
return this.listener.execute(script, args, timeout, opts);
|
|
|
|
|
|
|
|
// evaluate in content with sandbox
|
|
|
|
} else {
|
|
|
|
return this.listener.executeInSandbox(script, args, timeout, opts);
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
--HG--
extra : rebase_source : 38cc7b1e374fd42afb213133fd1a5e11bf8bdd95
2016-02-26 17:36:39 +03:00
|
|
|
}
|
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
case Context.CHROME:
|
|
|
|
let sb = this.sandboxes.get(opts.sandboxName, opts.newSandbox);
|
|
|
|
if (opts.sandboxName) {
|
|
|
|
sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
|
|
|
|
sb = sandbox.augment(sb, {global: sb});
|
|
|
|
}
|
|
|
|
|
|
|
|
opts.timeout = timeout;
|
|
|
|
script = this.importedScripts.for(Context.CHROME).concat(script);
|
2016-05-20 18:49:19 +03:00
|
|
|
let wargs = element.fromJson(args, this.curBrowser.seenEls, sb.window);
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let evaluatePromise = evaluate.sandbox(sb, script, wargs, opts);
|
2016-05-20 18:49:19 +03:00
|
|
|
return evaluatePromise.then(res => element.toJson(res, this.curBrowser.seenEls));
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Execute pure JavaScript. Used to execute simpletest harness tests,
|
|
|
|
* which are like mochitests only injected using Marionette.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Scripts are expected to call the {@code finish} global when done.
|
2015-03-20 00:12:58 +03:00
|
|
|
*/
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
GeckoDriver.prototype.executeJSScript = function(cmd, resp) {
|
|
|
|
let {script, args, scriptTimeout} = cmd.parameters;
|
|
|
|
scriptTimeout = scriptTimeout || this.scriptTimeout;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let opts = {
|
|
|
|
filename: cmd.parameters.filename,
|
|
|
|
line: cmd.parameters.line,
|
|
|
|
async: cmd.parameters.async,
|
|
|
|
};
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let wargs = element.fromJson(args, this.curBrowser.seenEls, win);
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
let harness = new simpletest.Harness(
|
|
|
|
win,
|
|
|
|
Context.CHROME,
|
|
|
|
this.marionetteLog,
|
|
|
|
scriptTimeout,
|
|
|
|
function() {},
|
|
|
|
this.testName);
|
|
|
|
|
|
|
|
let sb = sandbox.createSimpleTest(win, harness);
|
|
|
|
// TODO(ato): Not sure this is needed:
|
|
|
|
sb = sandbox.augment(sb, new logging.Adapter(this.marionetteLog));
|
|
|
|
|
|
|
|
let res = yield evaluate.sandbox(sb, script, wargs, opts);
|
2016-05-20 18:49:19 +03:00
|
|
|
resp.body.value = element.toJson(res, this.curBrowser.seenEls);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
resp.body.value = yield this.listener.executeSimpleTest(script, args, scriptTimeout, opts);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* Set the timeout for asynchronous script execution.
|
2016-05-07 01:12:14 +03:00
|
|
|
*
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
* @param {number} ms
|
|
|
|
* Time in milliseconds.
|
2015-03-20 00:12:58 +03:00
|
|
|
*/
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
GeckoDriver.prototype.setScriptTimeout = function(cmd, resp) {
|
|
|
|
let ms = parseInt(cmd.parameters.ms);
|
|
|
|
if (isNaN(ms)) {
|
|
|
|
throw new WebDriverError("Not a Number");
|
2016-05-07 01:12:14 +03:00
|
|
|
}
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.scriptTimeout = ms;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2015-05-04 13:25:03 +03:00
|
|
|
* Navigate to given URL.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
2015-05-04 13:25:03 +03:00
|
|
|
* Navigates the current browsing context to the given URL and waits for
|
|
|
|
* the document to load or the session's page timeout duration to elapse
|
|
|
|
* before returning.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
2015-05-04 13:25:03 +03:00
|
|
|
* The command will return with a failure if there is an error loading
|
|
|
|
* the document or the URL is blocked. This can occur if it fails to
|
|
|
|
* reach host, the URL is malformed, or if there is a certificate issue
|
|
|
|
* to name some examples.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
2015-05-04 13:25:03 +03:00
|
|
|
* The document is considered successfully loaded when the
|
|
|
|
* DOMContentLoaded event on the frame element associated with the
|
|
|
|
* current window triggers and document.readyState is "complete".
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
2015-05-04 13:25:03 +03:00
|
|
|
* In chrome context it will change the current window's location to
|
|
|
|
* the supplied URL and wait until document.readyState equals "complete"
|
|
|
|
* or the page timeout duration has elapsed.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
|
|
|
* @param {string} url
|
|
|
|
* URL to navigate to.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.get = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let url = cmd.parameters.url;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CONTENT:
|
2015-04-28 20:15:08 +03:00
|
|
|
let get = this.listener.get({url: url, pageTimeout: this.pageTimeout});
|
2016-01-21 22:27:23 +03:00
|
|
|
// TODO(ato): Bug 1242595
|
|
|
|
let id = this.listener.activeMessageId;
|
2015-04-28 20:15:08 +03:00
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
// If a remoteness update interrupts our page load, this will never return
|
|
|
|
// We need to re-issue this request to correctly poll for readyState and
|
|
|
|
// send errors.
|
|
|
|
this.curBrowser.pendingCommands.push(() => {
|
2015-04-28 20:15:08 +03:00
|
|
|
cmd.parameters.command_id = id;
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mm.broadcastAsyncMessage(
|
|
|
|
"Marionette:pollForReadyState" + this.curBrowser.curFrameId,
|
|
|
|
cmd.parameters);
|
|
|
|
});
|
2015-04-28 20:15:08 +03:00
|
|
|
|
|
|
|
yield get;
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CHROME:
|
|
|
|
// At least on desktop, navigating in chrome scope does not
|
|
|
|
// correspond to something a user can do, and leaves marionette
|
|
|
|
// and the browser in an unusable state. Return a generic error insted.
|
|
|
|
// TODO: Error codes need to be refined as a part of bug 1100545 and
|
|
|
|
// bug 945729.
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName == "Firefox") {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new UnknownError("Cannot navigate in chrome context");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.getCurrentWindow().location.href = url;
|
|
|
|
yield this.pageLoadPromise();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.pageLoadPromise = function() {
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
let timeout = this.pageTimeout;
|
|
|
|
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
let start = new Date().getTime();
|
|
|
|
let end = null;
|
|
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
let checkLoad = function() {
|
|
|
|
end = new Date().getTime();
|
|
|
|
let elapse = end - start;
|
2015-04-24 15:55:52 +03:00
|
|
|
if (timeout === null || elapse <= timeout) {
|
2015-03-23 23:43:18 +03:00
|
|
|
if (win.document.readyState == "complete") {
|
2015-03-20 00:12:58 +03:00
|
|
|
resolve();
|
2015-03-23 23:43:18 +03:00
|
|
|
} else {
|
2015-03-20 00:12:58 +03:00
|
|
|
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
} else {
|
|
|
|
throw new UnknownError("Error loading page");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a string representing the current URL.
|
|
|
|
*
|
|
|
|
* On Desktop this returns a string representation of the URL of the
|
|
|
|
* current top level browsing context. This is equivalent to
|
|
|
|
* document.location.href.
|
|
|
|
*
|
|
|
|
* When in the context of the chrome, this returns the canonical URL
|
|
|
|
* of the current resource.
|
|
|
|
*/
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
GeckoDriver.prototype.getCurrentUrl = function(cmd) {
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
return this.getCurrentWindow().location.href;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
case Context.CONTENT:
|
|
|
|
let isB2G = this.appName == "B2G";
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
return this.listener.getCurrentUrl(isB2G);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Gets the current title of the window. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getTitle = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = win.document.documentElement.getAttribute("title");
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getTitle();
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Gets the current type of the window. */
|
|
|
|
GeckoDriver.prototype.getWindowType = function(cmd, resp) {
|
|
|
|
let win = this.getCurrentWindow();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = win.document.documentElement.getAttribute("windowtype");
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Gets the page source of the content document. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getPageSource = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
let s = new win.XMLSerializer();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = s.serializeToString(win.document);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getPageSource();
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Go back in history. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.goBack = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
yield this.listener.goBack();
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Go forward in history. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.goForward = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
yield this.listener.goForward();
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Refresh the page. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.refresh = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
yield this.listener.refresh();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current window's handle. On desktop this typically corresponds
|
|
|
|
* to the currently selected tab.
|
|
|
|
*
|
|
|
|
* Return an opaque server-assigned identifier to this window that
|
|
|
|
* uniquely identifies it within this Marionette instance. This can
|
|
|
|
* be used to switch to this window at a later point.
|
|
|
|
*
|
|
|
|
* @return {string}
|
|
|
|
* Unique window handle.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getWindowHandle = function(cmd, resp) {
|
|
|
|
// curFrameId always holds the current tab.
|
|
|
|
if (this.curBrowser.curFrameId && this.appName != "B2G") {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = this.curBrowser.curFrameId;
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i in this.browsers) {
|
|
|
|
if (this.curBrowser == this.browsers[i]) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = i;
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Forces an update for the given browser's id.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
|
|
|
|
this._browserIds.set(browser.permanentKey, newId);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves a listener id for the given xul browser element. In case
|
|
|
|
* the browser is not known, an attempt is made to retrieve the id from
|
|
|
|
* a CPOW, and null is returned if this fails.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getIdForBrowser = function getIdForBrowser(browser) {
|
|
|
|
if (browser === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
let permKey = browser.permanentKey;
|
|
|
|
if (this._browserIds.has(permKey)) {
|
|
|
|
return this._browserIds.get(permKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
let winId = browser.outerWindowID;
|
|
|
|
if (winId) {
|
|
|
|
winId += "";
|
|
|
|
this._browserIds.set(permKey, winId);
|
|
|
|
return winId;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a list of top-level browsing contexts. On desktop this typically
|
|
|
|
* corresponds to the set of open tabs.
|
|
|
|
*
|
|
|
|
* Each window handle is assigned by the server and is guaranteed unique,
|
|
|
|
* however the return array does not have a specified ordering.
|
|
|
|
*
|
|
|
|
* @return {Array.<string>}
|
|
|
|
* Unique window handles.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getWindowHandles = function(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
let hs = [];
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
let win = winEn.getNext();
|
|
|
|
if (win.gBrowser && this.appName != "B2G") {
|
|
|
|
let tabbrowser = win.gBrowser;
|
|
|
|
for (let i = 0; i < tabbrowser.browsers.length; ++i) {
|
|
|
|
let winId = this.getIdForBrowser(tabbrowser.getBrowserAtIndex(i));
|
|
|
|
if (winId !== null) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
hs.push(winId);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// XUL Windows, at least, do not have gBrowser
|
|
|
|
let winId = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Ci.nsIDOMWindowUtils)
|
|
|
|
.outerWindowID;
|
|
|
|
winId += (this.appName == "B2G") ? "-b2g" : "";
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
hs.push(winId);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
}
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body = hs;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current window's handle. This corresponds to a window that
|
|
|
|
* may itself contain tabs.
|
|
|
|
*
|
|
|
|
* Return an opaque server-assigned identifier to this window that
|
|
|
|
* uniquely identifies it within this Marionette instance. This can
|
|
|
|
* be used to switch to this window at a later point.
|
|
|
|
*
|
|
|
|
* @return {string}
|
|
|
|
* Unique window handle.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getChromeWindowHandle = function(cmd, resp) {
|
|
|
|
for (let i in this.browsers) {
|
|
|
|
if (this.curBrowser == this.browsers[i]) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = i;
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns identifiers for each open chrome window for tests interested in
|
|
|
|
* managing a set of chrome windows and tabs separately.
|
|
|
|
*
|
|
|
|
* @return {Array.<string>}
|
|
|
|
* Unique window handles.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getChromeWindowHandles = function(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
let hs = [];
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
let foundWin = winEn.getNext();
|
|
|
|
let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Ci.nsIDOMWindowUtils)
|
|
|
|
.outerWindowID;
|
|
|
|
winId = winId + ((this.appName == "B2G") ? "-b2g" : "");
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
hs.push(winId);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body = hs;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current window position.
|
|
|
|
*
|
|
|
|
* @return {Object.<string, number>}
|
|
|
|
* Object with x and y coordinates.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getWindowPosition = function(cmd, resp) {
|
|
|
|
let win = this.getCurrentWindow();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.x = win.screenX;
|
|
|
|
resp.body.y = win.screenY;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the window position of the browser on the OS Window Manager
|
|
|
|
*
|
|
|
|
* @param {number} x
|
|
|
|
* X coordinate of the top/left of the window that it will be
|
|
|
|
* moved to.
|
|
|
|
* @param {number} y
|
|
|
|
* Y coordinate of the top/left of the window that it will be
|
|
|
|
* moved to.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setWindowPosition = function(cmd, resp) {
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName != "Firefox") {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new WebDriverError("Unable to set the window position on mobile");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let x = parseInt(cmd.parameters.x);
|
|
|
|
let y = parseInt(cmd.parameters.y);
|
2015-03-23 23:43:18 +03:00
|
|
|
if (isNaN(x) || isNaN(y)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new UnknownError("x and y arguments should be integers");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
win.moveTo(x, y);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Switch current top-level browsing context by name or server-assigned ID.
|
|
|
|
* Searches for windows by name, then ID. Content windows take precedence.
|
|
|
|
*
|
|
|
|
* @param {string} name
|
|
|
|
* Target name or ID of the window to switch to.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.switchToWindow = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let switchTo = cmd.parameters.name;
|
|
|
|
let isB2G = this.appName == "B2G";
|
|
|
|
let found;
|
|
|
|
|
|
|
|
let getOuterWindowId = function(win) {
|
|
|
|
let rv = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Ci.nsIDOMWindowUtils)
|
|
|
|
.outerWindowID;
|
|
|
|
rv += isB2G ? "-b2g" : "";
|
|
|
|
return rv;
|
|
|
|
};
|
|
|
|
|
|
|
|
let byNameOrId = function(name, outerId, contentWindowId) {
|
|
|
|
return switchTo == name ||
|
|
|
|
switchTo == contentWindowId ||
|
|
|
|
switchTo == outerId;
|
|
|
|
};
|
|
|
|
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
let win = winEn.getNext();
|
|
|
|
let outerId = getOuterWindowId(win);
|
|
|
|
|
|
|
|
if (win.gBrowser && !isB2G) {
|
|
|
|
let tabbrowser = win.gBrowser;
|
|
|
|
for (let i = 0; i < tabbrowser.browsers.length; ++i) {
|
|
|
|
let browser = tabbrowser.getBrowserAtIndex(i);
|
|
|
|
let contentWindowId = this.getIdForBrowser(browser);
|
|
|
|
if (byNameOrId(win.name, contentWindowId, outerId)) {
|
|
|
|
found = {
|
|
|
|
win: win,
|
|
|
|
outerId: outerId,
|
|
|
|
tabIndex: i,
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (byNameOrId(win.name, outerId)) {
|
|
|
|
found = {win: win, outerId: outerId};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
// Initialise Marionette if browser has not been seen before,
|
|
|
|
// otherwise switch to known browser and activate the tab if it's a
|
|
|
|
// content browser.
|
|
|
|
if (!(found.outerId in this.browsers)) {
|
|
|
|
let registerBrowsers, browserListening;
|
2015-06-01 23:26:15 +03:00
|
|
|
if ("tabIndex" in found) {
|
2015-03-20 00:12:58 +03:00
|
|
|
registerBrowsers = this.registerPromise();
|
|
|
|
browserListening = this.listeningPromise();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.startBrowser(found.win, false /* isNewSession */);
|
|
|
|
|
|
|
|
if (registerBrowsers && browserListening) {
|
|
|
|
yield registerBrowsers;
|
|
|
|
yield browserListening;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.curBrowser = this.browsers[found.outerId];
|
|
|
|
|
2015-06-01 23:26:15 +03:00
|
|
|
if ("tabIndex" in found) {
|
|
|
|
this.curBrowser.switchToTab(found.tabIndex, found.win);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new NoSuchWindowError(`Unable to locate window: ${switchTo}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.getActiveFrame = function(cmd, resp) {
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
// no frame means top-level
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = null;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.curFrame) {
|
2016-05-20 18:49:19 +03:00
|
|
|
resp.body.value = this.curBrowser.seenEls
|
2016-05-20 15:28:27 +03:00
|
|
|
.add(this.curFrame.frameElement);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = this.currentFrameElement;
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
|
2015-10-19 23:39:48 +03:00
|
|
|
let res = yield this.listener.switchToParentFrame();
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
/**
|
|
|
|
* Switch to a given frame within the current window.
|
|
|
|
*
|
|
|
|
* @param {Object} element
|
|
|
|
* A web element reference to the element to switch to.
|
|
|
|
* @param {(string|number)} id
|
|
|
|
* If element is not defined, then this holds either the id, name,
|
|
|
|
* or index of the frame to switch to.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.switchToFrame = function*(cmd, resp) {
|
2015-11-09 20:48:31 +03:00
|
|
|
let {id, element, focus} = cmd.parameters;
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
let curWindow = this.getCurrentWindow();
|
|
|
|
|
|
|
|
let checkLoad = function() {
|
|
|
|
let errorRegex = /about:.+(error)|(blocked)\?/;
|
|
|
|
let curWindow = this.getCurrentWindow();
|
|
|
|
if (curWindow.document.readyState == "complete") {
|
|
|
|
return;
|
|
|
|
} else if (curWindow.document.readyState == "interactive" &&
|
|
|
|
errorRegex.exec(curWindow.document.baseURI)) {
|
|
|
|
throw new UnknownError("Error loading page");
|
|
|
|
}
|
|
|
|
|
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.context == Context.CHROME) {
|
|
|
|
let foundFrame = null;
|
2015-04-24 15:55:52 +03:00
|
|
|
|
2015-11-09 20:48:31 +03:00
|
|
|
// just focus
|
|
|
|
if (typeof id == "undefined" && typeof element == "undefined") {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curFrame = null;
|
2015-11-09 20:48:31 +03:00
|
|
|
if (focus) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mainFrame.focus();
|
|
|
|
}
|
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
return;
|
|
|
|
}
|
2015-04-24 15:55:52 +03:00
|
|
|
|
2015-11-09 20:48:31 +03:00
|
|
|
// by element
|
2016-05-20 17:07:21 +03:00
|
|
|
if (this.curBrowser.seenEls.has(element)) {
|
|
|
|
// HTMLIFrameElement
|
2016-05-20 18:49:19 +03:00
|
|
|
let wantedFrame = this.curBrowser.seenEls.get(element, {frame: curWindow});
|
2016-05-20 17:07:21 +03:00
|
|
|
// Deal with an embedded xul:browser case
|
|
|
|
if (wantedFrame.tagName == "xul:browser" || wantedFrame.tagName == "browser") {
|
|
|
|
curWindow = wantedFrame.contentWindow;
|
|
|
|
this.curFrame = curWindow;
|
|
|
|
if (focus) {
|
|
|
|
this.curFrame.focus();
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
2016-05-20 17:07:21 +03:00
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
return;
|
|
|
|
}
|
2016-01-09 00:55:55 +03:00
|
|
|
|
2016-05-20 17:07:21 +03:00
|
|
|
// Check if the frame is XBL anonymous
|
|
|
|
let parent = curWindow.document.getBindingParent(wantedFrame);
|
|
|
|
// Shadow nodes also show up in getAnonymousNodes, we should ignore them.
|
|
|
|
if (parent && !(parent.shadowRoot && parent.shadowRoot.contains(wantedFrame))) {
|
|
|
|
let anonNodes = [...curWindow.document.getAnonymousNodes(parent) || []];
|
|
|
|
if (anonNodes.length > 0) {
|
|
|
|
let el = wantedFrame;
|
|
|
|
while (el) {
|
|
|
|
if (anonNodes.indexOf(el) > -1) {
|
|
|
|
curWindow = wantedFrame.contentWindow;
|
|
|
|
this.curFrame = curWindow;
|
|
|
|
if (focus) {
|
|
|
|
this.curFrame.focus();
|
2016-01-09 00:55:55 +03:00
|
|
|
}
|
2016-05-20 17:07:21 +03:00
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
return;
|
2016-01-09 00:55:55 +03:00
|
|
|
}
|
2016-05-20 17:07:21 +03:00
|
|
|
el = el.parentNode;
|
2016-01-09 00:55:55 +03:00
|
|
|
}
|
|
|
|
}
|
2016-05-20 17:07:21 +03:00
|
|
|
}
|
2016-01-09 00:55:55 +03:00
|
|
|
|
2016-05-20 17:07:21 +03:00
|
|
|
// else, assume iframe
|
|
|
|
let frames = curWindow.document.getElementsByTagName("iframe");
|
|
|
|
let numFrames = frames.length;
|
|
|
|
for (let i = 0; i < numFrames; i++) {
|
|
|
|
if (new XPCNativeWrapper(frames[i]) == new XPCNativeWrapper(wantedFrame)) {
|
|
|
|
curWindow = frames[i].contentWindow;
|
|
|
|
this.curFrame = curWindow;
|
|
|
|
if (focus) {
|
|
|
|
this.curFrame.focus();
|
2015-11-09 20:48:31 +03:00
|
|
|
}
|
2016-05-20 17:07:21 +03:00
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
return;
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-09 20:48:31 +03:00
|
|
|
|
|
|
|
switch (typeof id) {
|
|
|
|
case "string" :
|
|
|
|
let foundById = null;
|
|
|
|
let frames = curWindow.document.getElementsByTagName("iframe");
|
|
|
|
let numFrames = frames.length;
|
|
|
|
for (let i = 0; i < numFrames; i++) {
|
|
|
|
//give precedence to name
|
|
|
|
let frame = frames[i];
|
|
|
|
if (frame.getAttribute("name") == id) {
|
|
|
|
foundFrame = i;
|
|
|
|
curWindow = frame.contentWindow;
|
|
|
|
break;
|
|
|
|
} else if (foundById === null && frame.id == id) {
|
|
|
|
foundById = i;
|
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
2015-11-09 20:48:31 +03:00
|
|
|
if (foundFrame === null && foundById !== null) {
|
|
|
|
foundFrame = foundById;
|
|
|
|
curWindow = frames[foundById].contentWindow;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "number":
|
|
|
|
if (typeof curWindow.frames[id] != "undefined") {
|
|
|
|
foundFrame = id;
|
|
|
|
curWindow = curWindow.frames[foundFrame].frameElement.contentWindow;
|
|
|
|
}
|
|
|
|
break;
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
2015-11-09 20:48:31 +03:00
|
|
|
|
2015-04-24 15:55:52 +03:00
|
|
|
if (foundFrame !== null) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curFrame = curWindow;
|
2015-11-09 20:48:31 +03:00
|
|
|
if (focus) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curFrame.focus();
|
|
|
|
}
|
|
|
|
checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
|
|
} else {
|
2015-11-09 20:48:31 +03:00
|
|
|
throw new NoSuchFrameError(`Unable to locate frame: ${id}`);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
2015-11-09 20:48:31 +03:00
|
|
|
|
|
|
|
} else if (this.context == Context.CONTENT) {
|
|
|
|
if (!id && !element &&
|
|
|
|
this.curBrowser.frameManager.currentRemoteFrame !== null) {
|
2015-03-20 00:12:58 +03:00
|
|
|
// We're currently using a ChromeMessageSender for a remote frame, so this
|
|
|
|
// request indicates we need to switch back to the top-level (parent) frame.
|
|
|
|
// We'll first switch to the parent's (global) ChromeMessageBroadcaster, so
|
|
|
|
// we send the message to the right listener.
|
|
|
|
this.switchToGlobalMessageManager();
|
|
|
|
}
|
|
|
|
cmd.command_id = cmd.id;
|
|
|
|
|
|
|
|
let res = yield this.listener.switchToFrame(cmd.parameters);
|
|
|
|
if (res) {
|
|
|
|
let {win: winId, frame: frameId} = res;
|
|
|
|
this.mm = this.curBrowser.frameManager.getFrameMM(winId, frameId);
|
|
|
|
|
|
|
|
let registerBrowsers = this.registerPromise();
|
|
|
|
let browserListening = this.listeningPromise();
|
|
|
|
|
|
|
|
this.oopFrameId =
|
|
|
|
this.curBrowser.frameManager.switchToFrame(winId, frameId);
|
|
|
|
|
|
|
|
yield registerBrowsers;
|
|
|
|
yield browserListening;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set timeout for searching for elements.
|
|
|
|
*
|
|
|
|
* @param {number} ms
|
|
|
|
* Search timeout in milliseconds.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setSearchTimeout = function(cmd, resp) {
|
|
|
|
let ms = parseInt(cmd.parameters.ms);
|
2015-03-23 23:43:18 +03:00
|
|
|
if (isNaN(ms)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new WebDriverError("Not a Number");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
this.searchTimeout = ms;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set timeout for page loading, searching, and scripts.
|
|
|
|
*
|
|
|
|
* @param {string} type
|
|
|
|
* Type of timeout.
|
|
|
|
* @param {number} ms
|
|
|
|
* Timeout in milliseconds.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.timeouts = function(cmd, resp) {
|
|
|
|
let typ = cmd.parameters.type;
|
|
|
|
let ms = parseInt(cmd.parameters.ms);
|
2015-03-23 23:43:18 +03:00
|
|
|
if (isNaN(ms)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new WebDriverError("Not a Number");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
switch (typ) {
|
|
|
|
case "implicit":
|
|
|
|
this.setSearchTimeout(cmd, resp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "script":
|
|
|
|
this.setScriptTimeout(cmd, resp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
this.pageTimeout = ms;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Single tap. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.singleTap = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let {id, x, y} = cmd.parameters;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
throw new WebDriverError("Command 'singleTap' is not available in chrome context");
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
|
|
|
this.addFrameCloseListener("tap");
|
2015-09-10 18:45:33 +03:00
|
|
|
yield this.listener.singleTap(id, x, y);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An action chain.
|
|
|
|
*
|
|
|
|
* @param {Object} value
|
|
|
|
* A nested array where the inner array represents each event,
|
|
|
|
* and the outer array represents a collection of events.
|
|
|
|
*
|
|
|
|
* @return {number}
|
|
|
|
* Last touch ID.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.actionChain = function*(cmd, resp) {
|
2015-03-24 18:35:58 +03:00
|
|
|
let {chain, nextId} = cmd.parameters;
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
2015-03-24 18:35:58 +03:00
|
|
|
if (this.appName != "Firefox") {
|
|
|
|
// be conservative until this has a use case and is established
|
|
|
|
// to work as expected on b2g/fennec
|
|
|
|
throw new WebDriverError(
|
|
|
|
"Command 'actionChain' is not available in chrome context");
|
|
|
|
}
|
|
|
|
|
|
|
|
let win = this.getCurrentWindow();
|
2016-02-22 16:18:13 +03:00
|
|
|
resp.body.value = yield this.actions.dispatchActions(
|
2016-05-20 18:49:19 +03:00
|
|
|
chain, nextId, {frame: win}, this.curBrowser.seenEls);
|
2015-03-24 18:35:58 +03:00
|
|
|
break;
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
case Context.CONTENT:
|
|
|
|
this.addFrameCloseListener("action chain");
|
2015-09-02 15:36:03 +03:00
|
|
|
resp.body.value = yield this.listener.actionChain(chain, nextId);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A multi-action chain.
|
|
|
|
*
|
|
|
|
* @param {Object} value
|
|
|
|
* A nested array where the inner array represents eache vent,
|
|
|
|
* the middle array represents a collection of events for each
|
|
|
|
* finger, and the outer array represents all fingers.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.multiAction = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
2015-03-23 23:43:18 +03:00
|
|
|
case Context.CHROME:
|
|
|
|
throw new WebDriverError("Command 'multiAction' is not available in chrome context");
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-03-23 23:43:18 +03:00
|
|
|
case Context.CONTENT:
|
|
|
|
this.addFrameCloseListener("multi action chain");
|
2015-11-30 18:20:05 +03:00
|
|
|
yield this.listener.multiAction(cmd.parameters.value, cmd.parameters.max_length);
|
2015-03-23 23:43:18 +03:00
|
|
|
break;
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find an element using the indicated search strategy.
|
|
|
|
*
|
|
|
|
* @param {string} using
|
|
|
|
* Indicates which search method to use.
|
|
|
|
* @param {string} value
|
|
|
|
* Value the client is looking for.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.findElement = function*(cmd, resp) {
|
2016-05-20 15:28:27 +03:00
|
|
|
let strategy = cmd.parameters.using;
|
|
|
|
let expr = cmd.parameters.value;
|
2016-02-23 18:19:21 +03:00
|
|
|
let opts = {
|
|
|
|
startNode: cmd.parameters.element,
|
|
|
|
timeout: this.searchTimeout,
|
|
|
|
all: false,
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
2016-05-20 15:28:27 +03:00
|
|
|
if (!SUPPORTED_STRATEGIES.has(strategy)) {
|
|
|
|
throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
|
|
|
|
}
|
|
|
|
|
2016-02-23 18:19:21 +03:00
|
|
|
let container = {frame: this.getCurrentWindow()};
|
2016-05-20 15:28:27 +03:00
|
|
|
if (opts.startNode) {
|
2016-05-20 18:49:19 +03:00
|
|
|
opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
|
2016-05-20 15:28:27 +03:00
|
|
|
}
|
|
|
|
let el = yield element.find(container, strategy, expr, opts);
|
2016-05-20 18:49:19 +03:00
|
|
|
let elRef = this.curBrowser.seenEls.add(el);
|
2016-05-20 15:28:27 +03:00
|
|
|
let webEl = element.makeWebElement(elRef);
|
|
|
|
|
|
|
|
resp.body.value = webEl;
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
2016-02-23 18:19:21 +03:00
|
|
|
resp.body.value = yield this.listener.findElementContent(
|
2016-05-20 15:28:27 +03:00
|
|
|
strategy,
|
|
|
|
expr,
|
2016-02-23 18:19:21 +03:00
|
|
|
opts);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find elements using the indicated search strategy.
|
|
|
|
*
|
|
|
|
* @param {string} using
|
|
|
|
* Indicates which search method to use.
|
|
|
|
* @param {string} value
|
|
|
|
* Value the client is looking for.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.findElements = function*(cmd, resp) {
|
2016-05-20 15:28:27 +03:00
|
|
|
let strategy = cmd.parameters.using;
|
|
|
|
let expr = cmd.parameters.value;
|
2016-02-23 18:19:21 +03:00
|
|
|
let opts = {
|
|
|
|
startNode: cmd.parameters.element,
|
|
|
|
timeout: this.searchTimeout,
|
|
|
|
all: true,
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
2016-05-20 15:28:27 +03:00
|
|
|
if (!SUPPORTED_STRATEGIES.has(strategy)) {
|
|
|
|
throw new InvalidSelectorError(`Strategy not supported: ${strategy}`);
|
|
|
|
}
|
|
|
|
|
2016-02-23 18:19:21 +03:00
|
|
|
let container = {frame: this.getCurrentWindow()};
|
2016-05-20 15:28:27 +03:00
|
|
|
if (opts.startNode) {
|
2016-05-20 18:49:19 +03:00
|
|
|
opts.startNode = this.curBrowser.seenEls.get(opts.startNode, container);
|
2016-05-20 15:28:27 +03:00
|
|
|
}
|
|
|
|
let els = yield element.find(container, strategy, expr, opts);
|
|
|
|
|
2016-05-20 18:49:19 +03:00
|
|
|
let elRefs = this.curBrowser.seenEls.addAll(els);
|
2016-05-20 15:28:27 +03:00
|
|
|
let webEls = elRefs.map(element.makeWebElement);
|
|
|
|
resp.body = webEls;
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
2016-02-23 18:19:21 +03:00
|
|
|
resp.body = yield this.listener.findElementsContent(
|
|
|
|
cmd.parameters.using,
|
|
|
|
cmd.parameters.value,
|
|
|
|
opts);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Return the active element on the page. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getActiveElement();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send click event to element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be clicked.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.clickElement = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-03-03 16:58:13 +03:00
|
|
|
yield interaction.clickElement(
|
|
|
|
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
|
|
|
// We need to protect against the click causing an OOP frame to close.
|
|
|
|
// This fires the mozbrowserclose event when it closes so we need to
|
|
|
|
// listen for it and then just send an error back. The person making the
|
|
|
|
// call should be aware something isnt right and handle accordingly
|
|
|
|
this.addFrameCloseListener("click");
|
2015-04-15 14:18:00 +03:00
|
|
|
yield this.listener.clickElement(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a given attribute of an element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
2016-05-13 16:42:05 +03:00
|
|
|
* Web element reference ID to the element that will be inspected.
|
2015-03-20 00:12:58 +03:00
|
|
|
* @param {string} name
|
2016-05-13 16:42:05 +03:00
|
|
|
* Name of the attribute which value to retrieve.
|
|
|
|
*
|
|
|
|
* @return {string}
|
|
|
|
* Value of the attribute.
|
2015-03-20 00:12:58 +03:00
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let {id, name} = cmd.parameters;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-02-03 21:56:02 +03:00
|
|
|
resp.body.value = atom.getElementAttribute(el, name, this.getCurrentWindow());
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getElementAttribute(id, name);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-13 16:42:05 +03:00
|
|
|
/**
|
|
|
|
* Returns the value of a property associated with given element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Web element reference ID to the element that will be inspected.
|
|
|
|
* @param {string} name
|
|
|
|
* Name of the property which value to retrieve.
|
|
|
|
*
|
|
|
|
* @return {string}
|
|
|
|
* Value of the property.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getElementProperty = function*(cmd, resp) {
|
|
|
|
let {id, name} = cmd.parameters;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
throw new UnsupportedOperationError();
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
|
|
|
return this.listener.getElementProperty(id, name);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
/**
|
|
|
|
* Get the text of an element, if any. Includes the text of all child
|
|
|
|
* elements.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be inspected.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getElementText = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
// for chrome, we look at text nodes, and any node with a "label" field
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2015-03-20 00:12:58 +03:00
|
|
|
let lines = [];
|
|
|
|
this.getVisibleText(el, lines);
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = lines.join("\n");
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getElementText(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the tag name of the element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be inspected.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = el.tagName.toLowerCase();
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getElementTagName(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if element is displayed.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be inspected.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-03-03 16:58:13 +03:00
|
|
|
resp.body.value = yield interaction.isElementDisplayed(
|
|
|
|
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.isElementDisplayed(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the property of the computed style of an element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be checked.
|
|
|
|
* @param {string} propertyName
|
|
|
|
* CSS rule that is being requested.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let {id, propertyName: prop} = cmd.parameters;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2015-03-20 00:12:58 +03:00
|
|
|
let sty = win.document.defaultView.getComputedStyle(el, null);
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = sty.getPropertyValue(prop);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getElementValueOfCssProperty(id, prop);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if element is enabled.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be checked.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
// Selenium atom doesn't quite work here
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-03-03 16:58:13 +03:00
|
|
|
resp.body.value = yield interaction.isElementEnabled(
|
|
|
|
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.isElementEnabled(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if element is selected.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be checked.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
// Selenium atom doesn't quite work here
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-03-03 16:58:13 +03:00
|
|
|
resp.body.value = yield interaction.isElementSelected(
|
|
|
|
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.isElementSelected(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2015-03-20 00:12:58 +03:00
|
|
|
let rect = el.getBoundingClientRect();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body = {
|
2015-03-20 00:12:58 +03:00
|
|
|
x: rect.x + win.pageXOffset,
|
|
|
|
y: rect.y + win.pageYOffset,
|
|
|
|
width: rect.width,
|
|
|
|
height: rect.height
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body = yield this.listener.getElementRect(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send key presses to element after focusing on it.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be checked.
|
|
|
|
* @param {string} value
|
|
|
|
* Value to send to the element.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let {id, value} = cmd.parameters;
|
|
|
|
|
2015-04-02 17:16:00 +03:00
|
|
|
if (!value) {
|
2015-04-17 20:43:05 +03:00
|
|
|
throw new InvalidArgumentError(`Expected character sequence: ${value}`);
|
2015-04-02 17:16:00 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2016-03-03 16:58:13 +03:00
|
|
|
yield interaction.sendKeysToElement(
|
|
|
|
el, value, true, this.sessionCapabilities.raisesAccessibilityExceptions);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
2015-04-02 17:16:00 +03:00
|
|
|
let err;
|
|
|
|
let listener = function(msg) {
|
|
|
|
this.mm.removeMessageListener("Marionette:setElementValue", listener);
|
|
|
|
|
|
|
|
let val = msg.data.value;
|
|
|
|
let el = msg.objects.element;
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
|
|
|
|
if (el.type == "file") {
|
|
|
|
Cu.importGlobalProperties(["File"]);
|
|
|
|
let fs = Array.prototype.slice.call(el.files);
|
|
|
|
let file;
|
|
|
|
try {
|
|
|
|
file = new File(val);
|
|
|
|
} catch (e) {
|
2015-04-17 20:43:05 +03:00
|
|
|
err = new InvalidArgumentError(`File not found: ${val}`);
|
2015-04-02 17:16:00 +03:00
|
|
|
}
|
|
|
|
fs.push(file);
|
|
|
|
el.mozSetFileArray(fs);
|
|
|
|
} else {
|
|
|
|
el.value = val;
|
|
|
|
}
|
|
|
|
}.bind(this);
|
|
|
|
|
|
|
|
this.mm.addMessageListener("Marionette:setElementValue", listener);
|
2015-03-20 00:12:58 +03:00
|
|
|
yield this.listener.sendKeysToElement({id: id, value: value});
|
2015-04-02 17:16:00 +03:00
|
|
|
this.mm.removeMessageListener("Marionette:setElementValue", listener);
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Sets the test name. The test name is used for logging purposes. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.setTestName = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let val = cmd.parameters.value;
|
|
|
|
this.testName = val;
|
|
|
|
yield this.listener.setTestName({value: val});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear the text of an element.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference ID to the element that will be cleared.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.clearElement = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let id = cmd.parameters.id;
|
|
|
|
|
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
// the selenium atom doesn't work here
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-20 18:49:19 +03:00
|
|
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
2015-03-20 00:12:58 +03:00
|
|
|
if (el.nodeName == "textbox") {
|
|
|
|
el.value = "";
|
|
|
|
} else if (el.nodeName == "checkbox") {
|
|
|
|
el.checked = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
2015-08-21 17:37:04 +03:00
|
|
|
yield this.listener.clearElement(id);
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-28 23:43:54 +03:00
|
|
|
/**
|
|
|
|
* Switch to shadow root of the given host element.
|
|
|
|
*
|
|
|
|
* @param {string} id element id.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
|
2015-08-28 23:43:54 +03:00
|
|
|
let id;
|
|
|
|
if (cmd.parameters) { id = cmd.parameters.id; }
|
|
|
|
yield this.listener.switchToShadowRoot(id);
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
/** Add a cookie to the document. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.addCookie = function*(cmd, resp) {
|
2015-11-13 16:35:22 +03:00
|
|
|
let cb = msg => {
|
|
|
|
this.mm.removeMessageListener("Marionette:addCookie", cb);
|
|
|
|
let cookie = msg.json;
|
|
|
|
Services.cookies.add(
|
|
|
|
cookie.domain,
|
|
|
|
cookie.path,
|
|
|
|
cookie.name,
|
|
|
|
cookie.value,
|
|
|
|
cookie.secure,
|
|
|
|
cookie.httpOnly,
|
|
|
|
cookie.session,
|
2016-05-25 06:54:21 +03:00
|
|
|
cookie.expiry,
|
|
|
|
{}); // originAttributes
|
2015-11-13 16:35:22 +03:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
this.mm.addMessageListener("Marionette:addCookie", cb);
|
|
|
|
yield this.listener.addCookie(cmd.parameters.cookie);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all the cookies for the current domain.
|
|
|
|
*
|
|
|
|
* This is the equivalent of calling {@code document.cookie} and parsing
|
|
|
|
* the result.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getCookies = function*(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body = yield this.listener.getCookies();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Delete all cookies that are visible to a document. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.deleteAllCookies = function*(cmd, resp) {
|
2015-11-13 16:35:22 +03:00
|
|
|
let cb = msg => {
|
|
|
|
let cookie = msg.json;
|
|
|
|
cookieManager.remove(
|
|
|
|
cookie.host,
|
|
|
|
cookie.name,
|
|
|
|
cookie.path,
|
2016-04-10 07:46:07 +03:00
|
|
|
false,
|
|
|
|
cookie.originAttributes);
|
2015-11-13 16:35:22 +03:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
this.mm.addMessageListener("Marionette:deleteCookie", cb);
|
2015-03-20 00:12:58 +03:00
|
|
|
yield this.listener.deleteAllCookies();
|
2015-11-13 16:35:22 +03:00
|
|
|
this.mm.removeMessageListener("Marionette:deleteCookie", cb);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Delete a cookie by name. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.deleteCookie = function*(cmd, resp) {
|
2015-11-13 16:35:22 +03:00
|
|
|
let cb = msg => {
|
|
|
|
this.mm.removeMessageListener("Marionette:deleteCookie", cb);
|
|
|
|
let cookie = msg.json;
|
|
|
|
cookieManager.remove(
|
|
|
|
cookie.host,
|
|
|
|
cookie.name,
|
|
|
|
cookie.path,
|
2016-04-10 07:46:07 +03:00
|
|
|
false,
|
|
|
|
cookie.originAttributes);
|
2015-11-13 16:35:22 +03:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
this.mm.addMessageListener("Marionette:deleteCookie", cb);
|
|
|
|
yield this.listener.deleteCookie(cmd.parameters.name);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close the current window, ending the session if it's the last
|
|
|
|
* window currently open.
|
|
|
|
*
|
|
|
|
* On B2G this method is a noop and will return immediately.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.close = function(cmd, resp) {
|
|
|
|
// can't close windows on B2G
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName == "B2G") {
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let nwins = 0;
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
let win = winEn.getNext();
|
|
|
|
|
|
|
|
// count both windows and tabs
|
2015-03-23 23:43:18 +03:00
|
|
|
if (win.gBrowser) {
|
2015-03-20 00:12:58 +03:00
|
|
|
nwins += win.gBrowser.browsers.length;
|
2015-03-23 23:43:18 +03:00
|
|
|
} else {
|
2015-03-20 00:12:58 +03:00
|
|
|
nwins++;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// if there is only 1 window left, delete the session
|
|
|
|
if (nwins == 1) {
|
|
|
|
this.sessionTearDown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.mm != globalMessageManager) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.curBrowser.tab) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curBrowser.closeTab();
|
2015-03-23 23:43:18 +03:00
|
|
|
} else {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.getCurrentWindow().close();
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
} catch (e) {
|
|
|
|
throw new UnknownError(`Could not close window: ${e.message}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close the currently selected chrome window, ending the session if it's the last
|
|
|
|
* window currently open.
|
|
|
|
*
|
|
|
|
* On B2G this method is a noop and will return immediately.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.closeChromeWindow = function(cmd, resp) {
|
|
|
|
// can't close windows on B2G
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName == "B2G") {
|
2015-03-20 00:12:58 +03:00
|
|
|
return;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
// Get the total number of windows
|
|
|
|
let nwins = 0;
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
nwins++;
|
|
|
|
winEn.getNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there is only 1 window left, delete the session
|
|
|
|
if (nwins == 1) {
|
|
|
|
this.sessionTearDown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
|
|
|
|
this.getCurrentWindow().close();
|
|
|
|
} catch (e) {
|
|
|
|
throw new UnknownError(`Could not close window: ${e.message}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deletes the session.
|
|
|
|
*
|
|
|
|
* If it is a desktop environment, it will close all listeners.
|
|
|
|
*
|
|
|
|
* If it is a B2G environment, it will make the main content listener
|
|
|
|
* sleep, and close all other listeners. The main content listener
|
|
|
|
* persists after disconnect (it's the homescreen), and can safely
|
|
|
|
* be reused.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.sessionTearDown = function(cmd, resp) {
|
2015-04-24 15:55:52 +03:00
|
|
|
if (this.curBrowser !== null) {
|
2015-03-20 00:12:58 +03:00
|
|
|
if (this.appName == "B2G") {
|
|
|
|
globalMessageManager.broadcastAsyncMessage(
|
|
|
|
"Marionette:sleepSession" + this.curBrowser.mainContentId, {});
|
|
|
|
this.curBrowser.knownFrames.splice(
|
|
|
|
this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1);
|
|
|
|
} else {
|
|
|
|
// don't set this pref for B2G since the framescript can be safely reused
|
2016-01-19 01:05:30 +03:00
|
|
|
Preferences.set(CONTENT_LISTENER_PREF, false);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// delete session in each frame in each browser
|
|
|
|
for (let win in this.browsers) {
|
|
|
|
let browser = this.browsers[win];
|
|
|
|
for (let i in browser.knownFrames) {
|
|
|
|
globalMessageManager.broadcastAsyncMessage(
|
|
|
|
"Marionette:deleteSession" + browser.knownFrames[i], {});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-23 17:48:11 +03:00
|
|
|
let winEn = Services.wm.getEnumerator(null);
|
2015-03-20 00:12:58 +03:00
|
|
|
while (winEn.hasMoreElements()) {
|
|
|
|
winEn.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.curBrowser.frameManager.removeMessageManagerListeners(
|
|
|
|
globalMessageManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.switchToGlobalMessageManager();
|
|
|
|
|
|
|
|
// reset frame to the top-most frame
|
|
|
|
this.curFrame = null;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.mainFrame) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.mainFrame.focus();
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
this.sessionId = null;
|
|
|
|
|
|
|
|
if (this.observing !== null) {
|
|
|
|
for (let topic in this.observing) {
|
|
|
|
Services.obs.removeObserver(this.observing[topic], topic);
|
|
|
|
}
|
|
|
|
this.observing = null;
|
|
|
|
}
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.sandboxes.clear();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processes the "deleteSession" request from the client by tearing down
|
|
|
|
* the session and responding "ok".
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.deleteSession = function(cmd, resp) {
|
|
|
|
this.sessionTearDown();
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Returns the current status of the Application Cache. */
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.getAppCacheStatus = function*(cmd, resp) {
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = yield this.listener.getAppCacheStatus();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
2016-02-29 21:52:30 +03:00
|
|
|
/**
|
|
|
|
* Import script to the JS evaluation runtime.
|
|
|
|
*
|
|
|
|
* Imported scripts are exposed in the contexts of all subsequent
|
|
|
|
* calls to {@code executeScript}, {@code executeAsyncScript}, and
|
|
|
|
* {@code executeJSScript} by prepending them to the evaluated script.
|
|
|
|
*
|
|
|
|
* Scripts can be cleared with the {@code clearImportedScripts} command.
|
|
|
|
*
|
|
|
|
* @param {string} script
|
|
|
|
* Script to include. If the script is byte-by-byte equal to an
|
|
|
|
* existing imported script, it is not imported.
|
|
|
|
*/
|
2016-02-06 21:19:02 +03:00
|
|
|
GeckoDriver.prototype.importScript = function*(cmd, resp) {
|
2015-03-20 00:12:58 +03:00
|
|
|
let script = cmd.parameters.script;
|
2016-02-29 21:52:30 +03:00
|
|
|
this.importedScripts.for(this.context).add(script);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
2016-02-29 21:52:30 +03:00
|
|
|
/**
|
|
|
|
* Clear all scripts that are imported into the JS evaluation runtime.
|
|
|
|
*
|
|
|
|
* Scripts can be imported using the {@code importScript} command.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.clearImportedScripts = function*(cmd, resp) {
|
|
|
|
this.importedScripts.for(this.context).clear();
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes a screenshot of a web element, current frame, or viewport.
|
|
|
|
*
|
|
|
|
* The screen capture is returned as a lossless PNG image encoded as
|
|
|
|
* a base 64 string.
|
|
|
|
*
|
|
|
|
* If called in the content context, the <code>id</code> argument is not null
|
|
|
|
* and refers to a present and visible web element's ID, the capture area
|
|
|
|
* will be limited to the bounding box of that element. Otherwise, the
|
|
|
|
* capture area will be the bounding box of the current frame.
|
|
|
|
*
|
|
|
|
* If called in the chrome context, the screenshot will always represent the
|
|
|
|
* entire viewport.
|
|
|
|
*
|
|
|
|
* @param {string} id
|
|
|
|
* Reference to a web element.
|
|
|
|
* @param {string} highlights
|
|
|
|
* List of web elements to highlight.
|
2016-04-18 04:37:14 +03:00
|
|
|
* @param {boolean} hash
|
|
|
|
* True if the user requests a hash of the image data.
|
2015-03-20 00:12:58 +03:00
|
|
|
*
|
|
|
|
* @return {string}
|
2016-04-18 04:37:14 +03:00
|
|
|
* If {@code hash} is false, PNG image encoded as base64 encoded string. If
|
|
|
|
* 'hash' is True, hex digest of the SHA-256 hash of the base64 encoded
|
|
|
|
* string.
|
2015-03-20 00:12:58 +03:00
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.takeScreenshot = function(cmd, resp) {
|
2016-04-18 04:37:14 +03:00
|
|
|
let {id, highlights, full, hash} = cmd.parameters;
|
2015-10-13 18:52:26 +03:00
|
|
|
highlights = highlights || [];
|
2015-10-09 14:02:42 +03:00
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
switch (this.context) {
|
|
|
|
case Context.CHROME:
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
|
|
|
let doc;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName == "B2G") {
|
2015-03-20 00:12:58 +03:00
|
|
|
doc = win.document.body;
|
2015-03-23 23:43:18 +03:00
|
|
|
} else {
|
2016-01-27 19:43:33 +03:00
|
|
|
doc = win.document.documentElement;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
let docRect = doc.getBoundingClientRect();
|
|
|
|
let width = docRect.width;
|
|
|
|
let height = docRect.height;
|
|
|
|
|
|
|
|
// Convert width and height from CSS pixels (potentially fractional)
|
|
|
|
// to device pixels (integer).
|
|
|
|
let scale = win.devicePixelRatio;
|
|
|
|
canvas.setAttribute("width", Math.round(width * scale));
|
|
|
|
canvas.setAttribute("height", Math.round(height * scale));
|
|
|
|
|
|
|
|
let context = canvas.getContext("2d");
|
|
|
|
let flags;
|
|
|
|
if (this.appName == "B2G") {
|
|
|
|
flags =
|
|
|
|
context.DRAWWINDOW_DRAW_CARET |
|
|
|
|
context.DRAWWINDOW_DRAW_VIEW |
|
|
|
|
context.DRAWWINDOW_USE_WIDGET_LAYERS;
|
|
|
|
} else {
|
|
|
|
// Bug 1075168: CanvasRenderingContext2D image is distorted
|
|
|
|
// when using certain flags in chrome context.
|
|
|
|
flags =
|
|
|
|
context.DRAWWINDOW_DRAW_VIEW |
|
|
|
|
context.DRAWWINDOW_USE_WIDGET_LAYERS;
|
|
|
|
}
|
|
|
|
context.scale(scale, scale);
|
|
|
|
context.drawWindow(win, 0, 0, width, height, "rgb(255,255,255)", flags);
|
|
|
|
let dataUrl = canvas.toDataURL("image/png", "");
|
|
|
|
let data = dataUrl.substring(dataUrl.indexOf(",") + 1);
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = data;
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Context.CONTENT:
|
2016-04-18 04:37:14 +03:00
|
|
|
if (hash) {
|
|
|
|
return this.listener.getScreenshotHash(id, full, highlights);
|
|
|
|
} else {
|
|
|
|
return this.listener.takeScreenshot(id, full, highlights);
|
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current browser orientation.
|
|
|
|
*
|
|
|
|
* Will return one of the valid primary orientation values
|
|
|
|
* portrait-primary, landscape-primary, portrait-secondary, or
|
|
|
|
* landscape-secondary.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getScreenOrientation = function(cmd, resp) {
|
2016-03-17 17:54:48 +03:00
|
|
|
if (this.appName == "Firefox") {
|
|
|
|
throw new UnsupportedOperationError();
|
|
|
|
}
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = this.getCurrentWindow().screen.mozOrientation;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the current browser orientation.
|
|
|
|
*
|
|
|
|
* The supplied orientation should be given as one of the valid
|
|
|
|
* orientation values. If the orientation is unknown, an error will
|
|
|
|
* be raised.
|
|
|
|
*
|
|
|
|
* Valid orientations are "portrait" and "landscape", which fall
|
|
|
|
* back to "portrait-primary" and "landscape-primary" respectively,
|
|
|
|
* and "portrait-secondary" as well as "landscape-secondary".
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setScreenOrientation = function(cmd, resp) {
|
2016-03-17 17:54:48 +03:00
|
|
|
if (this.appName == "Firefox") {
|
|
|
|
throw new UnsupportedOperationError();
|
|
|
|
}
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
const ors = [
|
|
|
|
"portrait", "landscape",
|
|
|
|
"portrait-primary", "landscape-primary",
|
|
|
|
"portrait-secondary", "landscape-secondary"
|
|
|
|
];
|
|
|
|
|
|
|
|
let or = String(cmd.parameters.orientation);
|
|
|
|
let mozOr = or.toLowerCase();
|
2015-03-23 23:43:18 +03:00
|
|
|
if (ors.indexOf(mozOr) < 0) {
|
2016-05-10 16:31:04 +03:00
|
|
|
throw new InvalidArgumentError(`Unknown screen orientation: ${or}`);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let win = this.getCurrentWindow();
|
2015-03-23 23:43:18 +03:00
|
|
|
if (!win.screen.mozLockOrientation(mozOr)) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new WebDriverError(`Unable to set screen orientation: ${or}`);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the size of the browser window currently in focus.
|
|
|
|
*
|
|
|
|
* Will return the current browser window size in pixels. Refers to
|
|
|
|
* window outerWidth and outerHeight values, which include scroll bars,
|
|
|
|
* title bars, etc.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getWindowSize = function(cmd, resp) {
|
|
|
|
let win = this.getCurrentWindow();
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.width = win.outerWidth;
|
|
|
|
resp.body.height = win.outerHeight;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the size of the browser window currently in focus.
|
|
|
|
*
|
|
|
|
* Not supported on B2G. The supplied width and height values refer to
|
|
|
|
* the window outerWidth and outerHeight values, which include scroll
|
|
|
|
* bars, title bars, etc.
|
|
|
|
*
|
|
|
|
* An error will be returned if the requested window size would result
|
|
|
|
* in the window being in the maximized state.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.setWindowSize = function(cmd, resp) {
|
2016-03-17 17:57:46 +03:00
|
|
|
if (this.appName != "Firefox") {
|
|
|
|
throw new UnsupportedOperationError();
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let width = parseInt(cmd.parameters.width);
|
|
|
|
let height = parseInt(cmd.parameters.height);
|
|
|
|
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-18 13:35:20 +03:00
|
|
|
if (width >= win.screen.availWidth || height >= win.screen.availHeight) {
|
|
|
|
throw new UnsupportedOperationError("Requested size exceeds screen size")
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
win.resizeTo(width, height);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maximizes the user agent window as if the user pressed the maximise
|
|
|
|
* button.
|
|
|
|
*
|
|
|
|
* Not Supported on B2G or Fennec.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.maximizeWindow = function(cmd, resp) {
|
2015-03-23 23:43:18 +03:00
|
|
|
if (this.appName != "Firefox") {
|
2016-03-17 17:57:46 +03:00
|
|
|
throw new UnsupportedOperationError();
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let win = this.getCurrentWindow();
|
2016-05-06 23:15:13 +03:00
|
|
|
win.maximize()
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dismisses a currently displayed tab modal, or returns no such alert if
|
|
|
|
* no modal is displayed.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.dismissDialog = function(cmd, resp) {
|
2016-05-23 13:16:04 +03:00
|
|
|
this._checkIfAlertIsPresent();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let {button0, button1} = this.dialog.ui;
|
|
|
|
(button1 ? button1 : button0).click();
|
|
|
|
this.dialog = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Accepts a currently displayed tab modal, or returns no such alert if
|
|
|
|
* no modal is displayed.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.acceptDialog = function(cmd, resp) {
|
2016-05-23 13:16:04 +03:00
|
|
|
this._checkIfAlertIsPresent();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let {button0} = this.dialog.ui;
|
|
|
|
button0.click();
|
|
|
|
this.dialog = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the message shown in a currently displayed modal, or returns a no such
|
|
|
|
* alert error if no modal is currently displayed.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.getTextFromDialog = function(cmd, resp) {
|
2016-05-23 13:16:04 +03:00
|
|
|
this._checkIfAlertIsPresent();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let {infoBody} = this.dialog.ui;
|
Bug 1153822: Adjust Marionette responses to match WebDriver protocol
Introduce protocol version levels in the Marionette server.
On establishing a connection to a local end, the remote will return a
`marionetteProtocol` field indicating which level it speaks.
The protocol level can be used by local ends to either fall into
compatibility mode or warn the user that the local end is incompatible
with the remote.
The protocol is currently also more expressive than it needs to be and
this expressiveness has previously resulted in subtle inconsistencies
in the fields returned.
This patch reduces the amount of superfluous fields, reducing the
amount of data sent. Aligning the protocol closer to the WebDriver
specification's expectations will also reduce the amount of
post-processing required in the httpd.
Previous to this patch, this is a value response:
{"from":"0","value":null,"status":0,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}"}
And this for ok responses:
{"from":"0","ok":true}
And this for errors:
{"from":"0","status":21,"sessionId":"{6b6d68d2-4ac9-4308-9f07-d2e72519c407}","error":{"message":"Error loading page, timed out (onDOMContentLoaded)","stacktrace":null,"status":21}}
This patch drops the `from` and `sessionId` fields, and the `status`
field from non-error responses. It also drops the `ok` field in non-value
responses and flattens the error response to a simple dictionary with the
`error` (previously `status`), `message`, and `stacktrace` properties,
which are now all required.
r=jgriffin
--HG--
extra : commitid : FbEkv70rxl9
extra : rebase_source : 3116110a0d197289cc95eba8748be0a33566c5a5
2015-05-21 13:26:58 +03:00
|
|
|
resp.body.value = infoBody.textContent;
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends keys to the input field of a currently displayed modal, or
|
|
|
|
* returns a no such alert error if no modal is currently displayed. If
|
|
|
|
* a tab modal is currently displayed but has no means for text input,
|
|
|
|
* an element not visible error is returned.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.sendKeysToDialog = function(cmd, resp) {
|
2016-05-23 13:16:04 +03:00
|
|
|
this._checkIfAlertIsPresent();
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
// see toolkit/components/prompts/content/commonDialog.js
|
|
|
|
let {loginContainer, loginTextbox} = this.dialog.ui;
|
2015-03-23 23:43:18 +03:00
|
|
|
if (loginContainer.hidden) {
|
2015-03-20 00:12:58 +03:00
|
|
|
throw new ElementNotVisibleError("This prompt does not accept text input");
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
|
|
|
|
let win = this.dialog.window ? this.dialog.window : this.getCurrentWindow();
|
2016-02-03 21:56:02 +03:00
|
|
|
event.sendKeysToElement(
|
2016-02-11 19:05:41 +03:00
|
|
|
cmd.parameters.value,
|
2016-02-03 21:56:02 +03:00
|
|
|
loginTextbox,
|
|
|
|
{ignoreVisibility: true},
|
|
|
|
win);
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
|
|
|
|
2016-05-23 13:16:04 +03:00
|
|
|
GeckoDriver.prototype._checkIfAlertIsPresent = function() {
|
|
|
|
if (!this.dialog || !this.dialog.ui) {
|
|
|
|
throw new NoAlertOpenError(
|
|
|
|
"No tab modal was open when attempting to get the dialog text");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-26 19:12:01 +03:00
|
|
|
/**
|
|
|
|
* Quits Firefox with the provided flags and tears down the current
|
|
|
|
* session.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.quitApplication = function(cmd, resp) {
|
|
|
|
if (this.appName != "Firefox") {
|
|
|
|
throw new WebDriverError("In app initiated quit only supported in Firefox");
|
|
|
|
}
|
|
|
|
|
|
|
|
let flags = Ci.nsIAppStartup.eAttemptQuit;
|
|
|
|
for (let k of cmd.parameters.flags) {
|
|
|
|
flags |= Ci.nsIAppStartup[k];
|
|
|
|
}
|
|
|
|
|
|
|
|
this.stopSignal_();
|
|
|
|
resp.send();
|
|
|
|
|
|
|
|
this.sessionTearDown();
|
|
|
|
Services.startup.quit(flags);
|
|
|
|
};
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
/**
|
|
|
|
* Helper function to convert an outerWindowID into a UID that Marionette
|
|
|
|
* tracks.
|
|
|
|
*/
|
|
|
|
GeckoDriver.prototype.generateFrameId = function(id) {
|
|
|
|
let uid = id + (this.appName == "B2G" ? "-b2g" : "");
|
|
|
|
return uid;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Receives all messages from content messageManager. */
|
|
|
|
GeckoDriver.prototype.receiveMessage = function(message) {
|
|
|
|
switch (message.name) {
|
2015-10-30 09:29:14 +03:00
|
|
|
case "Marionette:ok":
|
|
|
|
case "Marionette:done":
|
|
|
|
case "Marionette:error":
|
|
|
|
// check if we need to remove the mozbrowserclose listener
|
|
|
|
if (this.mozBrowserClose !== null) {
|
|
|
|
let win = this.getCurrentWindow();
|
|
|
|
win.removeEventListener("mozbrowserclose", this.mozBrowserClose, true);
|
|
|
|
this.mozBrowserClose = null;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
case "Marionette:log":
|
|
|
|
// log server-side messages
|
|
|
|
logger.info(message.json.message);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Marionette:shareData":
|
|
|
|
// log messages from tests
|
2015-03-23 23:43:18 +03:00
|
|
|
if (message.json.log) {
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
this.marionetteLog.addAll(message.json.log);
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case "Marionette:switchToModalOrigin":
|
|
|
|
this.curBrowser.frameManager.switchToModalOrigin(message);
|
|
|
|
this.mm = this.curBrowser.frameManager
|
|
|
|
.currentRemoteFrame.messageManager.get();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Marionette:switchedToFrame":
|
|
|
|
if (message.json.restorePrevious) {
|
|
|
|
this.currentFrameElement = this.previousFrameElement;
|
|
|
|
} else {
|
|
|
|
// we don't arbitrarily save previousFrameElement, since
|
|
|
|
// we allow frame switching after modals appear, which would
|
|
|
|
// override this value and we'd lose our reference
|
2015-03-23 23:43:18 +03:00
|
|
|
if (message.json.storePrevious) {
|
2015-03-20 00:12:58 +03:00
|
|
|
this.previousFrameElement = this.currentFrameElement;
|
2015-03-23 23:43:18 +03:00
|
|
|
}
|
2015-03-20 00:12:58 +03:00
|
|
|
this.currentFrameElement = message.json.frameValue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Marionette:getVisibleCookies":
|
2015-11-13 16:35:22 +03:00
|
|
|
let [currentPath, host] = message.json;
|
2015-03-20 00:12:58 +03:00
|
|
|
let isForCurrentPath = path => currentPath.indexOf(path) != -1;
|
|
|
|
let results = [];
|
|
|
|
|
2016-05-25 06:54:21 +03:00
|
|
|
let en = cookieManager.getCookiesFromHost(host, {});
|
2015-03-20 00:12:58 +03:00
|
|
|
while (en.hasMoreElements()) {
|
2015-07-16 01:51:51 +03:00
|
|
|
let cookie = en.getNext().QueryInterface(Ci.nsICookie2);
|
2015-03-20 00:12:58 +03:00
|
|
|
// take the hostname and progressively shorten
|
|
|
|
let hostname = host;
|
|
|
|
do {
|
|
|
|
if ((cookie.host == "." + hostname || cookie.host == hostname) &&
|
|
|
|
isForCurrentPath(cookie.path)) {
|
|
|
|
results.push({
|
|
|
|
"name": cookie.name,
|
|
|
|
"value": cookie.value,
|
|
|
|
"path": cookie.path,
|
|
|
|
"host": cookie.host,
|
|
|
|
"secure": cookie.isSecure,
|
2015-07-16 01:51:51 +03:00
|
|
|
"expiry": cookie.expires,
|
2016-05-05 10:12:00 +03:00
|
|
|
"httpOnly": cookie.isHttpOnly,
|
|
|
|
"originAttributes": cookie.originAttributes
|
2015-03-20 00:12:58 +03:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
hostname = hostname.replace(/^.*?\./, "");
|
|
|
|
} while (hostname.indexOf(".") != -1);
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
|
2015-05-19 02:36:15 +03:00
|
|
|
case "Marionette:getFiles":
|
|
|
|
// Generates file objects to send back to the content script
|
|
|
|
// for handling file uploads.
|
|
|
|
let val = message.json.value;
|
|
|
|
let command_id = message.json.command_id;
|
|
|
|
Cu.importGlobalProperties(["File"]);
|
|
|
|
try {
|
|
|
|
let file = new File(val);
|
|
|
|
this.sendAsync("receiveFiles",
|
|
|
|
{file: file, command_id: command_id});
|
|
|
|
} catch (e) {
|
|
|
|
let err = `File not found: ${val}`;
|
|
|
|
this.sendAsync("receiveFiles",
|
|
|
|
{error: err, command_id: command_id});
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
case "Marionette:emitTouchEvent":
|
|
|
|
globalMessageManager.broadcastAsyncMessage(
|
|
|
|
"MarionetteMainListener:emitTouchEvent", message.json);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "Marionette:register":
|
|
|
|
let wid = message.json.value;
|
|
|
|
let be = message.target;
|
|
|
|
let rv = this.registerBrowser(wid, be);
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
case "Marionette:listenersAttached":
|
|
|
|
if (message.json.listenerId === this.curBrowser.curFrameId) {
|
|
|
|
// If remoteness gets updated we need to call newSession. In the case
|
|
|
|
// of desktop this just sets up a small amount of state that doesn't
|
|
|
|
// change over the course of a session.
|
2016-03-04 21:02:56 +03:00
|
|
|
this.sendAsync("newSession", this.sessionCapabilities);
|
2015-03-20 00:12:58 +03:00
|
|
|
this.curBrowser.flushPendingCommands();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.responseCompleted = function () {
|
|
|
|
if (this.curBrowser !== null) {
|
|
|
|
this.curBrowser.pendingCommands = [];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GeckoDriver.prototype.commands = {
|
|
|
|
"getMarionetteID": GeckoDriver.prototype.getMarionetteID,
|
|
|
|
"sayHello": GeckoDriver.prototype.sayHello,
|
|
|
|
"newSession": GeckoDriver.prototype.newSession,
|
|
|
|
"getSessionCapabilities": GeckoDriver.prototype.getSessionCapabilities,
|
|
|
|
"log": GeckoDriver.prototype.log,
|
|
|
|
"getLogs": GeckoDriver.prototype.getLogs,
|
|
|
|
"setContext": GeckoDriver.prototype.setContext,
|
|
|
|
"getContext": GeckoDriver.prototype.getContext,
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
"executeScript": GeckoDriver.prototype.executeScript,
|
2015-03-20 00:12:58 +03:00
|
|
|
"setScriptTimeout": GeckoDriver.prototype.setScriptTimeout,
|
|
|
|
"timeouts": GeckoDriver.prototype.timeouts,
|
|
|
|
"singleTap": GeckoDriver.prototype.singleTap,
|
|
|
|
"actionChain": GeckoDriver.prototype.actionChain,
|
|
|
|
"multiAction": GeckoDriver.prototype.multiAction,
|
Bug 1123506 - Evaluate scripts in content with lasting side-effects; r=automatedtester
In order to achieve WebDriver parity, Marionette needs the ability to
evaluate scripts in content space with lasting side-effects. This means
that state modifications should affect behaviour and state of the browsing
context, and such transgress the boundaries of the sandbox.
This patch brings a new script evaluation module that is shared between
code in chrome- and content space. This brings the number of unique
script evaluation implementations in Marionette down from six to one.
evaluate.sandbox provides the main entry-point for execution. It is
compatible with existing Marionette uses of Execute Script and Execute
Async Script commands in Mozilla clients, but also provides a new stateful
sandbox for evaluation that should have lasting side-effects.
It is not expected that Mozilla clients, such as testing/marionette/client
and the Node.js client in Gaia, should have to change as a consequence
of this change.
A substantial change to the script's runtime environment is that many
globals that previously existed are now only exposed whenever needed.
This means for example that Simple Test harness functionality (waitFor,
ok, isnot, is, &c.) is only available when using a sandbox augmented
with a Simple Test harness adapter.
Conversely, this patch does not expose marionetteScriptFinished as a
callback to asynchronous scripts for sandboxes which sandboxName parameter
is undefined, because this is what determines if the script should be
evaluated under WebDriver conformance constraints. In all other cases
where sandboxName _is_ defined, the traditional marionetteScriptFinished
et al. runtime environment is preserved.
MozReview-Commit-ID: 8FZ6rNVImuC
2016-02-26 17:36:39 +03:00
|
|
|
"executeAsyncScript": GeckoDriver.prototype.executeAsyncScript,
|
2015-03-20 00:12:58 +03:00
|
|
|
"executeJSScript": GeckoDriver.prototype.executeJSScript,
|
|
|
|
"setSearchTimeout": GeckoDriver.prototype.setSearchTimeout,
|
|
|
|
"findElement": GeckoDriver.prototype.findElement,
|
|
|
|
"findElements": GeckoDriver.prototype.findElements,
|
|
|
|
"clickElement": GeckoDriver.prototype.clickElement,
|
|
|
|
"getElementAttribute": GeckoDriver.prototype.getElementAttribute,
|
2016-05-13 16:42:05 +03:00
|
|
|
"getElementProperty": GeckoDriver.prototype.getElementProperty,
|
2015-03-20 00:12:58 +03:00
|
|
|
"getElementText": GeckoDriver.prototype.getElementText,
|
|
|
|
"getElementTagName": GeckoDriver.prototype.getElementTagName,
|
|
|
|
"isElementDisplayed": GeckoDriver.prototype.isElementDisplayed,
|
|
|
|
"getElementValueOfCssProperty": GeckoDriver.prototype.getElementValueOfCssProperty,
|
|
|
|
"getElementRect": GeckoDriver.prototype.getElementRect,
|
|
|
|
"isElementEnabled": GeckoDriver.prototype.isElementEnabled,
|
|
|
|
"isElementSelected": GeckoDriver.prototype.isElementSelected,
|
|
|
|
"sendKeysToElement": GeckoDriver.prototype.sendKeysToElement,
|
|
|
|
"clearElement": GeckoDriver.prototype.clearElement,
|
|
|
|
"getTitle": GeckoDriver.prototype.getTitle,
|
|
|
|
"getWindowType": GeckoDriver.prototype.getWindowType,
|
|
|
|
"getPageSource": GeckoDriver.prototype.getPageSource,
|
|
|
|
"get": GeckoDriver.prototype.get,
|
|
|
|
"goUrl": GeckoDriver.prototype.get, // deprecated
|
|
|
|
"getCurrentUrl": GeckoDriver.prototype.getCurrentUrl,
|
|
|
|
"getUrl": GeckoDriver.prototype.getCurrentUrl, // deprecated
|
|
|
|
"goBack": GeckoDriver.prototype.goBack,
|
|
|
|
"goForward": GeckoDriver.prototype.goForward,
|
|
|
|
"refresh": GeckoDriver.prototype.refresh,
|
|
|
|
"getWindowHandle": GeckoDriver.prototype.getWindowHandle,
|
|
|
|
"getCurrentWindowHandle": GeckoDriver.prototype.getWindowHandle, // Selenium 2 compat
|
|
|
|
"getChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
|
|
|
|
"getCurrentChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
|
|
|
|
"getWindow": GeckoDriver.prototype.getWindowHandle, // deprecated
|
|
|
|
"getWindowHandles": GeckoDriver.prototype.getWindowHandles,
|
|
|
|
"getChromeWindowHandles": GeckoDriver.prototype.getChromeWindowHandles,
|
|
|
|
"getCurrentWindowHandles": GeckoDriver.prototype.getWindowHandles, // Selenium 2 compat
|
|
|
|
"getWindows": GeckoDriver.prototype.getWindowHandles, // deprecated
|
|
|
|
"getWindowPosition": GeckoDriver.prototype.getWindowPosition,
|
|
|
|
"setWindowPosition": GeckoDriver.prototype.setWindowPosition,
|
|
|
|
"getActiveFrame": GeckoDriver.prototype.getActiveFrame,
|
|
|
|
"switchToFrame": GeckoDriver.prototype.switchToFrame,
|
2015-10-19 23:39:48 +03:00
|
|
|
"switchToParentFrame": GeckoDriver.prototype.switchToParentFrame,
|
2015-03-20 00:12:58 +03:00
|
|
|
"switchToWindow": GeckoDriver.prototype.switchToWindow,
|
2015-08-28 23:43:54 +03:00
|
|
|
"switchToShadowRoot": GeckoDriver.prototype.switchToShadowRoot,
|
2015-03-20 00:12:58 +03:00
|
|
|
"deleteSession": GeckoDriver.prototype.deleteSession,
|
|
|
|
"importScript": GeckoDriver.prototype.importScript,
|
|
|
|
"clearImportedScripts": GeckoDriver.prototype.clearImportedScripts,
|
|
|
|
"getAppCacheStatus": GeckoDriver.prototype.getAppCacheStatus,
|
|
|
|
"close": GeckoDriver.prototype.close,
|
|
|
|
"closeWindow": GeckoDriver.prototype.close, // deprecated
|
|
|
|
"closeChromeWindow": GeckoDriver.prototype.closeChromeWindow,
|
|
|
|
"setTestName": GeckoDriver.prototype.setTestName,
|
|
|
|
"takeScreenshot": GeckoDriver.prototype.takeScreenshot,
|
|
|
|
"screenShot": GeckoDriver.prototype.takeScreenshot, // deprecated
|
|
|
|
"screenshot": GeckoDriver.prototype.takeScreenshot, // Selenium 2 compat
|
|
|
|
"addCookie": GeckoDriver.prototype.addCookie,
|
|
|
|
"getCookies": GeckoDriver.prototype.getCookies,
|
|
|
|
"getAllCookies": GeckoDriver.prototype.getCookies, // deprecated
|
|
|
|
"deleteAllCookies": GeckoDriver.prototype.deleteAllCookies,
|
|
|
|
"deleteCookie": GeckoDriver.prototype.deleteCookie,
|
|
|
|
"getActiveElement": GeckoDriver.prototype.getActiveElement,
|
|
|
|
"getScreenOrientation": GeckoDriver.prototype.getScreenOrientation,
|
|
|
|
"setScreenOrientation": GeckoDriver.prototype.setScreenOrientation,
|
|
|
|
"getWindowSize": GeckoDriver.prototype.getWindowSize,
|
|
|
|
"setWindowSize": GeckoDriver.prototype.setWindowSize,
|
|
|
|
"maximizeWindow": GeckoDriver.prototype.maximizeWindow,
|
|
|
|
"dismissDialog": GeckoDriver.prototype.dismissDialog,
|
|
|
|
"acceptDialog": GeckoDriver.prototype.acceptDialog,
|
|
|
|
"getTextFromDialog": GeckoDriver.prototype.getTextFromDialog,
|
2015-09-26 19:12:01 +03:00
|
|
|
"sendKeysToDialog": GeckoDriver.prototype.sendKeysToDialog,
|
|
|
|
"quitApplication": GeckoDriver.prototype.quitApplication,
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|