mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1245153 - Convert interactions.js and elements.js to modules; r=automatedtester
To simplify the dependency chain and reduce the number of duplicate functions in Marionette, a number of functions have been removed from interactions.js and added to elements.js. This makes them more easily re-usable and works around a circular dependency issue. MozReview-Commit-ID: TZc3VZzHqM --HG-- extra : histedit_source : 06b82234371ca8cd6bb0ede9cbf03f848fc66d82 extra : rebase_source : da99b4329baba3fa8a604b9b2952692568b96a75 extra : commitid : BTgnO71SGbB extra : source : 5da7628c376765842c013f90566d4264f9e9312a extra : intermediate-source : 68a6dda373d2efffd8cf76103a80f1003c969093
This commit is contained in:
parent
3ce634a949
commit
f363202bb1
@ -2,8 +2,11 @@
|
||||
* 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");
|
||||
|
||||
/**
|
||||
@ -299,7 +302,7 @@ ElementManager.prototype = {
|
||||
* 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']) {
|
||||
@ -592,10 +595,113 @@ ElementManager.prototype = {
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
@ -2,15 +2,17 @@
|
||||
* 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.
|
||||
@ -72,32 +74,11 @@ const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([
|
||||
'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);
|
||||
};
|
||||
|
||||
@ -115,22 +96,25 @@ Interactions.prototype = {
|
||||
*/
|
||||
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');
|
||||
@ -159,8 +143,8 @@ Interactions.prototype = {
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
@ -180,7 +164,7 @@ Interactions.prototype = {
|
||||
*/
|
||||
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;
|
||||
@ -204,16 +188,16 @@ Interactions.prototype = {
|
||||
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);
|
||||
@ -238,7 +222,7 @@ Interactions.prototype = {
|
||||
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;
|
||||
@ -247,71 +231,11 @@ Interactions.prototype = {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user