--- a/testing/marionette/elements.js
+++ b/testing/marionette/elements.js
@@ -1,14 +1,17 @@
/* 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/. */
-let {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("chrome://marionette/content/atoms.js");
Cu.import("chrome://marionette/content/error.js");
/**
* The ElementManager manages DOM element references and
* interactions with elements.
*
* A web element is an abstraction used to identify an element when it
* is transported across the protocol, between remote- and local ends.
@@ -294,17 +297,17 @@ ElementManager.prototype = {
* list of arguments being passed in
*
* @return object
* If '__marionetteArgs' is in args, then
* it will return an object with these arguments
* as its members.
*/
applyNamedArgs: function EM_applyNamedArgs(args) {
- namedArgs = {};
+ let namedArgs = {};
args.forEach(function(arg) {
if (arg && typeof(arg['__marionetteArgs']) === 'object') {
for (let prop in arg['__marionetteArgs']) {
namedArgs[prop] = arg['__marionetteArgs'][prop];
}
}
});
return namedArgs;
@@ -587,15 +590,118 @@ ElementManager.prototype = {
elements = [el];
}
break;
default:
throw new InvalidSelectorError(`No such strategy: ${using}`);
}
return elements;
},
-}
+};
this.elements = {};
+
elements.generateUUID = function() {
let uuid = uuidGen.generateUUID().toString();
return uuid.substring(1, uuid.length - 1);
};
+
+/**
+ * This function generates a pair of coordinates relative to the viewport
+ * given a target element and coordinates relative to that element's
+ * top-left corner.
+ *
+ * @param {Node} node
+ * Target node.
+ * @param {number=} x
+ * Horizontal offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ * @param {number=} y
+ * Vertical offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ */
+// TODO(ato): Replicated from listener.js for the time being
+elements.coordinates = function(node, x = undefined, y = undefined) {
+ let box = node.getBoundingClientRect();
+ if (!x) {
+ x = box.width / 2.0;
+ }
+ if (!y) {
+ y = box.height / 2.0;
+ }
+ return {
+ x: box.left + x,
+ y: box.top + y,
+ };
+}
+
+/**
+ * This function returns true if the node is in the viewport.
+ *
+ * @param {Element} element
+ * Target element.
+ * @param {number=} x
+ * Horizontal offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ * @param {number=} y
+ * Vertical offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ */
+elements.inViewport = function(el, x = undefined, y = undefined) {
+ let win = el.ownerDocument.defaultView;
+ let c = elements.coordinates(el, x, y);
+ let vp = {
+ top: win.pageYOffset,
+ left: win.pageXOffset,
+ bottom: (win.pageYOffset + win.innerHeight),
+ right: (win.pageXOffset + win.innerWidth)
+ };
+
+ return (vp.left <= c.x + win.pageXOffset &&
+ c.x + win.pageXOffset <= vp.right &&
+ vp.top <= c.y + win.pageYOffset &&
+ c.y + win.pageYOffset <= vp.bottom);
+};
+
+/**
+ * This function throws the visibility of the element error if the element is
+ * not displayed or the given coordinates are not within the viewport.
+ *
+ * @param {Element} element
+ * Element to check if visible.
+ * @param {Window} window
+ * Window object.
+ * @param {number=} x
+ * Horizontal offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ * @param {number=} y
+ * Vertical offset relative to target. Defaults to the centre of
+ * the target's bounding box.
+ */
+elements.checkVisible = function(el, win, x = undefined, y = undefined) {
+ // Bug 1094246: Webdriver's isShown doesn't work with content xul
+ let ns = atom.getElementAttribute(el, "namespaceURI", win);
+ if (ns.indexOf("there.is.only.xul") < 0 &&
+ !atom.isElementDisplayed(el, win)) {
+ return false;
+ }
+
+ if (el.tagName.toLowerCase() == "body") {
+ return true;
+ }
+
+ if (!elements.inViewport(el, x, y)) {
+ if (el.scrollIntoView) {
+ el.scrollIntoView(false);
+ if (!elements.inViewport(el)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+};
+
+elements.isXULElement = function(el) {
+ let ns = atom.getElementAttribute(el, "namespaceURI");
+ return ns.indexOf("there.is.only.xul") >= 0;
+};
--- a/testing/marionette/interactions.js
+++ b/testing/marionette/interactions.js
@@ -1,21 +1,23 @@
/* 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/. */
-/* global Components, Accessibility, ElementNotVisibleError,
- InvalidElementStateError, Interactions */
+"use strict";
-var {utils: Cu} = Components;
+const {utils: Cu} = Components;
-this.EXPORTED_SYMBOLS = ['Interactions'];
+Cu.import("chrome://marionette/content/accessibility.js");
+Cu.import("chrome://marionette/content/atoms.js");
+Cu.import("chrome://marionette/content/error.js");
+Cu.import("chrome://marionette/content/elements.js");
+Cu.import("chrome://marionette/content/event.js");
-Cu.import('chrome://marionette/content/accessibility.js');
-Cu.import('chrome://marionette/content/error.js');
+this.EXPORTED_SYMBOLS = ["Interactions"];
/**
* XUL elements that support disabled attribtue.
*/
const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
'ARROWSCROLLBOX',
'BUTTON',
'CHECKBOX',
@@ -68,41 +70,20 @@ const SELECTED_PROPERTY_SUPPORTED_XUL =
'MENUITEM',
'MENUSEPARATOR',
'RADIO',
'RICHLISTITEM',
'TAB'
]);
/**
- * This function generates a pair of coordinates relative to the viewport given
- * a target element and coordinates relative to that element's top-left corner.
- * @param 'x', and 'y' are the relative to the target.
- * If they are not specified, then the center of the target is used.
- */
-function coordinates(target, x, y) {
- let box = target.getBoundingClientRect();
- if (typeof x === 'undefined') {
- x = box.width / 2;
- }
- if (typeof y === 'undefined') {
- y = box.height / 2;
- }
- return {
- x: box.left + x,
- y: box.top + y
- };
-}
-
-/**
* A collection of interactions available in marionette.
* @type {Object}
*/
-this.Interactions = function(utils, getCapabilies) {
- this.utils = utils;
+this.Interactions = function(getCapabilies) {
this.accessibility = new Accessibility(getCapabilies);
};
Interactions.prototype = {
/**
* Send click event to element.
*
* @param nsIDOMWindow, ShadowRoot container
@@ -110,32 +91,35 @@ Interactions.prototype = {
*
* @param ElementManager elementManager
*
* @param String id
* The DOM reference ID
*/
clickElement(container, elementManager, id) {
let el = elementManager.getKnownElement(id, container);
- let visible = this.checkVisible(container, el);
+ let visible = elements.checkVisible(el, container.frame);
if (!visible) {
throw new ElementNotVisibleError('Element is not visible');
}
return this.accessibility.getAccessibleObject(el, true).then(acc => {
this.accessibility.checkVisible(acc, el, visible);
- if (this.utils.isElementEnabled(el)) {
+ if (atom.isElementEnabled(el)) {
this.accessibility.checkEnabled(acc, el, true, container);
this.accessibility.checkActionable(acc, el);
- if (this.isXULElement(el)) {
+ if (elements.isXULElement(el)) {
el.click();
} else {
let rects = el.getClientRects();
- this.utils.synthesizeMouseAtPoint(rects[0].left + rects[0].width/2,
- rects[0].top + rects[0].height/2,
- {}, el.ownerDocument.defaultView);
+ let win = el.ownerDocument.defaultView;
+ event.synthesizeMouseAtPoint(
+ rects[0].left + rects[0].width / 2,
+ rects[0].top + rects[0].height / 2,
+ {} /* opts */,
+ win);
}
} else {
throw new InvalidElementStateError('Element is not enabled');
}
});
},
/**
@@ -154,18 +138,18 @@ Interactions.prototype = {
*
* @param Boolean ignoreVisibility
* A flag to check element visibility
*/
sendKeysToElement(container, elementManager, id, value, ignoreVisibility) {
let el = elementManager.getKnownElement(id, container);
return this.accessibility.getAccessibleObject(el, true).then(acc => {
this.accessibility.checkActionable(acc, el);
- this.utils.sendKeysToElement(
- container.frame, el, value, ignoreVisibility);
+ event.sendKeysToElement(
+ value, el, {ignoreVisibility: false}, container.frame);
});
},
/**
* Determine the element displayedness of the given web element.
*
* @param nsIDOMWindow, ShadowRoot container
* The window and an optional shadow root that contains the element
@@ -175,17 +159,17 @@ Interactions.prototype = {
* @param {WebElement} id
* Reference to web element.
*
* Also performs additional accessibility checks if enabled by session
* capability.
*/
isElementDisplayed(container, elementManager, id) {
let el = elementManager.getKnownElement(id, container);
- let displayed = this.utils.isElementDisplayed(el);
+ let displayed = atom.isElementDisplayed(el, container.frame);
return this.accessibility.getAccessibleObject(el).then(acc => {
this.accessibility.checkVisible(acc, el, displayed);
return displayed;
});
},
/**
* Check if element is enabled.
@@ -199,26 +183,26 @@ Interactions.prototype = {
* Reference to web element.
*
* @return {boolean}
* True if enabled, false otherwise.
*/
isElementEnabled(container, elementManager, id) {
let el = elementManager.getKnownElement(id, container);
let enabled = true;
- if (this.isXULElement(el)) {
+ if (elements.isXULElement(el)) {
// Check if XUL element supports disabled attribute
if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
- let disabled = this.utils.getElementAttribute(el, 'disabled');
+ let disabled = atom.getElementAttribute(el, 'disabled', container.frame);
if (disabled && disabled === 'true') {
enabled = false;
}
}
} else {
- enabled = this.utils.isElementEnabled(el);
+ enabled = atom.isElementEnabled(el, container.frame);
}
return this.accessibility.getAccessibleObject(el).then(acc => {
this.accessibility.checkEnabled(acc, el, enabled, container);
return enabled;
});
},
/**
@@ -233,85 +217,25 @@ Interactions.prototype = {
* @param ElementManager elementManager
*
* @param {WebElement} id
* Reference to web element.
*/
isElementSelected(container, elementManager, id) {
let el = elementManager.getKnownElement(id, container);
let selected = true;
- if (this.isXULElement(el)) {
+ if (elements.isXULElement(el)) {
let tagName = el.tagName.toUpperCase();
if (CHECKED_PROPERTY_SUPPORTED_XUL.has(tagName)) {
selected = el.checked;
}
if (SELECTED_PROPERTY_SUPPORTED_XUL.has(tagName)) {
selected = el.selected;
}
} else {
- selected = this.utils.isElementSelected(el);
+ selected = atom.isElementSelected(el, container.frame);
}
return this.accessibility.getAccessibleObject(el).then(acc => {
this.accessibility.checkSelected(acc, el, selected);
return selected;
});
},
-
- /**
- * This function throws the visibility of the element error if the element is
- * not displayed or the given coordinates are not within the viewport.
- *
- * @param 'x', and 'y' are the coordinates relative to the target.
- * If they are not specified, then the center of the target is used.
- */
- checkVisible(container, el, x, y) {
- // Bug 1094246 - Webdriver's isShown doesn't work with content xul
- if (!this.isXULElement(el)) {
- //check if the element is visible
- let visible = this.utils.isElementDisplayed(el);
- if (!visible) {
- return false;
- }
- }
-
- if (el.tagName.toLowerCase() === 'body') {
- return true;
- }
- if (!this.elementInViewport(container, el, x, y)) {
- //check if scroll function exist. If so, call it.
- if (el.scrollIntoView) {
- el.scrollIntoView(false);
- if (!this.elementInViewport(container, el)) {
- return false;
- }
- }
- else {
- return false;
- }
- }
- return true;
- },
-
- isXULElement(el) {
- return this.utils.getElementAttribute(el, 'namespaceURI').indexOf(
- 'there.is.only.xul') >= 0;
- },
-
- /**
- * This function returns true if the given coordinates are in the viewport.
- * @param 'x', and 'y' are the coordinates relative to the target.
- * If they are not specified, then the center of the target is used.
- */
- elementInViewport(container, el, x, y) {
- let c = coordinates(el, x, y);
- let win = container.frame;
- let viewPort = {
- top: win.pageYOffset,
- left: win.pageXOffset,
- bottom: win.pageYOffset + win.innerHeight,
- right: win.pageXOffset + win.innerWidth
- };
- return (viewPort.left <= c.x + win.pageXOffset &&
- c.x + win.pageXOffset <= viewPort.right &&
- viewPort.top <= c.y + win.pageYOffset &&
- c.y + win.pageYOffset <= viewPort.bottom);
- }
};