2016-01-14 21:12:13 +00: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/. */
|
|
|
|
|
2016-02-03 18:54:23 +00:00
|
|
|
"use strict";
|
2016-01-14 21:12:13 +00:00
|
|
|
|
2016-02-03 18:54:23 +00:00
|
|
|
const {utils: Cu} = Components;
|
2016-01-14 21:12:13 +00:00
|
|
|
|
2016-02-03 18:54:23 +00:00
|
|
|
Cu.import("chrome://marionette/content/accessibility.js");
|
2016-02-03 19:00:46 +00:00
|
|
|
Cu.import("chrome://marionette/content/atom.js");
|
2016-02-03 18:54:23 +00:00
|
|
|
Cu.import("chrome://marionette/content/error.js");
|
|
|
|
Cu.import("chrome://marionette/content/elements.js");
|
|
|
|
Cu.import("chrome://marionette/content/event.js");
|
2016-01-14 21:12:13 +00:00
|
|
|
|
2016-02-03 18:54:23 +00:00
|
|
|
this.EXPORTED_SYMBOLS = ["Interactions"];
|
2016-01-14 21:12:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* XUL elements that support disabled attribtue.
|
|
|
|
*/
|
|
|
|
const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
|
|
|
|
'ARROWSCROLLBOX',
|
|
|
|
'BUTTON',
|
|
|
|
'CHECKBOX',
|
|
|
|
'COLORPICKER',
|
|
|
|
'COMMAND',
|
|
|
|
'DATEPICKER',
|
|
|
|
'DESCRIPTION',
|
|
|
|
'KEY',
|
|
|
|
'KEYSET',
|
|
|
|
'LABEL',
|
|
|
|
'LISTBOX',
|
|
|
|
'LISTCELL',
|
|
|
|
'LISTHEAD',
|
|
|
|
'LISTHEADER',
|
|
|
|
'LISTITEM',
|
|
|
|
'MENU',
|
|
|
|
'MENUITEM',
|
|
|
|
'MENULIST',
|
|
|
|
'MENUSEPARATOR',
|
|
|
|
'PREFERENCE',
|
|
|
|
'RADIO',
|
|
|
|
'RADIOGROUP',
|
|
|
|
'RICHLISTBOX',
|
|
|
|
'RICHLISTITEM',
|
|
|
|
'SCALE',
|
|
|
|
'TAB',
|
|
|
|
'TABS',
|
|
|
|
'TEXTBOX',
|
|
|
|
'TIMEPICKER',
|
|
|
|
'TOOLBARBUTTON',
|
|
|
|
'TREE'
|
|
|
|
]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* XUL elements that support checked property.
|
|
|
|
*/
|
|
|
|
const CHECKED_PROPERTY_SUPPORTED_XUL = new Set([
|
|
|
|
'BUTTON',
|
|
|
|
'CHECKBOX',
|
|
|
|
'LISTITEM',
|
|
|
|
'TOOLBARBUTTON'
|
|
|
|
]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* XUL elements that support selected property.
|
|
|
|
*/
|
|
|
|
const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([
|
|
|
|
'LISTITEM',
|
|
|
|
'MENU',
|
|
|
|
'MENUITEM',
|
|
|
|
'MENUSEPARATOR',
|
|
|
|
'RADIO',
|
|
|
|
'RICHLISTITEM',
|
|
|
|
'TAB'
|
|
|
|
]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A collection of interactions available in marionette.
|
|
|
|
* @type {Object}
|
|
|
|
*/
|
2016-02-03 18:54:23 +00:00
|
|
|
this.Interactions = function(getCapabilies) {
|
2016-01-14 21:12:13 +00:00
|
|
|
this.accessibility = new Accessibility(getCapabilies);
|
|
|
|
};
|
|
|
|
|
|
|
|
Interactions.prototype = {
|
|
|
|
/**
|
|
|
|
* Send click event to element.
|
|
|
|
*
|
|
|
|
* @param nsIDOMWindow, ShadowRoot container
|
|
|
|
* The window and an optional shadow root that contains the element
|
|
|
|
*
|
|
|
|
* @param ElementManager elementManager
|
|
|
|
*
|
|
|
|
* @param String id
|
|
|
|
* The DOM reference ID
|
|
|
|
*/
|
|
|
|
clickElement(container, elementManager, id) {
|
|
|
|
let el = elementManager.getKnownElement(id, container);
|
2016-02-03 18:54:23 +00:00
|
|
|
let visible = elements.checkVisible(el, container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
if (!visible) {
|
|
|
|
throw new ElementNotVisibleError('Element is not visible');
|
|
|
|
}
|
|
|
|
return this.accessibility.getAccessibleObject(el, true).then(acc => {
|
|
|
|
this.accessibility.checkVisible(acc, el, visible);
|
2016-02-03 18:54:23 +00:00
|
|
|
if (atom.isElementEnabled(el)) {
|
2016-01-14 21:12:13 +00:00
|
|
|
this.accessibility.checkEnabled(acc, el, true, container);
|
|
|
|
this.accessibility.checkActionable(acc, el);
|
2016-02-03 18:54:23 +00:00
|
|
|
if (elements.isXULElement(el)) {
|
2016-01-14 21:12:13 +00:00
|
|
|
el.click();
|
|
|
|
} else {
|
|
|
|
let rects = el.getClientRects();
|
2016-02-03 18:54:23 +00:00
|
|
|
let win = el.ownerDocument.defaultView;
|
|
|
|
event.synthesizeMouseAtPoint(
|
|
|
|
rects[0].left + rects[0].width / 2,
|
|
|
|
rects[0].top + rects[0].height / 2,
|
|
|
|
{} /* opts */,
|
|
|
|
win);
|
2016-01-14 21:12:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new InvalidElementStateError('Element is not enabled');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send keys to element
|
|
|
|
*
|
|
|
|
* @param nsIDOMWindow, ShadowRoot container
|
|
|
|
* The window and an optional shadow root that contains the element
|
|
|
|
*
|
|
|
|
* @param ElementManager elementManager
|
|
|
|
*
|
|
|
|
* @param String id
|
|
|
|
* The DOM reference ID
|
|
|
|
*
|
|
|
|
* @param String?Array value
|
|
|
|
* Value to send to an element
|
|
|
|
*
|
|
|
|
* @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);
|
2016-02-03 18:54:23 +00:00
|
|
|
event.sendKeysToElement(
|
|
|
|
value, el, {ignoreVisibility: false}, container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine the element displayedness of the given web element.
|
|
|
|
*
|
|
|
|
* @param nsIDOMWindow, ShadowRoot container
|
|
|
|
* The window and an optional shadow root that contains the element
|
|
|
|
*
|
|
|
|
* @param ElementManager elementManager
|
|
|
|
*
|
|
|
|
* @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);
|
2016-02-03 18:54:23 +00:00
|
|
|
let displayed = atom.isElementDisplayed(el, container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
return this.accessibility.getAccessibleObject(el).then(acc => {
|
|
|
|
this.accessibility.checkVisible(acc, el, displayed);
|
|
|
|
return displayed;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if element is enabled.
|
|
|
|
*
|
|
|
|
* @param nsIDOMWindow, ShadowRoot container
|
|
|
|
* The window and an optional shadow root that contains the element
|
|
|
|
*
|
|
|
|
* @param ElementManager elementManager
|
|
|
|
*
|
|
|
|
* @param {WebElement} id
|
|
|
|
* Reference to web element.
|
|
|
|
*
|
|
|
|
* @return {boolean}
|
|
|
|
* True if enabled, false otherwise.
|
|
|
|
*/
|
|
|
|
isElementEnabled(container, elementManager, id) {
|
|
|
|
let el = elementManager.getKnownElement(id, container);
|
|
|
|
let enabled = true;
|
2016-02-03 18:54:23 +00:00
|
|
|
if (elements.isXULElement(el)) {
|
2016-01-14 21:12:13 +00:00
|
|
|
// Check if XUL element supports disabled attribute
|
|
|
|
if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
|
2016-02-03 18:54:23 +00:00
|
|
|
let disabled = atom.getElementAttribute(el, 'disabled', container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
if (disabled && disabled === 'true') {
|
|
|
|
enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2016-02-03 18:54:23 +00:00
|
|
|
enabled = atom.isElementEnabled(el, container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
}
|
|
|
|
return this.accessibility.getAccessibleObject(el).then(acc => {
|
|
|
|
this.accessibility.checkEnabled(acc, el, enabled, container);
|
|
|
|
return enabled;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines if the referenced element is selected or not.
|
|
|
|
*
|
|
|
|
* This operation only makes sense on input elements of the Checkbox-
|
|
|
|
* and Radio Button states, or option elements.
|
|
|
|
*
|
|
|
|
* @param nsIDOMWindow, ShadowRoot container
|
|
|
|
* The window and an optional shadow root that contains the element
|
|
|
|
*
|
|
|
|
* @param ElementManager elementManager
|
|
|
|
*
|
|
|
|
* @param {WebElement} id
|
|
|
|
* Reference to web element.
|
|
|
|
*/
|
|
|
|
isElementSelected(container, elementManager, id) {
|
|
|
|
let el = elementManager.getKnownElement(id, container);
|
|
|
|
let selected = true;
|
2016-02-03 18:54:23 +00:00
|
|
|
if (elements.isXULElement(el)) {
|
2016-01-14 21:12:13 +00:00
|
|
|
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 {
|
2016-02-03 18:54:23 +00:00
|
|
|
selected = atom.isElementSelected(el, container.frame);
|
2016-01-14 21:12:13 +00:00
|
|
|
}
|
|
|
|
return this.accessibility.getAccessibleObject(el).then(acc => {
|
|
|
|
this.accessibility.checkSelected(acc, el, selected);
|
|
|
|
return selected;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|