зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 4dec8d87c105 (bug 1245064) for marionette bustage
This commit is contained in:
Родитель
38c337c81b
Коммит
84efe80138
|
@ -2,244 +2,209 @@
|
|||
* 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";
|
||||
/* global Accessibility, Components, Log, ElementNotAccessibleError,
|
||||
XPCOMUtils */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Log.jsm');
|
||||
|
||||
Cu.import("chrome://marionette/content/error.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'setInterval',
|
||||
'resource://gre/modules/Timer.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'clearInterval',
|
||||
'resource://gre/modules/Timer.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'ElementNotAccessibleError',
|
||||
'chrome://marionette/content/error.js');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(
|
||||
this, "setInterval", "resource://gre/modules/Timer.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(
|
||||
this, "clearInterval", "resource://gre/modules/Timer.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "retrieval",
|
||||
() => Cc["@mozilla.org/accessibleRetrieval;1"].getService(Ci.nsIAccessibleRetrieval));
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["accessibility"];
|
||||
|
||||
const logger = Log.repository.getLogger("Marionette");
|
||||
this.EXPORTED_SYMBOLS = ['Accessibility'];
|
||||
|
||||
/**
|
||||
* Number of attempts to get an accessible object for an element.
|
||||
* We attempt more than once because accessible tree can be out of sync
|
||||
* with the DOM tree for a short period of time.
|
||||
*/
|
||||
const GET_ACCESSIBLE_ATTEMPTS = 100;
|
||||
|
||||
/**
|
||||
* An interval between attempts to retrieve an accessible object for an
|
||||
* element.
|
||||
*/
|
||||
const GET_ACCESSIBLE_ATTEMPT_INTERVAL = 10;
|
||||
|
||||
this.accessibility = {};
|
||||
|
||||
/**
|
||||
* Accessible states used to check element"s state from the accessiblity API
|
||||
* Accessible states used to check element's state from the accessiblity API
|
||||
* perspective.
|
||||
*/
|
||||
accessibility.State = {
|
||||
Unavailable: Ci.nsIAccessibleStates.STATE_UNAVAILABLE,
|
||||
Focusable: Ci.nsIAccessibleStates.STATE_FOCUSABLE,
|
||||
Selectable: Ci.nsIAccessibleStates.STATE_SELECTABLE,
|
||||
Selected: Ci.nsIAccessibleStates.STATE_SELECTED,
|
||||
const states = {
|
||||
unavailable: Ci.nsIAccessibleStates.STATE_UNAVAILABLE,
|
||||
focusable: Ci.nsIAccessibleStates.STATE_FOCUSABLE,
|
||||
selectable: Ci.nsIAccessibleStates.STATE_SELECTABLE,
|
||||
selected: Ci.nsIAccessibleStates.STATE_SELECTED
|
||||
};
|
||||
|
||||
/**
|
||||
* Accessible object roles that support some action.
|
||||
*/
|
||||
accessibility.ActionableRoles = new Set([
|
||||
"checkbutton",
|
||||
"check menu item",
|
||||
"check rich option",
|
||||
"combobox",
|
||||
"combobox option",
|
||||
"entry",
|
||||
"key",
|
||||
"link",
|
||||
"listbox option",
|
||||
"listbox rich option",
|
||||
"menuitem",
|
||||
"option",
|
||||
"outlineitem",
|
||||
"pagetab",
|
||||
"pushbutton",
|
||||
"radiobutton",
|
||||
"radio menu item",
|
||||
"rowheader",
|
||||
"slider",
|
||||
"spinbutton",
|
||||
"switch",
|
||||
]);
|
||||
|
||||
var logger = Log.repository.getLogger('Marionette');
|
||||
|
||||
/**
|
||||
* Factory function that constructs a new {@code accessibility.Checks}
|
||||
* object with enforced strictness or not.
|
||||
*/
|
||||
accessibility.get = function(strict = false) {
|
||||
return new accessibility.Checks(!!strict);
|
||||
};
|
||||
|
||||
/**
|
||||
* Component responsible for interacting with platform accessibility
|
||||
* API.
|
||||
* Component responsible for interacting with platform accessibility API. Its
|
||||
* methods serve as wrappers for testing content and chrome accessibility as
|
||||
* well as accessibility of user interactions.
|
||||
*
|
||||
* Its methods serve as wrappers for testing content and chrome
|
||||
* accessibility as well as accessibility of user interactions.
|
||||
* @param {Function} getCapabilies
|
||||
* Session capabilities getter.
|
||||
*/
|
||||
accessibility.Checks = class {
|
||||
this.Accessibility = function Accessibility(getCapabilies = () => {}) {
|
||||
// A flag indicating whether the accessibility issue should be logged or cause
|
||||
// an exception. Default: log to stdout.
|
||||
Object.defineProperty(this, 'strict', {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
let capabilies = getCapabilies();
|
||||
return !!capabilies.raisesAccessibilityExceptions;
|
||||
}
|
||||
});
|
||||
// An interface for in-process accessibility clients
|
||||
// Note: we access it lazily to not enable accessibility when it is not needed
|
||||
Object.defineProperty(this, 'retrieval', {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
delete this.retrieval;
|
||||
this.retrieval = Cc[
|
||||
'@mozilla.org/accessibleRetrieval;1'].getService(
|
||||
Ci.nsIAccessibleRetrieval);
|
||||
return this.retrieval;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Accessibility.prototype = {
|
||||
|
||||
/**
|
||||
* @param {boolean} strict
|
||||
* Flag indicating whether the accessibility issue should be logged
|
||||
* or cause an error to be thrown. Default is to log to stdout.
|
||||
* Number of attempts to get an accessible object for an element. We attempt
|
||||
* more than once because accessible tree can be out of sync with the DOM tree
|
||||
* for a short period of time.
|
||||
* @type {Number}
|
||||
*/
|
||||
constructor(strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
GET_ACCESSIBLE_ATTEMPTS: 100,
|
||||
|
||||
/**
|
||||
* Get an accessible object for an element.
|
||||
*
|
||||
* @param {DOMElement|XULElement} element
|
||||
* Element to get the accessible object for.
|
||||
* @param {boolean=} mustHaveAccessible
|
||||
* Flag indicating that the element must have an accessible object.
|
||||
* Defaults to not require this.
|
||||
*
|
||||
* @return {nsIAccessible}
|
||||
* Accessibility object for the given element.
|
||||
* An interval between attempts to retrieve an accessible object for an
|
||||
* element.
|
||||
* @type {Number} ms
|
||||
*/
|
||||
getAccessible(element, mustHaveAccessible = false) {
|
||||
GET_ACCESSIBLE_ATTEMPT_INTERVAL: 10,
|
||||
|
||||
/**
|
||||
* Accessible object roles that support some action
|
||||
* @type Object
|
||||
*/
|
||||
ACTIONABLE_ROLES: new Set([
|
||||
'pushbutton',
|
||||
'checkbutton',
|
||||
'combobox',
|
||||
'key',
|
||||
'link',
|
||||
'menuitem',
|
||||
'check menu item',
|
||||
'radio menu item',
|
||||
'option',
|
||||
'listbox option',
|
||||
'listbox rich option',
|
||||
'check rich option',
|
||||
'combobox option',
|
||||
'radiobutton',
|
||||
'rowheader',
|
||||
'switch',
|
||||
'slider',
|
||||
'spinbutton',
|
||||
'pagetab',
|
||||
'entry',
|
||||
'outlineitem'
|
||||
]),
|
||||
|
||||
/**
|
||||
* Get an accessible object for a DOM element
|
||||
* @param nsIDOMElement element
|
||||
* @param Boolean mustHaveAccessible a flag indicating that the element must
|
||||
* have an accessible object
|
||||
* @return nsIAccessible object for the element
|
||||
*/
|
||||
getAccessibleObject(element, mustHaveAccessible = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let acc = retrieval.getAccessibleFor(element);
|
||||
let acc = this.retrieval.getAccessibleFor(element);
|
||||
|
||||
// if accessible object is found, return it;
|
||||
// if it is not required, also resolve
|
||||
if (acc || !mustHaveAccessible) {
|
||||
// If accessible object is found, return it. If it is not required,
|
||||
// also resolve.
|
||||
resolve(acc);
|
||||
|
||||
// if we must have an accessible but are strict,
|
||||
// reject now and avoid polling for an accessible object
|
||||
} else if (mustHaveAccessible && !this.strict) {
|
||||
// If we must have an accessible but are not raising accessibility
|
||||
// exceptions, reject now and avoid polling for an accessible object.
|
||||
reject();
|
||||
|
||||
// if we require an accessible object, we need to poll for it
|
||||
// because accessible tree might be
|
||||
// out of sync with DOM tree for a short time
|
||||
} else {
|
||||
let attempts = GET_ACCESSIBLE_ATTEMPTS;
|
||||
// If we require an accessible object, we need to poll for it because
|
||||
// accessible tree might be out of sync with DOM tree for a short time.
|
||||
let attempts = this.GET_ACCESSIBLE_ATTEMPTS;
|
||||
let intervalId = setInterval(() => {
|
||||
let acc = retrieval.getAccessibleFor(element);
|
||||
let acc = this.retrieval.getAccessibleFor(element);
|
||||
if (acc || --attempts <= 0) {
|
||||
clearInterval(intervalId);
|
||||
if (acc) {
|
||||
resolve(acc);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
if (acc) { resolve(acc); }
|
||||
else { reject(); }
|
||||
}
|
||||
}, GET_ACCESSIBLE_ATTEMPT_INTERVAL);
|
||||
}, this.GET_ACCESSIBLE_ATTEMPT_INTERVAL);
|
||||
}
|
||||
}).catch(() => this.error(
|
||||
"Element does not have an accessible object", element));
|
||||
};
|
||||
'Element does not have an accessible object', element));
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if the accessible has a role that supports some arbitrary
|
||||
* action.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if an actionable role is found on the accessible, false
|
||||
* otherwise.
|
||||
* Check if the accessible has a role that supports some action
|
||||
* @param nsIAccessible object
|
||||
* @return Boolean an indicator of role being actionable
|
||||
*/
|
||||
isActionableRole(accessible) {
|
||||
return accessibility.ActionableRoles.has(
|
||||
retrieval.getStringRole(accessible.role));
|
||||
}
|
||||
return this.ACTIONABLE_ROLES.has(
|
||||
this.retrieval.getStringRole(accessible.role));
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if an accessible has at least one action that it supports.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if the accessible has at least one supported action,
|
||||
* false otherwise.
|
||||
* Determine if an accessible has at least one action that it supports
|
||||
* @param nsIAccessible object
|
||||
* @return Boolean an indicator of supporting at least one accessible action
|
||||
*/
|
||||
hasActionCount(accessible) {
|
||||
return accessible.actionCount > 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if an accessible has a valid name.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if the accessible has a non-empty valid name, or false if
|
||||
* this is not the case.
|
||||
* Determine if an accessible has a valid name
|
||||
* @param nsIAccessible object
|
||||
* @return Boolean an indicator that the element has a non empty valid name
|
||||
*/
|
||||
hasValidName(accessible) {
|
||||
return accessible.name && accessible.name.trim();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if an accessible has a {@code hidden} attribute.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if the accesible object has a {@code hidden} attribute,
|
||||
* false otherwise.
|
||||
* Check if an accessible has a set hidden attribute
|
||||
* @param nsIAccessible object
|
||||
* @return Boolean an indicator that the element has a hidden accessible
|
||||
* attribute set to true
|
||||
*/
|
||||
hasHiddenAttribute(accessible) {
|
||||
let hidden = false;
|
||||
try {
|
||||
hidden = accessible.attributes.getStringProperty("hidden");
|
||||
hidden = accessible.attributes.getStringProperty('hidden');
|
||||
} finally {
|
||||
// if the property is missing, error will be thrown
|
||||
return hidden && hidden === "true";
|
||||
// If the property is missing, exception will be thrown.
|
||||
return hidden && hidden === 'true';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Verify if an accessible has a given state.
|
||||
* Test if an accessible has a given state.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object to test.
|
||||
* @param {number} stateToMatch
|
||||
* State to match.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if |accessible| has |stateToMatch|, false otherwise.
|
||||
* Verify if an accessible has a given state
|
||||
* @param nsIAccessible object
|
||||
* @param Number stateToMatch the state to match
|
||||
* @return Boolean accessible has a state
|
||||
*/
|
||||
matchState(accessible, stateToMatch) {
|
||||
let state = {};
|
||||
accessible.getState(state, {});
|
||||
return !!(state.value & stateToMatch);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if an accessible is hidden from the user.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if element is hidden from user, false otherwise.
|
||||
* Check if an accessible is hidden from the user of the accessibility API
|
||||
* @param nsIAccessible object
|
||||
* @return Boolean an indicator that the element is hidden from the user
|
||||
*/
|
||||
isHidden(accessible) {
|
||||
while (accessible) {
|
||||
|
@ -249,156 +214,12 @@ accessibility.Checks = class {
|
|||
accessible = accessible.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if the element's visible state corresponds to its accessibility
|
||||
* API visibility.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
* @param {DOMElement|XULElement} element
|
||||
* Element associated with |accessible|.
|
||||
* @param {boolean} visible
|
||||
* Visibility state of |element|.
|
||||
*
|
||||
* @throws ElementNotAccessibleError
|
||||
* If |element|'s visibility state does not correspond to
|
||||
* |accessible|'s.
|
||||
*/
|
||||
checkVisible(accessible, element, visible) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hiddenAccessibility = this.isHidden(accessible);
|
||||
|
||||
let message;
|
||||
if (visible && hiddenAccessibility) {
|
||||
message = "Element is not currently visible via the accessibility API " +
|
||||
"and may not be manipulated by it";
|
||||
} else if (!visible && !hiddenAccessibility) {
|
||||
message = "Element is currently only visible via the accessibility API " +
|
||||
"and can be manipulated by it";
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the element's unavailable accessibility state matches the
|
||||
* enabled state.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
* @param {DOMElement|XULElement} element
|
||||
* Element associated with |accessible|.
|
||||
* @param {boolean} enabled
|
||||
* Enabled state of |element|.
|
||||
*
|
||||
* @throws ElementNotAccessibleError
|
||||
* If |element|'s enabled state does not match |accessible|'s.
|
||||
*/
|
||||
checkEnabled(accessible, element, enabled) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
let win = element.ownerDocument.defaultView;
|
||||
let disabledAccessibility = this.matchState(
|
||||
accessible, accessibility.State.Unavailable);
|
||||
let explorable = win.getComputedStyle(element)
|
||||
.getPropertyValue("pointer-events") !== "none";
|
||||
|
||||
let message;
|
||||
if (!explorable && !disabledAccessibility) {
|
||||
message = "Element is enabled but is not explorable via the " +
|
||||
"accessibility API";
|
||||
} else if (enabled && disabledAccessibility) {
|
||||
message = "Element is enabled but disabled via the accessibility API";
|
||||
} else if (!enabled && !disabledAccessibility) {
|
||||
message = "Element is disabled but enabled via the accessibility API";
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if it is possible to activate an element with the accessibility
|
||||
* API.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
* @param {DOMElement|XULElement} element
|
||||
* Element associated with |accessible|.
|
||||
*
|
||||
* @throws ElementNotAccessibleError
|
||||
* If it is impossible to activate |element| with |accessible|.
|
||||
*/
|
||||
checkActionable(accessible, element) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
let message;
|
||||
if (!this.hasActionCount(accessible)) {
|
||||
message = "Element does not support any accessible actions";
|
||||
} else if (!this.isActionableRole(accessible)) {
|
||||
message = "Element does not have a correct accessibility role " +
|
||||
"and may not be manipulated via the accessibility API";
|
||||
} else if (!this.hasValidName(accessible)) {
|
||||
message = "Element is missing an accessible name";
|
||||
} else if (!this.matchState(accessible, accessibility.State.Focusable)) {
|
||||
message = "Element is not focusable via the accessibility API";
|
||||
}
|
||||
|
||||
this.error(message, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an element's selected state corresponds to its
|
||||
* accessibility API selected state.
|
||||
*
|
||||
* @param {nsIAccessible} accessible
|
||||
* Accessible object.
|
||||
* @param {DOMElement|XULElement}
|
||||
* Element associated with |accessible|.
|
||||
* @param {boolean} selected
|
||||
* The |element|s selected state.
|
||||
*
|
||||
* @throws ElementNotAccessibleError
|
||||
* If |element|'s selected state does not correspond to
|
||||
* |accessible|'s.
|
||||
*/
|
||||
checkSelected(accessible, element, selected) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
// element is not selectable via the accessibility API
|
||||
if (!this.matchState(accessible, accessibility.State.Selectable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedAccessibility = this.matchState(accessible, accessibility.State.Selected);
|
||||
|
||||
let message;
|
||||
if (selected && !selectedAccessibility) {
|
||||
message = "Element is selected but not selected via the accessibility API";
|
||||
} else if (!selected && selectedAccessibility) {
|
||||
message = "Element is not selected but selected via the accessibility API";
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an error if strict accessibility checks are enforced and log
|
||||
* the error to the log.
|
||||
*
|
||||
* @param {string} message
|
||||
* @param {DOMElement|XULElement} element
|
||||
* Element that caused an error.
|
||||
*
|
||||
* @throws ElementNotAccessibleError
|
||||
* If |strict| is true.
|
||||
* Send an error message or log the error message in the log
|
||||
* @param String message
|
||||
* @param DOMElement element that caused an error
|
||||
*/
|
||||
error(message, element) {
|
||||
if (!message) {
|
||||
|
@ -412,6 +233,107 @@ accessibility.Checks = class {
|
|||
throw new ElementNotAccessibleError(message);
|
||||
}
|
||||
logger.debug(message);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the element's visible state corresponds to its accessibility API
|
||||
* visibility
|
||||
* @param nsIAccessible object
|
||||
* @param WebElement corresponding to nsIAccessible object
|
||||
* @param Boolean visible element's visibility state
|
||||
*/
|
||||
checkVisible(accessible, element, visible) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
let hiddenAccessibility = this.isHidden(accessible);
|
||||
let message;
|
||||
if (visible && hiddenAccessibility) {
|
||||
message = 'Element is not currently visible via the accessibility API ' +
|
||||
'and may not be manipulated by it';
|
||||
} else if (!visible && !hiddenAccessibility) {
|
||||
message = 'Element is currently only visible via the accessibility API ' +
|
||||
'and can be manipulated by it';
|
||||
}
|
||||
this.error(message, element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the element's unavailable accessibility state matches the enabled
|
||||
* state
|
||||
* @param nsIAccessible object
|
||||
* @param WebElement corresponding to nsIAccessible object
|
||||
* @param Boolean enabled element's enabled state
|
||||
* @param Object container frame and optional ShadowDOM
|
||||
*/
|
||||
checkEnabled(accessible, element, enabled, container) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
let disabledAccessibility = this.matchState(accessible, states.unavailable);
|
||||
let explorable = container.frame.document.defaultView.getComputedStyle(
|
||||
element).getPropertyValue('pointer-events') !== 'none';
|
||||
let message;
|
||||
|
||||
if (!explorable && !disabledAccessibility) {
|
||||
message = 'Element is enabled but is not explorable via the ' +
|
||||
'accessibility API';
|
||||
} else if (enabled && disabledAccessibility) {
|
||||
message = 'Element is enabled but disabled via the accessibility API';
|
||||
} else if (!enabled && !disabledAccessibility) {
|
||||
message = 'Element is disabled but enabled via the accessibility API';
|
||||
}
|
||||
this.error(message, element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if it is possible to activate an element with the accessibility API
|
||||
* @param nsIAccessible object
|
||||
* @param WebElement corresponding to nsIAccessible object
|
||||
*/
|
||||
checkActionable(accessible, element) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
let message;
|
||||
if (!this.hasActionCount(accessible)) {
|
||||
message = 'Element does not support any accessible actions';
|
||||
} else if (!this.isActionableRole(accessible)) {
|
||||
message = 'Element does not have a correct accessibility role ' +
|
||||
'and may not be manipulated via the accessibility API';
|
||||
} else if (!this.hasValidName(accessible)) {
|
||||
message = 'Element is missing an accessible name';
|
||||
} else if (!this.matchState(accessible, states.focusable)) {
|
||||
message = 'Element is not focusable via the accessibility API';
|
||||
}
|
||||
this.error(message, element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if element's selected state corresponds to its accessibility API
|
||||
* selected state.
|
||||
* @param nsIAccessible object
|
||||
* @param WebElement corresponding to nsIAccessible object
|
||||
* @param Boolean selected element's selected state
|
||||
*/
|
||||
checkSelected(accessible, element, selected) {
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
if (!this.matchState(accessible, states.selectable)) {
|
||||
// Element is not selectable via the accessibility API
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedAccessibility = this.matchState(accessible, states.selected);
|
||||
let message;
|
||||
if (selected && !selectedAccessibility) {
|
||||
message =
|
||||
'Element is selected but not selected via the accessibility API';
|
||||
} else if (!selected && selectedAccessibility) {
|
||||
message =
|
||||
'Element is not selected but selected via the accessibility API';
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -158,6 +158,8 @@ this.GeckoDriver = function(appName, device, stopSignal, emulator) {
|
|||
"version": Services.appinfo.version,
|
||||
};
|
||||
|
||||
this.interactions = new Interactions(() => this.sessionCapabilities);
|
||||
|
||||
this.mm = globalMessageManager;
|
||||
this.listener = proxy.toListener(() => this.mm, this.sendAsync.bind(this));
|
||||
|
||||
|
@ -1964,9 +1966,8 @@ GeckoDriver.prototype.clickElement = function*(cmd, resp) {
|
|||
switch (this.context) {
|
||||
case Context.CHROME:
|
||||
let win = this.getCurrentWindow();
|
||||
let el = this.curBrowser.elementManager.getKnownElement(id, {frame: win});
|
||||
yield interaction.clickElement(
|
||||
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
||||
yield this.interactions.clickElement({ frame: win },
|
||||
this.curBrowser.elementManager, id);
|
||||
break;
|
||||
|
||||
case Context.CONTENT:
|
||||
|
@ -2064,10 +2065,8 @@ GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
|
|||
switch (this.context) {
|
||||
case Context.CHROME:
|
||||
let win = this.getCurrentWindow();
|
||||
let el = this.curBrowser.elementManager.getKnownElement(
|
||||
id, {frame: win});
|
||||
resp.body.value = yield interaction.isElementDisplayed(
|
||||
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
||||
resp.body.value = yield this.interactions.isElementDisplayed(
|
||||
{frame: win}, this.curBrowser.elementManager, id);
|
||||
break;
|
||||
|
||||
case Context.CONTENT:
|
||||
|
@ -2114,10 +2113,8 @@ GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
|
|||
case Context.CHROME:
|
||||
// Selenium atom doesn't quite work here
|
||||
let win = this.getCurrentWindow();
|
||||
let el = this.curBrowser.elementManager.getKnownElement(
|
||||
id, {frame: win});
|
||||
resp.body.value = yield interaction.isElementEnabled(
|
||||
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
||||
resp.body.value = yield this.interactions.isElementEnabled(
|
||||
{frame: win}, this.curBrowser.elementManager, id);
|
||||
break;
|
||||
|
||||
case Context.CONTENT:
|
||||
|
@ -2139,10 +2136,8 @@ GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
|
|||
case Context.CHROME:
|
||||
// Selenium atom doesn't quite work here
|
||||
let win = this.getCurrentWindow();
|
||||
let el = this.curBrowser.elementManager.getKnownElement(
|
||||
id, {frame: win});
|
||||
resp.body.value = yield interaction.isElementSelected(
|
||||
el, this.sessionCapabilities.raisesAccessibilityExceptions);
|
||||
resp.body.value = yield this.interactions.isElementSelected(
|
||||
{ frame: win }, this.curBrowser.elementManager, id);
|
||||
break;
|
||||
|
||||
case Context.CONTENT:
|
||||
|
@ -2191,10 +2186,8 @@ GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
|
|||
switch (this.context) {
|
||||
case Context.CHROME:
|
||||
let win = this.getCurrentWindow();
|
||||
let el = this.curBrowser.elementManager.getKnownElement(
|
||||
id, {frame: win});
|
||||
yield interaction.sendKeysToElement(
|
||||
el, value, true, this.sessionCapabilities.raisesAccessibilityExceptions);
|
||||
yield this.interactions.sendKeysToElement(
|
||||
{ frame: win }, this.curBrowser.elementManager, id, value, true);
|
||||
break;
|
||||
|
||||
case Context.CONTENT:
|
||||
|
|
|
@ -12,222 +12,230 @@ Cu.import("chrome://marionette/content/error.js");
|
|||
Cu.import("chrome://marionette/content/element.js");
|
||||
Cu.import("chrome://marionette/content/event.js");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["interaction"];
|
||||
this.EXPORTED_SYMBOLS = ["Interactions"];
|
||||
|
||||
/**
|
||||
* XUL elements that support disabled attribute.
|
||||
* 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",
|
||||
'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",
|
||||
'BUTTON',
|
||||
'CHECKBOX',
|
||||
'LISTITEM',
|
||||
'TOOLBARBUTTON'
|
||||
]);
|
||||
|
||||
/**
|
||||
* XUL elements that support selected property.
|
||||
*/
|
||||
const SELECTED_PROPERTY_SUPPORTED_XUL = new Set([
|
||||
"LISTITEM",
|
||||
"MENU",
|
||||
"MENUITEM",
|
||||
"MENUSEPARATOR",
|
||||
"RADIO",
|
||||
"RICHLISTITEM",
|
||||
"TAB",
|
||||
'LISTITEM',
|
||||
'MENU',
|
||||
'MENUITEM',
|
||||
'MENUSEPARATOR',
|
||||
'RADIO',
|
||||
'RICHLISTITEM',
|
||||
'TAB'
|
||||
]);
|
||||
|
||||
this.interaction = {};
|
||||
|
||||
/**
|
||||
* Interact with an element by clicking it.
|
||||
*
|
||||
* @param {DOMElement|XULElement} el
|
||||
* Element to click.
|
||||
* @param {boolean=} strict
|
||||
* Enforce strict accessibility tests.
|
||||
* A collection of interactions available in marionette.
|
||||
* @type {Object}
|
||||
*/
|
||||
interaction.clickElement = function(el, strict = false) {
|
||||
let win = getWindow(el);
|
||||
let visible = element.isVisible(el, win);
|
||||
if (!visible) {
|
||||
throw new ElementNotVisibleError("Element is not visible");
|
||||
}
|
||||
this.Interactions = function(getCapabilies) {
|
||||
this.accessibility = new Accessibility(getCapabilies);
|
||||
};
|
||||
|
||||
let a11y = accessibility.get(strict);
|
||||
return a11y.getAccessible(el, true).then(acc => {
|
||||
a11y.checkVisible(acc, el, visible);
|
||||
|
||||
if (atom.isElementEnabled(el)) {
|
||||
a11y.checkEnabled(acc, el, true);
|
||||
a11y.checkActionable(acc, el);
|
||||
|
||||
if (element.isXULElement(el)) {
|
||||
el.click();
|
||||
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);
|
||||
let visible = element.isVisible(el);
|
||||
if (!visible) {
|
||||
throw new ElementNotVisibleError('Element is not visible');
|
||||
}
|
||||
return this.accessibility.getAccessibleObject(el, true).then(acc => {
|
||||
this.accessibility.checkVisible(acc, el, visible);
|
||||
if (atom.isElementEnabled(el)) {
|
||||
this.accessibility.checkEnabled(acc, el, true, container);
|
||||
this.accessibility.checkActionable(acc, el);
|
||||
if (element.isXULElement(el)) {
|
||||
el.click();
|
||||
} else {
|
||||
let rects = el.getClientRects();
|
||||
let win = el.ownerDocument.defaultView;
|
||||
event.synthesizeMouseAtPoint(
|
||||
rects[0].left + rects[0].width / 2,
|
||||
rects[0].top + rects[0].height / 2,
|
||||
{} /* opts */,
|
||||
win);
|
||||
}
|
||||
} else {
|
||||
let rects = el.getClientRects();
|
||||
event.synthesizeMouseAtPoint(
|
||||
rects[0].left + rects[0].width / 2,
|
||||
rects[0].top + rects[0].height / 2,
|
||||
{} /* opts */,
|
||||
win);
|
||||
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);
|
||||
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
|
||||
*
|
||||
* @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);
|
||||
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.
|
||||
*
|
||||
* @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;
|
||||
if (element.isXULElement(el)) {
|
||||
// Check if XUL element supports disabled attribute
|
||||
if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
|
||||
let disabled = atom.getElementAttribute(el, 'disabled', container.frame);
|
||||
if (disabled && disabled === 'true') {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new InvalidElementStateError("Element is not enabled");
|
||||
enabled = atom.isElementEnabled(el, container.frame);
|
||||
}
|
||||
});
|
||||
};
|
||||
return this.accessibility.getAccessibleObject(el).then(acc => {
|
||||
this.accessibility.checkEnabled(acc, el, enabled, container);
|
||||
return enabled;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send keys to element.
|
||||
*
|
||||
* @param {DOMElement|XULElement} el
|
||||
* Element to send key events to.
|
||||
* @param {Array.<string>} value
|
||||
* Sequence of keystrokes to send to the element.
|
||||
* @param {boolean} ignoreVisibility
|
||||
* Flag to enable or disable element visibility tests.
|
||||
* @param {boolean=} strict
|
||||
* Enforce strict accessibility tests.
|
||||
*/
|
||||
interaction.sendKeysToElement = function(el, value, ignoreVisibility, strict = false) {
|
||||
let win = getWindow(el);
|
||||
let a11y = accessibility.get(strict);
|
||||
return a11y.getAccessible(el, true).then(acc => {
|
||||
a11y.checkActionable(acc, el);
|
||||
event.sendKeysToElement(value, el, {ignoreVisibility: false}, win);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the element displayedness of an element.
|
||||
*
|
||||
* @param {DOMElement|XULElement} el
|
||||
* Element to determine displayedness of.
|
||||
* @param {boolean=} strict
|
||||
* Enforce strict accessibility tests.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if element is displayed, false otherwise.
|
||||
*/
|
||||
interaction.isElementDisplayed = function(el, strict = false) {
|
||||
let win = getWindow(el);
|
||||
let displayed = atom.isElementDisplayed(el, win);
|
||||
|
||||
let a11y = accessibility.get(strict);
|
||||
return a11y.getAccessible(el).then(acc => {
|
||||
a11y.checkVisible(acc, el, displayed);
|
||||
return displayed;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if element is enabled.
|
||||
*
|
||||
* @param {DOMElement|XULElement} el
|
||||
* Element to test if is enabled.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if enabled, false otherwise.
|
||||
*/
|
||||
interaction.isElementEnabled = function(el, strict = false) {
|
||||
let enabled = true;
|
||||
let win = getWindow(el);
|
||||
|
||||
if (element.isXULElement(el)) {
|
||||
// check if XUL element supports disabled attribute
|
||||
if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
|
||||
let disabled = atom.getElementAttribute(el, "disabled", win);
|
||||
if (disabled && disabled === "true") {
|
||||
enabled = false;
|
||||
/**
|
||||
* 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;
|
||||
if (element.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 = atom.isElementSelected(el, container.frame);
|
||||
}
|
||||
} else {
|
||||
enabled = atom.isElementEnabled(el, {frame: win});
|
||||
}
|
||||
|
||||
let a11y = accessibility.get(strict);
|
||||
return a11y.getAccessible(el).then(acc => {
|
||||
a11y.checkEnabled(acc, el, enabled);
|
||||
return enabled;
|
||||
});
|
||||
return this.accessibility.getAccessibleObject(el).then(acc => {
|
||||
this.accessibility.checkSelected(acc, el, selected);
|
||||
return selected;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 {DOMElement|XULElement} el
|
||||
* Element to test if is selected.
|
||||
* @param {boolean=} strict
|
||||
* Enforce strict accessibility tests.
|
||||
*
|
||||
* @return {boolean}
|
||||
* True if element is selected, false otherwise.
|
||||
*/
|
||||
interaction.isElementSelected = function(el, strict = false) {
|
||||
let selected = true;
|
||||
let win = getWindow(el);
|
||||
|
||||
if (element.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 = atom.isElementSelected(el, win);
|
||||
}
|
||||
|
||||
let a11y = accessibility.get(strict);
|
||||
return a11y.getAccessible(el).then(acc => {
|
||||
a11y.checkSelected(acc, el, selected);
|
||||
return selected;
|
||||
});
|
||||
};
|
||||
|
||||
function getWindow(el) {
|
||||
return el.ownerDocument.defaultView;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
|||
loader.loadSubScript("chrome://marionette/content/simpletest.js");
|
||||
loader.loadSubScript("chrome://marionette/content/common.js");
|
||||
|
||||
Cu.import("chrome://marionette/content/accessibility.js");
|
||||
Cu.import("chrome://marionette/content/action.js");
|
||||
Cu.import("chrome://marionette/content/atom.js");
|
||||
Cu.import("chrome://marionette/content/capture.js");
|
||||
|
@ -42,7 +41,9 @@ var isRemoteBrowser = () => curContainer.frame.contentWindow !== null;
|
|||
var previousContainer = null;
|
||||
var elementManager = new ElementManager();
|
||||
|
||||
// Holds session capabilities.
|
||||
var capabilities = {};
|
||||
var interactions = new Interactions(() => capabilities);
|
||||
|
||||
var actions = new action.Chain(checkForInterrupted);
|
||||
|
||||
|
@ -857,11 +858,9 @@ function singleTap(id, corx, cory) {
|
|||
if (!visible) {
|
||||
throw new ElementNotVisibleError("Element is not currently visible and may not be manipulated");
|
||||
}
|
||||
|
||||
let a11y = accessibility.get(capabilities.raisesAccessibilityExceptions);
|
||||
return a11y.getAccessible(el, true).then(acc => {
|
||||
a11y.checkVisible(acc, el, visible);
|
||||
a11y.checkActionable(acc, el);
|
||||
return interactions.accessibility.getAccessibleObject(el, true).then(acc => {
|
||||
interactions.accessibility.checkVisible(acc, el, visible);
|
||||
interactions.accessibility.checkActionable(acc, el);
|
||||
if (!curContainer.frame.document.createTouch) {
|
||||
actions.mouseEventsOnly = true;
|
||||
}
|
||||
|
@ -1270,9 +1269,7 @@ function getActiveElement() {
|
|||
* Reference to the web element to click.
|
||||
*/
|
||||
function clickElement(id) {
|
||||
let el = elementManager.getKnownElement(id, curContainer);
|
||||
return interaction.clickElement(
|
||||
el, capabilities.raisesAccessibilityExceptions);
|
||||
return interactions.clickElement(curContainer, elementManager, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1326,9 +1323,7 @@ function getElementTagName(id) {
|
|||
* capability.
|
||||
*/
|
||||
function isElementDisplayed(id) {
|
||||
let el = elementManager.getKnownElement(id, curContainer);
|
||||
return interaction.isElementDisplayed(
|
||||
el, capabilities.raisesAccessibilityExceptions);
|
||||
return interactions.isElementDisplayed(curContainer, elementManager, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1379,9 +1374,7 @@ function getElementRect(id) {
|
|||
* True if enabled, false otherwise.
|
||||
*/
|
||||
function isElementEnabled(id) {
|
||||
let el = elementManager.getKnownElement(id, curContainer);
|
||||
return interaction.isElementEnabled(
|
||||
el, capabilities.raisesAccessibilityExceptions);
|
||||
return interactions.isElementEnabled(curContainer, elementManager, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1391,9 +1384,7 @@ function isElementEnabled(id) {
|
|||
* and Radio Button states, or option elements.
|
||||
*/
|
||||
function isElementSelected(id) {
|
||||
let el = elementManager.getKnownElement(id, curContainer);
|
||||
return interaction.isElementSelected(
|
||||
el, capabilities.raisesAccessibilityExceptions);
|
||||
return interactions.isElementSelected(curContainer, elementManager, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1414,10 +1405,9 @@ function sendKeysToElement(msg) {
|
|||
sendSyncMessage("Marionette:getFiles",
|
||||
{value: p, command_id: command_id});
|
||||
} else {
|
||||
let promise = interaction.sendKeysToElement(
|
||||
el, val, false, capabilities.raisesAccessibilityExceptions)
|
||||
.then(() => sendOk(command_id))
|
||||
.catch(e => sendError(e, command_id));
|
||||
interactions.sendKeysToElement(curContainer, elementManager, id, val)
|
||||
.then(() => sendOk(command_id))
|
||||
.catch(e => sendError(e, command_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче