Bug 1561435 - Format accessible/, a=automatic-formatting

# ignore-this-changeset

Differential Revision: https://phabricator.services.mozilla.com/D35895

--HG--
extra : source : e786ed0773342d7c897007bb1be5a101945b894a
This commit is contained in:
Victor Porof 2019-07-05 09:45:34 +02:00
Родитель 10375c0418
Коммит 058dce8bba
103 изменённых файлов: 7207 добавлений и 4029 удалений

Просмотреть файл

@ -44,7 +44,6 @@ module.exports = {
],
"overrides": [{
"files": [
"accessible/**",
"browser/**",
"build/**",
"caps/**",

Просмотреть файл

@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js
# Ignore all top-level directories for now.
accessible/**
browser/**
build/**
caps/**

Просмотреть файл

@ -6,10 +6,15 @@
var EXPORTED_SYMBOLS = ["AccessFu"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Rect",
"resource://gre/modules/Geometry.jsm");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { Logger, Utils } = ChromeUtils.import(
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Rect",
"resource://gre/modules/Geometry.jsm"
);
const GECKOVIEW_MESSAGE = {
ACTIVATE: "GeckoView:AccessibilityActivate",
@ -121,8 +126,10 @@ var AccessFu = {
};
this._eventDispatcherListeners.set(win, listener);
// desktop mochitests don't have this.
win.WindowEventDispatcher.registerListener(listener,
Object.values(GECKOVIEW_MESSAGE));
win.WindowEventDispatcher.registerListener(
listener,
Object.values(GECKOVIEW_MESSAGE)
);
}
},
@ -139,7 +146,8 @@ var AccessFu = {
// desktop mochitests don't have this.
win.WindowEventDispatcher.unregisterListener(
this._eventDispatcherListeners.get(win),
Object.values(GECKOVIEW_MESSAGE));
Object.values(GECKOVIEW_MESSAGE)
);
this._eventDispatcherListeners.delete(win);
}
},
@ -157,7 +165,8 @@ var AccessFu = {
case GECKOVIEW_MESSAGE.PREVIOUS: {
let rule = "Simple";
if (data && data.rule && data.rule.length) {
rule = data.rule.substr(0, 1).toUpperCase() +
rule =
data.rule.substr(0, 1).toUpperCase() +
data.rule.substr(1).toLowerCase();
}
let method = event.replace(/GeckoView:Accessibility(\w+)/, "move$1");
@ -198,9 +207,13 @@ var AccessFu = {
switch (aTopic) {
case "domwindowopened": {
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", () => {
this._attachWindow(win);
}, { once: true });
win.addEventListener(
"load",
() => {
this._attachWindow(win);
},
{ once: true }
);
break;
}
}
@ -208,8 +221,7 @@ var AccessFu = {
_handleEvent: function _handleEvent(aEvent) {
switch (aEvent.type) {
case "TabSelect":
{
case "TabSelect": {
if (this._focused) {
// We delay this for half a second so the awesomebar could close,
// and we could use the current coordinates for the content item.
@ -218,7 +230,8 @@ var AccessFu = {
delay: 500,
forcePresent: true,
noOpIfOnScreen: true,
moveMethod: "moveFirst" });
moveMethod: "moveFirst",
});
}
break;
}
@ -247,36 +260,48 @@ var AccessFu = {
* @param {Window} aWindow the window containing the item
*/
screenToClientBounds(aJsonBounds, aWindow) {
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top);
let { devicePixelRatio, mozInnerScreenX, mozInnerScreenY } = aWindow;
let bounds = new Rect(
aJsonBounds.left,
aJsonBounds.top,
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top
);
let { devicePixelRatio, mozInnerScreenX, mozInnerScreenY } = aWindow;
bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
return bounds.expandToIntegers();
},
bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
return bounds.expandToIntegers();
},
};
var Input = {
moveToPoint: function moveToPoint(aRule, aX, aY, aWindow) {
Logger.debug("moveToPoint", aX, aY);
const mm = Utils.getCurrentMessageManager(aWindow);
mm.sendAsyncMessage("AccessFu:MoveToPoint",
{rule: aRule, x: aX, y: aY, origin: "top"});
mm.sendAsyncMessage("AccessFu:MoveToPoint", {
rule: aRule,
x: aX,
y: aY,
origin: "top",
});
},
moveCursor: function moveCursor(aAction, aRule, aInputType, aWindow) {
const mm = Utils.getCurrentMessageManager(aWindow);
mm.sendAsyncMessage("AccessFu:MoveCursor",
{ action: aAction, rule: aRule,
origin: "top", inputType: aInputType });
mm.sendAsyncMessage("AccessFu:MoveCursor", {
action: aAction,
rule: aRule,
origin: "top",
inputType: aInputType,
});
},
androidScroll: function androidScroll(aDirection, aWindow) {
const mm = Utils.getCurrentMessageManager(aWindow);
mm.sendAsyncMessage("AccessFu:AndroidScroll",
{ direction: aDirection, origin: "top" });
mm.sendAsyncMessage("AccessFu:AndroidScroll", {
direction: aDirection,
origin: "top",
});
},
moveByGranularity: function moveByGranularity(aDetails, aWindow) {
@ -305,9 +330,18 @@ var Input = {
let win = aBrowser.ownerGlobal;
let winUtils = win.windowUtils;
let p = AccessFu.screenToClientBounds(aDetails.bounds, win).center();
winUtils.sendWheelEvent(p.x, p.y,
horizontal ? page : 0, horizontal ? 0 : page, 0,
win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
winUtils.sendWheelEvent(
p.x,
p.y,
horizontal ? page : 0,
horizontal ? 0 : page,
0,
win.WheelEvent.DOM_DELTA_PAGE,
0,
0,
0,
0
);
},
};
AccessFu.Input = Input;

Просмотреть файл

@ -1,4 +1,6 @@
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const AndroidEvents = {
VIEW_CLICKED: 0x01,
@ -21,53 +23,51 @@ function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) {
let offset = aPrefix.length;
for (var name in aObject) {
if (name.indexOf(aPrefix) === 0) {
aMap[name.slice(offset)] = aModifier ?
aModifier(aObject[name]) : aObject[name];
aMap[name.slice(offset)] = aModifier
? aModifier(aObject[name])
: aObject[name];
}
}
return aMap;
}
XPCOMUtils.defineLazyGetter(
this, "Roles",
function() {
return ConstantsMap(Ci.nsIAccessibleRole, "ROLE_");
});
XPCOMUtils.defineLazyGetter(this, "Roles", function() {
return ConstantsMap(Ci.nsIAccessibleRole, "ROLE_");
});
XPCOMUtils.defineLazyGetter(
this, "Events",
function() {
return ConstantsMap(Ci.nsIAccessibleEvent, "EVENT_");
});
XPCOMUtils.defineLazyGetter(this, "Events", function() {
return ConstantsMap(Ci.nsIAccessibleEvent, "EVENT_");
});
XPCOMUtils.defineLazyGetter(
this, "Relations",
function() {
return ConstantsMap(Ci.nsIAccessibleRelation, "RELATION_");
});
XPCOMUtils.defineLazyGetter(this, "Relations", function() {
return ConstantsMap(Ci.nsIAccessibleRelation, "RELATION_");
});
XPCOMUtils.defineLazyGetter(
this, "Prefilters",
function() {
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "PREFILTER_");
});
XPCOMUtils.defineLazyGetter(this, "Prefilters", function() {
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "PREFILTER_");
});
XPCOMUtils.defineLazyGetter(
this, "Filters",
function() {
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "FILTER_");
});
XPCOMUtils.defineLazyGetter(this, "Filters", function() {
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "FILTER_");
});
XPCOMUtils.defineLazyGetter(
this, "States",
function() {
let statesMap = ConstantsMap(Ci.nsIAccessibleStates, "STATE_", {},
(val) => { return { base: val, extended: 0 }; });
ConstantsMap(Ci.nsIAccessibleStates, "EXT_STATE_", statesMap,
(val) => { return { base: 0, extended: val }; });
return statesMap;
XPCOMUtils.defineLazyGetter(this, "States", function() {
let statesMap = ConstantsMap(Ci.nsIAccessibleStates, "STATE_", {}, val => {
return { base: val, extended: 0 };
});
ConstantsMap(Ci.nsIAccessibleStates, "EXT_STATE_", statesMap, val => {
return { base: 0, extended: val };
});
return statesMap;
});
var EXPORTED_SYMBOLS = ["Roles", "Events", "Relations",
"Filters", "States", "Prefilters", "AndroidEvents"];
var EXPORTED_SYMBOLS = [
"Roles",
"Events",
"Relations",
"Filters",
"States",
"Prefilters",
"AndroidEvents",
];

Просмотреть файл

@ -2,18 +2,36 @@
* 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/. */
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Logger",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Roles",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "TraversalRules",
"resource://gre/modules/accessibility/Traversal.jsm");
ChromeUtils.defineModuleGetter(this, "TraversalHelper",
"resource://gre/modules/accessibility/Traversal.jsm");
ChromeUtils.defineModuleGetter(
this,
"Utils",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Logger",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Roles",
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"States",
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"TraversalRules",
"resource://gre/modules/accessibility/Traversal.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"TraversalHelper",
"resource://gre/modules/accessibility/Traversal.jsm"
);
var EXPORTED_SYMBOLS = ["ContentControl"];
@ -31,15 +49,17 @@ function ContentControl(aContentScope) {
}
this.ContentControl.prototype = {
messagesOfInterest: ["AccessFu:Activate",
"AccessFu:AndroidScroll",
"AccessFu:AutoMove",
"AccessFu:ClearCursor",
"AccessFu:Clipboard",
"AccessFu:MoveByGranularity",
"AccessFu:MoveCursor",
"AccessFu:MoveToPoint",
"AccessFu:SetSelection"],
messagesOfInterest: [
"AccessFu:Activate",
"AccessFu:AndroidScroll",
"AccessFu:AutoMove",
"AccessFu:ClearCursor",
"AccessFu:Clipboard",
"AccessFu:MoveByGranularity",
"AccessFu:MoveCursor",
"AccessFu:MoveToPoint",
"AccessFu:SetSelection",
],
start: function cc_start() {
let cs = this._contentScope.get();
@ -69,9 +89,11 @@ this.ContentControl.prototype = {
receiveMessage: function cc_receiveMessage(aMessage) {
Logger.debug(() => {
return ["ContentControl.receiveMessage",
return [
"ContentControl.receiveMessage",
aMessage.name,
JSON.stringify(aMessage.json)];
JSON.stringify(aMessage.json),
];
});
// If we get an explicit message, we should immediately cancel any autoMove
@ -86,7 +108,9 @@ this.ContentControl.prototype = {
}
} catch (x) {
Logger.logException(
x, "Error handling message: " + JSON.stringify(aMessage.json));
x,
"Error handling message: " + JSON.stringify(aMessage.json)
);
}
},
@ -105,10 +129,11 @@ this.ContentControl.prototype = {
return;
}
this._contentScope.get().sendAsyncMessage("AccessFu:DoScroll",
{ bounds: Utils.getBounds(position),
page: aMessage.json.direction === "forward" ? 1 : -1,
horizontal: false });
this._contentScope.get().sendAsyncMessage("AccessFu:DoScroll", {
bounds: Utils.getBounds(position),
page: aMessage.json.direction === "forward" ? 1 : -1,
horizontal: false,
});
},
handleMoveCursor: function cc_handleMoveCursor(aMessage) {
@ -132,7 +157,9 @@ this.ContentControl.prototype = {
if (origin === "child") {
// We just stepped out of a child, clear child cursor.
Utils.getMessageManagerForFrame(aMessage.target).sendAsyncMessage(
"AccessFu:ClearCursor", {});
"AccessFu:ClearCursor",
{}
);
} else {
// We potentially landed on a new child cursor. If so, we want to
// either be on the first or last item in the child doc.
@ -147,8 +174,10 @@ this.ContentControl.prototype = {
// new position.
this.sendToChild(vc, aMessage, { action: childAction }, true);
}
} else if (!this._childMessageSenders.has(aMessage.target) &&
origin !== "top") {
} else if (
!this._childMessageSenders.has(aMessage.target) &&
origin !== "top"
) {
// We failed to move, and the message is not from a parent, so forward
// to it.
this.sendToParent(aMessage);
@ -176,7 +205,7 @@ this.ContentControl.prototype = {
},
handleActivate: function cc_handleActivate(aMessage) {
let activateAccessible = (aAccessible) => {
let activateAccessible = aAccessible => {
Logger.debug(() => {
return ["activateAccessible", Logger.accessibleToString(aAccessible)];
});
@ -194,30 +223,55 @@ this.ContentControl.prototype = {
// Could possibly be made simpler in the future. Maybe core
// engine could expose nsCoreUtiles::DispatchMouseEvent()?
let docAcc = Utils.AccService.getAccessibleFor(this.document);
let docX = {}, docY = {}, docW = {}, docH = {};
let docX = {},
docY = {},
docW = {},
docH = {};
docAcc.getBounds(docX, docY, docW, docH);
let objX = {}, objY = {}, objW = {}, objH = {};
let objX = {},
objY = {},
objW = {},
objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
let x = Math.round((objX.value - docX.value) + objW.value / 2);
let y = Math.round((objY.value - docY.value) + objH.value / 2);
let x = Math.round(objX.value - docX.value + objW.value / 2);
let y = Math.round(objY.value - docY.value + objH.value / 2);
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
for (let eventType of ["mousedown", "mouseup"]) {
let evt = this.document.createEvent("MouseEvents");
evt.initMouseEvent(eventType, true, true, this.window,
x, y, 0, 0, 0, false, false, false, false, 0, null);
evt.initMouseEvent(
eventType,
true,
true,
this.window,
x,
y,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
node.dispatchEvent(evt);
}
}
};
let focusedAcc = Utils.AccService.getAccessibleFor(
this.document.activeElement);
if (focusedAcc && this.vc.position === focusedAcc
&& focusedAcc.role === Roles.ENTRY) {
this.document.activeElement
);
if (
focusedAcc &&
this.vc.position === focusedAcc &&
focusedAcc.role === Roles.ENTRY
) {
let accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
let newOffset = aMessage.json.offset;
if (newOffset >= 0 && newOffset <= accText.characterCount) {
@ -228,7 +282,7 @@ this.ContentControl.prototype = {
}
// recursively find a descendant that is activatable.
let getActivatableDescendant = (aAccessible) => {
let getActivatableDescendant = aAccessible => {
if (aAccessible.actionCount > 0) {
return aAccessible;
}
@ -273,7 +327,17 @@ this.ContentControl.prototype = {
let evt = this.document.createEvent("KeyboardEvent");
let keycode = aStepUp ? evt.DOM_VK_DOWN : evt.DOM_VK_UP;
evt.initKeyEvent(
"keypress", false, true, null, false, false, false, false, keycode, 0);
"keypress",
false,
true,
null,
false,
false,
false,
false,
keycode,
0
);
elem.dispatchEvent(evt);
}
@ -282,11 +346,13 @@ this.ContentControl.prototype = {
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
const { direction, granularity, select } = aMessage.json;
const focusedAcc =
Utils.AccService.getAccessibleFor(this.document.activeElement);
const focusedAcc = Utils.AccService.getAccessibleFor(
this.document.activeElement
);
const editable =
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE) ?
focusedAcc.QueryInterface(Ci.nsIAccessibleText) : null;
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE)
? focusedAcc.QueryInterface(Ci.nsIAccessibleText)
: null;
if (editable) {
const caretOffset = editable.caretOffset;
@ -315,8 +381,8 @@ this.ContentControl.prototype = {
}
if (editable) {
const newOffset = direction === "Next" ?
this.vc.endOffset : this.vc.startOffset;
const newOffset =
direction === "Next" ? this.vc.endOffset : this.vc.startOffset;
if (select) {
let anchor = editable.caretOffset;
if (editable.selectionCount) {
@ -332,8 +398,9 @@ this.ContentControl.prototype = {
handleSetSelection: function cc_handleSetSelection(aMessage) {
const { start, end } = aMessage.json;
const focusedAcc =
Utils.AccService.getAccessibleFor(this.document.activeElement);
const focusedAcc = Utils.AccService.getAccessibleFor(
this.document.activeElement
);
if (focusedAcc) {
const accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
if (start == end) {
@ -346,8 +413,9 @@ this.ContentControl.prototype = {
handleClipboard: function cc_handleClipboard(aMessage) {
const { action } = aMessage.json;
const focusedAcc =
Utils.AccService.getAccessibleFor(this.document.activeElement);
const focusedAcc = Utils.AccService.getAccessibleFor(
this.document.activeElement
);
if (focusedAcc) {
const [startSel, endSel] = Utils.getTextSelection(focusedAcc);
const editText = focusedAcc.QueryInterface(Ci.nsIAccessibleEditableText);
@ -389,8 +457,12 @@ this.ContentControl.prototype = {
return null;
},
sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer,
aFocus) {
sendToChild: function cc_sendToChild(
aVirtualCursor,
aMessage,
aReplacer,
aFocus
) {
let position = aVirtualCursor.position;
let mm = this.getChildCursor(position);
if (!mm) {
@ -436,17 +508,20 @@ this.ContentControl.prototype = {
let moveFunc = () => {
let vc = this.vc;
let acc = aAnchor;
let rule = aOptions.onScreenOnly ?
TraversalRules.SimpleOnScreen : TraversalRules.Simple;
let rule = aOptions.onScreenOnly
? TraversalRules.SimpleOnScreen
: TraversalRules.Simple;
if (aOptions.noOpIfOnScreen &&
Utils.isAliveAndVisible(vc.position, true)) {
if (
aOptions.noOpIfOnScreen &&
Utils.isAliveAndVisible(vc.position, true)
) {
return;
}
if (aOptions.moveToFocused) {
acc = Utils.AccService.getAccessibleFor(
this.document.activeElement) || acc;
acc =
Utils.AccService.getAccessibleFor(this.document.activeElement) || acc;
}
let moved = false;
@ -454,22 +529,31 @@ this.ContentControl.prototype = {
let moveFirstOrLast = moveMethod in ["moveFirst", "moveLast"];
if (!moveFirstOrLast || acc) {
// We either need next/previous or there is an anchor we need to use.
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](rule, acc, true,
true);
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](
rule,
acc,
true,
true
);
}
if (moveFirstOrLast && !moved) {
// We move to first/last after no anchor move happened or succeeded.
moved = vc[moveMethod](rule, true);
}
this.sendToChild(vc, {
name: "AccessFu:AutoMove",
json: {
moveMethod: aOptions.moveMethod,
moveToFocused: aOptions.moveToFocused,
noOpIfOnScreen: true,
this.sendToChild(
vc,
{
name: "AccessFu:AutoMove",
json: {
moveMethod: aOptions.moveMethod,
moveToFocused: aOptions.moveToFocused,
noOpIfOnScreen: true,
},
},
}, null, true);
null,
true
);
};
if (aOptions.delay) {
@ -484,7 +568,8 @@ this.ContentControl.prototype = {
this._autoMove = 0;
},
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference,
QueryInterface: ChromeUtils.generateQI([
Ci.nsISupportsWeakReference,
Ci.nsIMessageListener,
]),
};

Просмотреть файл

@ -4,25 +4,38 @@
"use strict";
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Logger",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Events",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(
this,
"Services",
"resource://gre/modules/Services.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Utils",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Logger",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Events",
"resource://gre/modules/accessibility/Constants.jsm"
);
var EXPORTED_SYMBOLS = ["EventManager"];
function EventManager(aContentScope) {
this.contentScope = aContentScope;
this.addEventListener = this.contentScope.addEventListener.bind(
this.contentScope);
this.contentScope
);
this.removeEventListener = this.contentScope.removeEventListener.bind(
this.contentScope);
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(
this.contentScope);
this.contentScope
);
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(this.contentScope);
}
this.EventManager.prototype = {
@ -65,67 +78,72 @@ this.EventManager.prototype = {
handleAccEvent: function handleAccEvent(aEvent) {
Logger.debug(() => {
return ["A11yEvent", Logger.eventToString(aEvent),
Logger.accessibleToString(aEvent.accessible)];
return [
"A11yEvent",
Logger.eventToString(aEvent),
Logger.accessibleToString(aEvent.accessible),
];
});
// Don't bother with non-content events in firefox.
if (Utils.MozBuildApp == "browser" &&
aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
// XXX Bug 442005 results in DocAccessible::getDocType returning
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
// 'window' does not currently work.
(aEvent.accessibleDocument.DOMDocument.doctype &&
aEvent.accessibleDocument.DOMDocument.doctype.name === "window")) {
if (
Utils.MozBuildApp == "browser" &&
aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
// XXX Bug 442005 results in DocAccessible::getDocType returning
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
// 'window' does not currently work.
(aEvent.accessibleDocument.DOMDocument.doctype &&
aEvent.accessibleDocument.DOMDocument.doctype.name === "window")
) {
return;
}
switch (aEvent.eventType) {
case Events.TEXT_CARET_MOVED:
{
if (aEvent.accessible != aEvent.accessibleDocument &&
!aEvent.isFromUserInput) {
case Events.TEXT_CARET_MOVED: {
if (
aEvent.accessible != aEvent.accessibleDocument &&
!aEvent.isFromUserInput
) {
// If caret moves in document without direct user
// we are probably stepping through results in find-in-page.
let acc = Utils.getTextLeafForOffset(aEvent.accessible,
aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset);
let acc = Utils.getTextLeafForOffset(
aEvent.accessible,
aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset
);
this.contentControl.autoMove(acc);
}
break;
}
case Events.NAME_CHANGE:
{
case Events.NAME_CHANGE: {
// XXX: Port to Android
break;
}
case Events.SCROLLING_START:
{
case Events.SCROLLING_START: {
this.contentControl.autoMove(aEvent.accessible);
break;
}
case Events.SHOW:
{
case Events.SHOW: {
// XXX: Port to Android
break;
}
case Events.HIDE:
{
case Events.HIDE: {
// XXX: Port to Android
break;
}
case Events.VALUE_CHANGE:
{
case Events.VALUE_CHANGE: {
// XXX: Port to Android
break;
}
}
},
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver]),
QueryInterface: ChromeUtils.generateQI([
Ci.nsISupportsWeakReference,
Ci.nsIObserver,
]),
};
const AccessibilityEventObserver = {
/**
* A WeakMap containing [content, EventManager] pairs.
*/
@ -180,8 +198,10 @@ const AccessibilityEventObserver = {
}
this.eventManagers.set(content, aEventManager);
// Since at least one EventManager was registered, start listening.
Logger.debug("AccessibilityEventObserver.addListener. Total:",
this.listenerCount);
Logger.debug(
"AccessibilityEventObserver.addListener. Total:",
this.listenerCount
);
this.start();
},
@ -198,8 +218,10 @@ const AccessibilityEventObserver = {
return;
}
this.listenerCount--;
Logger.debug("AccessibilityEventObserver.removeListener. Total:",
this.listenerCount);
Logger.debug(
"AccessibilityEventObserver.removeListener. Total:",
this.listenerCount
);
if (this.listenerCount === 0) {
// If there are no EventManagers registered at the moment, stop listening
// to the 'accessible-event' messages.
@ -237,8 +259,10 @@ const AccessibilityEventObserver = {
if (!event.accessibleDocument) {
Logger.warning(
"AccessibilityEventObserver.observe: no accessible document:",
Logger.eventToString(event), "accessible:",
Logger.accessibleToString(event.accessible));
Logger.eventToString(event),
"accessible:",
Logger.accessibleToString(event.accessible)
);
return;
}
let content;
@ -247,8 +271,10 @@ const AccessibilityEventObserver = {
} catch (e) {
Logger.warning(
"AccessibilityEventObserver.observe: no window for accessible document:",
Logger.eventToString(event), "accessible:",
Logger.accessibleToString(event.accessible));
Logger.eventToString(event),
"accessible:",
Logger.accessibleToString(event.accessible)
);
return;
}
// Match the content window to its EventManager.
@ -257,9 +283,12 @@ const AccessibilityEventObserver = {
if (Utils.MozBuildApp === "browser" && !content.isChromeWindow) {
Logger.warning(
"AccessibilityEventObserver.observe: ignored event:",
Logger.eventToString(event), "accessible:",
Logger.accessibleToString(event.accessible), "document:",
Logger.accessibleToString(event.accessibleDocument));
Logger.eventToString(event),
"accessible:",
Logger.accessibleToString(event.accessible),
"document:",
Logger.accessibleToString(event.accessibleDocument)
);
}
return;
}

Просмотреть файл

@ -6,17 +6,33 @@
var EXPORTED_SYMBOLS = ["TraversalRules", "TraversalHelper"]; // jshint ignore:line
const {PrefCache, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Filters", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Prefilters", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
const { PrefCache, Utils } = ChromeUtils.import(
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Filters", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Prefilters", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
var gSkipEmptyImages = new PrefCache("accessibility.accessfu.skip_empty_images");
var gSkipEmptyImages = new PrefCache(
"accessibility.accessfu.skip_empty_images"
);
function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter, aContainerRule) {
this._explicitMatchRoles = new Set(aRoles);
@ -30,66 +46,71 @@ function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter, aContainerRule) {
this._matchRoles.push(Roles.INTERNAL_FRAME);
}
}
this._matchFunc = aMatchFunc || function() { return Filters.MATCH; };
this._matchFunc =
aMatchFunc ||
function() {
return Filters.MATCH;
};
this.preFilter = aPreFilter || gSimplePreFilter;
this.containerRule = aContainerRule;
}
BaseTraversalRule.prototype = {
getMatchRoles: function BaseTraversalRule_getmatchRoles() {
return this._matchRoles;
},
getMatchRoles: function BaseTraversalRule_getmatchRoles() {
return this._matchRoles;
},
match: function BaseTraversalRule_match(aAccessible) {
let role = aAccessible.role;
if (role == Roles.INTERNAL_FRAME) {
return (Utils.getMessageManagerForFrame(aAccessible.DOMNode)) ?
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
}
match: function BaseTraversalRule_match(aAccessible) {
let role = aAccessible.role;
if (role == Roles.INTERNAL_FRAME) {
return Utils.getMessageManagerForFrame(aAccessible.DOMNode)
? Filters.MATCH | Filters.IGNORE_SUBTREE
: Filters.IGNORE;
}
if (this._explicitMatchRoles.has(role) ||
!this._explicitMatchRoles.size) {
return this._matchFunc(aAccessible);
}
if (this._explicitMatchRoles.has(role) || !this._explicitMatchRoles.size) {
return this._matchFunc(aAccessible);
}
return Filters.IGNORE;
},
return Filters.IGNORE;
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
};
var gSimpleTraversalRoles =
[Roles.MENUITEM,
Roles.LINK,
Roles.PAGETAB,
Roles.GRAPHIC,
Roles.STATICTEXT,
Roles.TEXT_LEAF,
Roles.PUSHBUTTON,
Roles.CHECKBUTTON,
Roles.RADIOBUTTON,
Roles.COMBOBOX,
Roles.PROGRESSBAR,
Roles.BUTTONDROPDOWN,
Roles.BUTTONMENU,
Roles.CHECK_MENU_ITEM,
Roles.PASSWORD_TEXT,
Roles.RADIO_MENU_ITEM,
Roles.TOGGLE_BUTTON,
Roles.ENTRY,
Roles.KEY,
Roles.HEADER,
Roles.HEADING,
Roles.SLIDER,
Roles.SPINBUTTON,
Roles.OPTION,
Roles.LISTITEM,
Roles.GRID_CELL,
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.STATUSBAR,
Roles.SWITCH,
Roles.MATHML_MATH];
var gSimpleTraversalRoles = [
Roles.MENUITEM,
Roles.LINK,
Roles.PAGETAB,
Roles.GRAPHIC,
Roles.STATICTEXT,
Roles.TEXT_LEAF,
Roles.PUSHBUTTON,
Roles.CHECKBUTTON,
Roles.RADIOBUTTON,
Roles.COMBOBOX,
Roles.PROGRESSBAR,
Roles.BUTTONDROPDOWN,
Roles.BUTTONMENU,
Roles.CHECK_MENU_ITEM,
Roles.PASSWORD_TEXT,
Roles.RADIO_MENU_ITEM,
Roles.TOGGLE_BUTTON,
Roles.ENTRY,
Roles.KEY,
Roles.HEADER,
Roles.HEADING,
Roles.SLIDER,
Roles.SPINBUTTON,
Roles.OPTION,
Roles.LISTITEM,
Roles.GRID_CELL,
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.STATUSBAR,
Roles.SWITCH,
Roles.MATHML_MATH,
];
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
// An object is simple, if it either has a single child lineage,
@ -118,90 +139,101 @@ var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
}
switch (aAccessible.role) {
case Roles.COMBOBOX:
// We don't want to ignore the subtree because this is often
// where the list box hangs out.
return Filters.MATCH;
case Roles.TEXT_LEAF:
{
case Roles.COMBOBOX:
// We don't want to ignore the subtree because this is often
// where the list box hangs out.
return Filters.MATCH;
case Roles.TEXT_LEAF: {
// Nameless text leaves are boring, skip them.
let name = aAccessible.name;
return (name && name.trim()) ? Filters.MATCH : Filters.IGNORE;
return name && name.trim() ? Filters.MATCH : Filters.IGNORE;
}
case Roles.STATICTEXT:
// Ignore prefix static text in list items. They are typically bullets or numbers.
return Utils.isListItemDecorator(aAccessible) ?
Filters.IGNORE : Filters.MATCH;
case Roles.GRAPHIC:
return TraversalRules._shouldSkipImage(aAccessible);
case Roles.HEADER:
case Roles.HEADING:
case Roles.COLUMNHEADER:
case Roles.ROWHEADER:
case Roles.STATUSBAR:
if ((aAccessible.childCount > 0 || aAccessible.name) &&
(isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))) {
case Roles.STATICTEXT:
// Ignore prefix static text in list items. They are typically bullets or numbers.
return Utils.isListItemDecorator(aAccessible)
? Filters.IGNORE
: Filters.MATCH;
case Roles.GRAPHIC:
return TraversalRules._shouldSkipImage(aAccessible);
case Roles.HEADER:
case Roles.HEADING:
case Roles.COLUMNHEADER:
case Roles.ROWHEADER:
case Roles.STATUSBAR:
if (
(aAccessible.childCount > 0 || aAccessible.name) &&
(isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))
) {
return Filters.MATCH | Filters.IGNORE_SUBTREE;
}
return Filters.IGNORE;
case Roles.GRID_CELL:
return isSingleLineage(aAccessible) || isFlatSubtree(aAccessible)
? Filters.MATCH | Filters.IGNORE_SUBTREE
: Filters.IGNORE;
case Roles.LISTITEM: {
let item =
aAccessible.childCount === 2 &&
aAccessible.firstChild.role === Roles.STATICTEXT
? aAccessible.lastChild
: aAccessible;
return isSingleLineage(item) || isFlatSubtree(item)
? Filters.MATCH | Filters.IGNORE_SUBTREE
: Filters.IGNORE;
}
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
return Filters.MATCH | Filters.IGNORE_SUBTREE;
}
return Filters.IGNORE;
case Roles.GRID_CELL:
return isSingleLineage(aAccessible) || isFlatSubtree(aAccessible) ?
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
case Roles.LISTITEM:
{
let item = aAccessible.childCount === 2 &&
aAccessible.firstChild.role === Roles.STATICTEXT ?
aAccessible.lastChild : aAccessible;
return isSingleLineage(item) || isFlatSubtree(item) ?
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
}
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
return Filters.MATCH |
Filters.IGNORE_SUBTREE;
}
};
var gSimplePreFilter = Prefilters.DEFUNCT |
var gSimplePreFilter =
Prefilters.DEFUNCT |
Prefilters.INVISIBLE |
Prefilters.TRANSPARENT |
Prefilters.PLATFORM_PRUNED;
var TraversalRules = { // jshint ignore:line
var TraversalRules = {
// jshint ignore:line
Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
SimpleOnScreen: new BaseTraversalRule(
gSimpleTraversalRoles, gSimpleMatchFunc,
gSimplePreFilter | Prefilters.OFFSCREEN),
gSimpleTraversalRoles,
gSimpleMatchFunc,
gSimplePreFilter | Prefilters.OFFSCREEN
),
Anchor: new BaseTraversalRule(
[Roles.LINK],
function Anchor_match(aAccessible) {
// We want to ignore links, only focus named anchors.
if (Utils.getState(aAccessible).contains(States.LINKED)) {
return Filters.IGNORE;
}
return Filters.MATCH;
}),
Anchor: new BaseTraversalRule([Roles.LINK], function Anchor_match(
aAccessible
) {
// We want to ignore links, only focus named anchors.
if (Utils.getState(aAccessible).contains(States.LINKED)) {
return Filters.IGNORE;
}
return Filters.MATCH;
}),
Button: new BaseTraversalRule(
[Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID]),
Button: new BaseTraversalRule([
Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID,
]),
Combobox: new BaseTraversalRule(
[Roles.COMBOBOX,
Roles.LISTBOX]),
Combobox: new BaseTraversalRule([Roles.COMBOBOX, Roles.LISTBOX]),
Landmark: new BaseTraversalRule(
[],
function Landmark_match(aAccessible) {
return Utils.getLandmarkName(aAccessible) ? Filters.MATCH :
Filters.IGNORE;
}, null, true),
return Utils.getLandmarkName(aAccessible)
? Filters.MATCH
: Filters.IGNORE;
},
null,
true
),
/* A rule for Android's section navigation, lands on landmarks, regions, and
on headings to aid navigation of traditionally structured documents */
@ -220,123 +252,131 @@ var TraversalRules = { // jshint ignore:line
"navigation",
"search",
"region",
]);
]);
return matchedRole ? Filters.MATCH : Filters.IGNORE;
}, null, true),
},
null,
true
),
Entry: new BaseTraversalRule(
[Roles.ENTRY,
Roles.PASSWORD_TEXT]),
Entry: new BaseTraversalRule([Roles.ENTRY, Roles.PASSWORD_TEXT]),
FormElement: new BaseTraversalRule(
[Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID,
Roles.COMBOBOX,
Roles.LISTBOX,
Roles.ENTRY,
Roles.PASSWORD_TEXT,
Roles.PAGETAB,
Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM,
Roles.SLIDER,
Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH]),
FormElement: new BaseTraversalRule([
Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID,
Roles.COMBOBOX,
Roles.LISTBOX,
Roles.ENTRY,
Roles.PASSWORD_TEXT,
Roles.PAGETAB,
Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM,
Roles.SLIDER,
Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH,
]),
Graphic: new BaseTraversalRule(
[Roles.GRAPHIC],
function Graphic_match(aAccessible) {
return TraversalRules._shouldSkipImage(aAccessible);
}),
Graphic: new BaseTraversalRule([Roles.GRAPHIC], function Graphic_match(
aAccessible
) {
return TraversalRules._shouldSkipImage(aAccessible);
}),
Heading: new BaseTraversalRule(
[Roles.HEADING],
function Heading_match(aAccessible) {
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
}),
Heading: new BaseTraversalRule([Roles.HEADING], function Heading_match(
aAccessible
) {
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
}),
ListItem: new BaseTraversalRule(
[Roles.LISTITEM,
Roles.TERM]),
ListItem: new BaseTraversalRule([Roles.LISTITEM, Roles.TERM]),
Link: new BaseTraversalRule(
[Roles.LINK],
function Link_match(aAccessible) {
// We want to ignore anchors, only focus real links.
if (Utils.getState(aAccessible).contains(States.LINKED)) {
return Filters.MATCH;
}
return Filters.IGNORE;
}),
Link: new BaseTraversalRule([Roles.LINK], function Link_match(aAccessible) {
// We want to ignore anchors, only focus real links.
if (Utils.getState(aAccessible).contains(States.LINKED)) {
return Filters.MATCH;
}
return Filters.IGNORE;
}),
/* For TalkBack's "Control" granularity. Form conrols and links */
Control: new BaseTraversalRule(
[Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID,
Roles.COMBOBOX,
Roles.LISTBOX,
Roles.ENTRY,
Roles.PASSWORD_TEXT,
Roles.PAGETAB,
Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM,
Roles.SLIDER,
Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH,
Roles.LINK,
Roles.MENUITEM],
[
Roles.PUSHBUTTON,
Roles.SPINBUTTON,
Roles.TOGGLE_BUTTON,
Roles.BUTTONDROPDOWN,
Roles.BUTTONDROPDOWNGRID,
Roles.COMBOBOX,
Roles.LISTBOX,
Roles.ENTRY,
Roles.PASSWORD_TEXT,
Roles.PAGETAB,
Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM,
Roles.SLIDER,
Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH,
Roles.LINK,
Roles.MENUITEM,
],
function Control_match(aAccessible) {
// We want to ignore anchors, only focus real links.
if (aAccessible.role == Roles.LINK &&
!Utils.getState(aAccessible).contains(States.LINKED)) {
if (
aAccessible.role == Roles.LINK &&
!Utils.getState(aAccessible).contains(States.LINKED)
) {
return Filters.IGNORE;
}
return Filters.MATCH;
}),
}
),
List: new BaseTraversalRule(
[Roles.LIST,
Roles.DEFINITION_LIST],
null, null, true),
[Roles.LIST, Roles.DEFINITION_LIST],
null,
null,
true
),
PageTab: new BaseTraversalRule(
[Roles.PAGETAB]),
PageTab: new BaseTraversalRule([Roles.PAGETAB]),
Paragraph: new BaseTraversalRule(
[Roles.PARAGRAPH,
Roles.SECTION],
[Roles.PARAGRAPH, Roles.SECTION],
function Paragraph_match(aAccessible) {
for (let child = aAccessible.firstChild; child; child = child.nextSibling) {
for (
let child = aAccessible.firstChild;
child;
child = child.nextSibling
) {
if (child.role === Roles.TEXT_LEAF) {
return Filters.MATCH | Filters.IGNORE_SUBTREE;
}
}
return Filters.IGNORE;
}),
}
),
RadioButton: new BaseTraversalRule(
[Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM]),
RadioButton: new BaseTraversalRule([
Roles.RADIOBUTTON,
Roles.RADIO_MENU_ITEM,
]),
Separator: new BaseTraversalRule(
[Roles.SEPARATOR]),
Separator: new BaseTraversalRule([Roles.SEPARATOR]),
Table: new BaseTraversalRule(
[Roles.TABLE]),
Table: new BaseTraversalRule([Roles.TABLE]),
Checkbox: new BaseTraversalRule(
[Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH /* A type of checkbox that represents on/off values */]),
Checkbox: new BaseTraversalRule([
Roles.CHECKBUTTON,
Roles.CHECK_MENU_ITEM,
Roles.SWITCH /* A type of checkbox that represents on/off values */,
]),
_shouldSkipImage: function _shouldSkipImage(aAccessible) {
if (gSkipEmptyImages.value && aAccessible.name === "") {
@ -390,5 +430,4 @@ var TraversalHelper = {
}
return aVirtualCursor[aMethod](rule);
},
};

Просмотреть файл

@ -4,24 +4,46 @@
"use strict";
ChromeUtils.defineModuleGetter(this, "Services", // jshint ignore:line
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "Rect", // jshint ignore:line
"resource://gre/modules/Geometry.jsm");
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Events", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "Relations", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "PluralForm", // jshint ignore:line
"resource://gre/modules/PluralForm.jsm");
ChromeUtils.defineModuleGetter(
this,
"Services", // jshint ignore:line
"resource://gre/modules/Services.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Rect", // jshint ignore:line
"resource://gre/modules/Geometry.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Events", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Relations", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"PluralForm", // jshint ignore:line
"resource://gre/modules/PluralForm.jsm"
);
var EXPORTED_SYMBOLS = ["Utils", "Logger", "PivotContext", "PrefCache"]; // jshint ignore:line
var Utils = { // jshint ignore:line
var Utils = {
// jshint ignore:line
_buildAppMap: {
"{3c2e2abc-06d4-11e1-ac3b-374f68613e61}": "b2g",
"{d1bfe7d9-c01e-4237-998b-7b5f960a4314}": "graphene",
@ -31,8 +53,9 @@ var Utils = { // jshint ignore:line
get AccService() {
if (!this._AccService) {
this._AccService = Cc["@mozilla.org/accessibilityService;1"].
getService(Ci.nsIAccessibilityService);
this._AccService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
}
return this._AccService;
@ -52,7 +75,7 @@ var Utils = { // jshint ignore:line
get ScriptName() {
if (!this._ScriptName) {
this._ScriptName =
(Services.appinfo.processType == 2) ? "AccessFuContent" : "AccessFu";
Services.appinfo.processType == 2 ? "AccessFuContent" : "AccessFu";
}
return this._ScriptName;
},
@ -61,7 +84,8 @@ var Utils = { // jshint ignore:line
if (!this._AndroidSdkVersion) {
if (Services.appinfo.OS == "Android") {
this._AndroidSdkVersion = Services.sysinfo.getPropertyAsInt32(
"version");
"version"
);
} else {
// Most useful in desktop debugging.
this._AndroidSdkVersion = 16;
@ -76,7 +100,9 @@ var Utils = { // jshint ignore:line
},
getCurrentBrowser: function getCurrentBrowser(aWindow) {
return aWindow.document.querySelector("browser[type=content][primary=true]");
return aWindow.document.querySelector(
"browser[type=content][primary=true]"
);
},
get isContentProcess() {
@ -88,17 +114,19 @@ var Utils = { // jshint ignore:line
localize: function localize(aOutput) {
let outputArray = Array.isArray(aOutput) ? aOutput : [aOutput];
let localized =
outputArray.map(details => this.stringBundle.get(details));
let localized = outputArray.map(details => this.stringBundle.get(details));
// Clean up the white space.
return localized.filter(word => word).map(word => word.trim()).
filter(trimmed => trimmed);
return localized
.filter(word => word)
.map(word => word.trim())
.filter(trimmed => trimmed);
},
get stringBundle() {
delete this.stringBundle;
let bundle = Services.strings.createBundle(
"chrome://global/locale/AccessFu.properties");
"chrome://global/locale/AccessFu.properties"
);
this.stringBundle = {
get: function stringBundle_get(aDetails = {}) {
if (!aDetails || typeof aDetails === "string") {
@ -150,12 +178,13 @@ var Utils = { // jshint ignore:line
if (aAccessibleOrEvent instanceof Ci.nsIAccessibleStateChangeEvent) {
return new State(
aAccessibleOrEvent.isExtraState ? 0 : aAccessibleOrEvent.state,
aAccessibleOrEvent.isExtraState ? aAccessibleOrEvent.state : 0);
aAccessibleOrEvent.isExtraState ? aAccessibleOrEvent.state : 0
);
}
let state = {};
let extState = {};
aAccessibleOrEvent.getState(state, extState);
return new State(state.value, extState.value);
let state = {};
let extState = {};
aAccessibleOrEvent.getState(state, extState);
return new State(state.value, extState.value);
},
getAttributes: function getAttributes(aAccessible) {
@ -173,8 +202,10 @@ var Utils = { // jshint ignore:line
},
getVirtualCursor: function getVirtualCursor(aDocument) {
let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
this.AccService.getAccessibleFor(aDocument);
let doc =
aDocument instanceof Ci.nsIAccessible
? aDocument
: this.AccService.getAccessibleFor(aDocument);
return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
},
@ -184,7 +215,10 @@ var Utils = { // jshint ignore:line
},
getBounds: function getBounds(aAccessible) {
let objX = {}, objY = {}, objW = {}, objH = {};
let objX = {},
objY = {},
objW = {},
objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
return new Rect(objX.value, objY.value, objW.value, objH.value);
@ -192,7 +226,8 @@ var Utils = { // jshint ignore:line
getTextSelection: function getTextSelection(aAccessible) {
const accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
const start = {}, end = {};
const start = {},
end = {};
if (accText.selectionCount) {
accText.getSelectionBounds(0, start, end);
} else {
@ -202,12 +237,26 @@ var Utils = { // jshint ignore:line
return [start.value, end.value];
},
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
aPreserveContentScale) {
getTextBounds: function getTextBounds(
aAccessible,
aStart,
aEnd,
aPreserveContentScale
) {
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
let objX = {}, objY = {}, objW = {}, objH = {};
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
let objX = {},
objY = {},
objW = {},
objH = {};
accText.getRangeExtents(
aStart,
aEnd,
objX,
objY,
objW,
objH,
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE
);
return new Rect(objX.value, objY.value, objW.value, objH.value);
},
@ -219,8 +268,10 @@ var Utils = { // jshint ignore:line
// ancestry of documents and skip everything else.
if (aSubTreeRoot instanceof Ci.nsIAccessibleDocument) {
while (acc) {
let parentDoc = acc instanceof Ci.nsIAccessibleDocument ?
acc.parentDocument : acc.document;
let parentDoc =
acc instanceof Ci.nsIAccessibleDocument
? acc.parentDocument
: acc.document;
if (parentDoc === aSubTreeRoot) {
return true;
}
@ -260,8 +311,11 @@ var Utils = { // jshint ignore:line
try {
let state = this.getState(aAccessible);
if (state.contains(States.DEFUNCT) || state.contains(States.INVISIBLE) ||
(aIsOnScreen && state.contains(States.OFFSCREEN))) {
if (
state.contains(States.DEFUNCT) ||
state.contains(States.INVISIBLE) ||
(aIsOnScreen && state.contains(States.OFFSCREEN))
) {
return false;
}
} catch (x) {
@ -333,15 +387,20 @@ var Utils = { // jshint ignore:line
return null;
},
isListItemDecorator: function isListItemDecorator(aStaticText,
aExcludeOrdered) {
isListItemDecorator: function isListItemDecorator(
aStaticText,
aExcludeOrdered
) {
let parent = aStaticText.parent;
if (aExcludeOrdered && parent.parent.DOMNode.nodeName === "OL") {
return false;
}
return parent.role === Roles.LISTITEM && parent.childCount > 1 &&
aStaticText.indexInParent === 0;
return (
parent.role === Roles.LISTITEM &&
parent.childCount > 1 &&
aStaticText.indexInParent === 0
);
},
getTextLeafForOffset: function getTextLeafForOffset(aAccessible, aOffset) {
@ -380,8 +439,10 @@ State.prototype = {
return !!(this.base & other.base || this.extended & other.extended);
},
toString: function State_toString() {
let stateStrings = Utils.AccService.
getStringStates(this.base, this.extended);
let stateStrings = Utils.AccService.getStringStates(
this.base,
this.extended
);
let statesArray = new Array(stateStrings.length);
for (let i = 0; i < statesArray.length; i++) {
statesArray[i] = stateStrings.item(i);
@ -390,7 +451,8 @@ State.prototype = {
},
};
var Logger = { // jshint ignore:line
var Logger = {
// jshint ignore:line
GESTURE: -1,
DEBUG: 0,
INFO: 1,
@ -409,9 +471,15 @@ var Logger = { // jshint ignore:line
}
let args = Array.prototype.slice.call(arguments, 1);
let message = (typeof(args[0]) === "function" ? args[0]() : args).join(" ");
message = "[" + Utils.ScriptName + "] " + this._LEVEL_NAMES[aLogLevel + 1] +
" " + message + "\n";
let message = (typeof args[0] === "function" ? args[0]() : args).join(" ");
message =
"[" +
Utils.ScriptName +
"] " +
this._LEVEL_NAMES[aLogLevel + 1] +
" " +
message +
"\n";
dump(message);
if (this.useConsoleService) {
try {
@ -424,31 +492,43 @@ var Logger = { // jshint ignore:line
info: function info() {
this.log.apply(
this, [this.INFO].concat(Array.prototype.slice.call(arguments)));
this,
[this.INFO].concat(Array.prototype.slice.call(arguments))
);
},
gesture: function gesture() {
this.log.apply(
this, [this.GESTURE].concat(Array.prototype.slice.call(arguments)));
this,
[this.GESTURE].concat(Array.prototype.slice.call(arguments))
);
},
debug: function debug() {
this.log.apply(
this, [this.DEBUG].concat(Array.prototype.slice.call(arguments)));
this,
[this.DEBUG].concat(Array.prototype.slice.call(arguments))
);
},
warning: function warning() {
this.log.apply(
this, [this.WARNING].concat(Array.prototype.slice.call(arguments)));
this,
[this.WARNING].concat(Array.prototype.slice.call(arguments))
);
},
error: function error() {
this.log.apply(
this, [this.ERROR].concat(Array.prototype.slice.call(arguments)));
this,
[this.ERROR].concat(Array.prototype.slice.call(arguments))
);
},
logException: function logException(
aException, aErrorMessage = "An exception has occured") {
aException,
aErrorMessage = "An exception has occured"
) {
try {
let stackMessage = "";
if (aException.stack) {
@ -458,7 +538,8 @@ var Logger = { // jshint ignore:line
let stackLines = [];
while (frame && frame.lineNumber) {
stackLines.push(
" " + frame.name + "@" + frame.filename + ":" + frame.lineNumber);
" " + frame.name + "@" + frame.filename + ":" + frame.lineNumber
);
frame = frame.caller;
}
stackMessage = stackLines.join("\n");
@ -466,9 +547,9 @@ var Logger = { // jshint ignore:line
stackMessage =
"(" + aException.fileName + ":" + aException.lineNumber + ")";
}
this.error(aErrorMessage + ":\n " +
aException.message + "\n" +
stackMessage);
this.error(
aErrorMessage + ":\n " + aException.message + "\n" + stackMessage
);
} catch (x) {
this.error(x);
}
@ -480,8 +561,13 @@ var Logger = { // jshint ignore:line
}
try {
return "[ " + Utils.AccService.getStringRole(aAccessible.role) +
" | " + aAccessible.name + " ]";
return (
"[ " +
Utils.AccService.getStringRole(aAccessible.role) +
" | " +
aAccessible.name +
" ]"
);
} catch (x) {
return "[ defunct ]";
}
@ -491,19 +577,24 @@ var Logger = { // jshint ignore:line
let str = Utils.AccService.getStringEventType(aEvent.eventType);
if (aEvent.eventType == Events.STATE_CHANGE) {
let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
let stateStrings = event.isExtraState ?
Utils.AccService.getStringStates(0, event.state) :
Utils.AccService.getStringStates(event.state, 0);
let stateStrings = event.isExtraState
? Utils.AccService.getStringStates(0, event.state)
: Utils.AccService.getStringStates(event.state, 0);
str += " (" + stateStrings.item(0) + ")";
}
if (aEvent.eventType == Events.VIRTUALCURSOR_CHANGED) {
let event = aEvent.QueryInterface(
Ci.nsIAccessibleVirtualCursorChangeEvent);
let pivot = aEvent.accessible.QueryInterface(
Ci.nsIAccessibleDocument).virtualCursor;
str += " (" + this.accessibleToString(event.oldAccessible) + " -> " +
this.accessibleToString(pivot.position) + ")";
Ci.nsIAccessibleVirtualCursorChangeEvent
);
let pivot = aEvent.accessible.QueryInterface(Ci.nsIAccessibleDocument)
.virtualCursor;
str +=
" (" +
this.accessibleToString(event.oldAccessible) +
" -> " +
this.accessibleToString(pivot.position) +
")";
}
return str;
@ -521,20 +612,25 @@ var Logger = { // jshint ignore:line
this._dumpTreeInternal(aLogLevel, aRootAccessible, 0);
},
_dumpTreeInternal:
function _dumpTreeInternal(aLogLevel, aAccessible, aIndent) {
let indentStr = "";
for (let i = 0; i < aIndent; i++) {
indentStr += " ";
}
this.log(aLogLevel, indentStr,
this.accessibleToString(aAccessible),
"(" + this.statesToString(aAccessible) + ")");
for (let i = 0; i < aAccessible.childCount; i++) {
this._dumpTreeInternal(aLogLevel, aAccessible.getChildAt(i),
aIndent + 1);
}
},
_dumpTreeInternal: function _dumpTreeInternal(
aLogLevel,
aAccessible,
aIndent
) {
let indentStr = "";
for (let i = 0; i < aIndent; i++) {
indentStr += " ";
}
this.log(
aLogLevel,
indentStr,
this.accessibleToString(aAccessible),
"(" + this.statesToString(aAccessible) + ")"
);
for (let i = 0; i < aAccessible.childCount; i++) {
this._dumpTreeInternal(aLogLevel, aAccessible.getChildAt(i), aIndent + 1);
}
},
};
/**
@ -547,13 +643,17 @@ var Logger = { // jshint ignore:line
* label. In this case the |accessible| field would be the embedded control,
* and the |accessibleForBounds| field would be the label.
*/
function PivotContext(aAccessible, aOldAccessible, // jshint ignore:line
aStartOffset, aEndOffset, aIgnoreAncestry = false,
aIncludeInvisible = false) {
function PivotContext(
aAccessible,
aOldAccessible, // jshint ignore:line
aStartOffset,
aEndOffset,
aIgnoreAncestry = false,
aIncludeInvisible = false
) {
this._accessible = aAccessible;
this._nestedControl = Utils.getEmbeddedControl(aAccessible);
this._oldAccessible =
this._isDefunct(aOldAccessible) ? null : aOldAccessible;
this._oldAccessible = this._isDefunct(aOldAccessible) ? null : aOldAccessible;
this.startOffset = aStartOffset;
this.endOffset = aEndOffset;
this._ignoreAncestry = aIgnoreAncestry;
@ -585,13 +685,16 @@ PivotContext.prototype = {
}
if (!this._textAndAdjustedOffsets) {
let result = {startOffset: this.startOffset,
endOffset: this.endOffset,
text: this._accessible.QueryInterface(Ci.nsIAccessibleText).
getText(0,
Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT)};
let result = {
startOffset: this.startOffset,
endOffset: this.endOffset,
text: this._accessible
.QueryInterface(Ci.nsIAccessibleText)
.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT),
};
let hypertextAcc = this._accessible.QueryInterface(
Ci.nsIAccessibleHyperText);
Ci.nsIAccessibleHyperText
);
// Iterate through the links in backwards order so text replacements don't
// affect the offsets of links yet to be processed.
@ -599,9 +702,9 @@ PivotContext.prototype = {
let link = hypertextAcc.getLinkAt(i);
let linkText = "";
if (link instanceof Ci.nsIAccessibleText) {
linkText = link.QueryInterface(Ci.nsIAccessibleText).
getText(0,
Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
linkText = link
.QueryInterface(Ci.nsIAccessibleText)
.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
}
let start = link.startIndex;
@ -611,8 +714,10 @@ PivotContext.prototype = {
result[offset] += linkText.length - (end - start);
}
}
result.text = result.text.substring(0, start) + linkText +
result.text.substring(end);
result.text =
result.text.substring(0, start) +
linkText +
result.text.substring(end);
}
this._textAndAdjustedOffsets = result;
@ -631,7 +736,7 @@ PivotContext.prototype = {
let parent = aAccessible;
try {
while (parent && (parent = parent.parent)) {
ancestry.push(parent);
ancestry.push(parent);
}
} catch (x) {
// A defunct accessible will raise an exception geting parent.
@ -660,8 +765,9 @@ PivotContext.prototype = {
*/
get currentAncestry() {
if (!this._currentAncestry) {
this._currentAncestry = this._ignoreAncestry ? [] :
this._getAncestry(this.accessible);
this._currentAncestry = this._ignoreAncestry
? []
: this._getAncestry(this.accessible);
}
return this._currentAncestry;
},
@ -673,9 +779,11 @@ PivotContext.prototype = {
*/
get newAncestry() {
if (!this._newAncestry) {
this._newAncestry = this._ignoreAncestry ? [] :
this.currentAncestry.filter(
(currentAncestor, i) => currentAncestor !== this.oldAncestry[i]);
this._newAncestry = this._ignoreAncestry
? []
: this.currentAncestry.filter(
(currentAncestor, i) => currentAncestor !== this.oldAncestry[i]
);
}
return this._newAncestry;
},
@ -716,17 +824,23 @@ PivotContext.prototype = {
*/
get interactionHints() {
let hints = [];
this.newAncestry.concat(this.accessible).reverse().forEach(aAccessible => {
let hint = Utils.getAttributes(aAccessible)["moz-hint"];
if (hint) {
hints.push(hint);
} else if (aAccessible.actionCount > 0) {
hints.push({
string: Utils.AccService.getStringRole(
aAccessible.role).replace(/\s/g, "") + "-hint",
});
}
});
this.newAncestry
.concat(this.accessible)
.reverse()
.forEach(aAccessible => {
let hint = Utils.getAttributes(aAccessible)["moz-hint"];
if (hint) {
hints.push(hint);
} else if (aAccessible.actionCount > 0) {
hints.push({
string:
Utils.AccService.getStringRole(aAccessible.role).replace(
/\s/g,
""
) + "-hint",
});
}
});
return hints;
},
@ -758,13 +872,15 @@ PivotContext.prototype = {
if (!aAccessible) {
return null;
}
if (![
Roles.CELL,
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.MATHML_CELL,
].includes(aAccessible.role)) {
return null;
if (
![
Roles.CELL,
Roles.COLUMNHEADER,
Roles.ROWHEADER,
Roles.MATHML_CELL,
].includes(aAccessible.role)
) {
return null;
}
try {
return aAccessible.QueryInterface(Ci.nsIAccessibleTableCell);
@ -774,7 +890,7 @@ PivotContext.prototype = {
}
};
let getHeaders = function* getHeaders(aHeaderCells) {
for (let {name} of aHeaderCells.enumerate(Ci.nsIAccessible)) {
for (let { name } of aHeaderCells.enumerate(Ci.nsIAccessible)) {
yield name;
}
};
@ -782,8 +898,10 @@ PivotContext.prototype = {
cellInfo.current = getAccessibleCell(aAccessible);
if (!cellInfo.current) {
Logger.warning(aAccessible,
"does not support nsIAccessibleTableCell interface.");
Logger.warning(
aAccessible,
"does not support nsIAccessibleTableCell interface."
);
this._cells.set(domNode, null);
return null;
}
@ -806,10 +924,10 @@ PivotContext.prototype = {
}
if (cellInfo.previous) {
cellInfo.rowChanged = cellInfo.current.rowIndex !==
cellInfo.previous.rowIndex;
cellInfo.columnChanged = cellInfo.current.columnIndex !==
cellInfo.previous.columnIndex;
cellInfo.rowChanged =
cellInfo.current.rowIndex !== cellInfo.previous.rowIndex;
cellInfo.columnChanged =
cellInfo.current.columnIndex !== cellInfo.previous.columnIndex;
} else {
cellInfo.rowChanged = true;
cellInfo.columnChanged = true;
@ -821,14 +939,20 @@ PivotContext.prototype = {
cellInfo.rowIndex = cellInfo.current.rowIndex;
cellInfo.columnHeaders = [];
if (cellInfo.columnChanged && cellInfo.current.role !==
Roles.COLUMNHEADER) {
cellInfo.columnHeaders = [...getHeaders(cellInfo.current.columnHeaderCells)];
if (
cellInfo.columnChanged &&
cellInfo.current.role !== Roles.COLUMNHEADER
) {
cellInfo.columnHeaders = [
...getHeaders(cellInfo.current.columnHeaderCells),
];
}
cellInfo.rowHeaders = [];
if (cellInfo.rowChanged &&
(cellInfo.current.role === Roles.CELL ||
cellInfo.current.role === Roles.MATHML_CELL)) {
if (
cellInfo.rowChanged &&
(cellInfo.current.role === Roles.CELL ||
cellInfo.current.role === Roles.MATHML_CELL)
) {
cellInfo.rowHeaders = [...getHeaders(cellInfo.current.rowHeaderCells)];
}
@ -853,7 +977,8 @@ PivotContext.prototype = {
},
};
function PrefCache(aName, aCallback, aRunCallbackNow) { // jshint ignore:line
function PrefCache(aName, aCallback, aRunCallbackNow) {
// jshint ignore:line
this.name = aName;
this.callback = aCallback;
@ -905,6 +1030,8 @@ PrefCache.prototype = {
}
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
QueryInterface: ChromeUtils.generateQI([
Ci.nsIObserver,
Ci.nsISupportsWeakReference,
]),
};

Просмотреть файл

@ -4,16 +4,31 @@
/* eslint-env mozilla/frame-script */
ChromeUtils.defineModuleGetter(this, "Logger",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "EventManager",
"resource://gre/modules/accessibility/EventManager.jsm");
ChromeUtils.defineModuleGetter(this, "ContentControl",
"resource://gre/modules/accessibility/ContentControl.jsm");
ChromeUtils.defineModuleGetter(this, "States",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(
this,
"Logger",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"Utils",
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"EventManager",
"resource://gre/modules/accessibility/EventManager.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"ContentControl",
"resource://gre/modules/accessibility/ContentControl.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"States",
"resource://gre/modules/accessibility/Constants.jsm"
);
Logger.info("content-script.js", content.document.location);

Просмотреть файл

@ -13,15 +13,19 @@ async function testScaledBounds(browser, accDoc, scale, id, type = "object") {
let [docX, docY] = getBounds(accDoc);
// Get the unscaled bounds of the accessible
let [x, y, width, height] = type == "text" ?
getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) : getBounds(acc);
let [x, y, width, height] =
type == "text"
? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE)
: getBounds(acc);
await ContentTask.spawn(browser, scale, _scale => {
setResolution(content.document, _scale);
});
let [scaledX, scaledY, scaledWidth, scaledHeight] = type == "text" ?
getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) : getBounds(acc);
let [scaledX, scaledY, scaledWidth, scaledHeight] =
type == "text"
? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE)
: getBounds(acc);
let name = prettyName(acc);
isWithin(scaledWidth, width * scale, 2, "Wrong scaled width of " + name);
@ -48,7 +52,8 @@ async function runTests(browser, accDoc) {
/**
* Test accessible boundaries when page is zoomed
*/
addAccessibleTask(`
addAccessibleTask(
`
<p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
<p id="p2">para 2</p>
<button id="b1">Hello</button>

Просмотреть файл

@ -16,8 +16,12 @@ async function getContentBoundsForDOMElm(browser, id) {
}
async function testContentBounds(browser, acc) {
let [expectedX, expectedY, expectedWidth, expectedHeight] =
await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc));
let [
expectedX,
expectedY,
expectedWidth,
expectedHeight,
] = await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc));
let contentDPR = await getContentDPR(browser);
let [x, y, width, height] = getBounds(acc, contentDPR);
@ -58,7 +62,8 @@ async function runTests(browser, accDoc) {
/**
* Test accessible boundaries when page is zoomed
*/
addAccessibleTask(`
addAccessibleTask(
`
<p id="p1">para 1</p><p id="p2">para 2</p>
<map name="atoz_map" id="map">
<area id="area1" href="http://mozilla.org"

Просмотреть файл

@ -15,18 +15,33 @@ async function runTests(browser, accDoc) {
let contentDPR = await getContentDPR(browser);
let [x, y, width, height] = getBounds(textNode, contentDPR);
testTextBounds(hyperTextNode, 0, -1, [x, y, width, height],
COORDTYPE_SCREEN_RELATIVE);
testTextBounds(
hyperTextNode,
0,
-1,
[x, y, width, height],
COORDTYPE_SCREEN_RELATIVE
);
}
async function testEmptyInputNode(id) {
let inputNode = findAccessibleChildByID(accDoc, id);
let [x, y, width, height] = getBounds(inputNode);
testTextBounds(inputNode, 0, -1, [x, y, width, height],
COORDTYPE_SCREEN_RELATIVE);
testTextBounds(inputNode, 0, 0, [x, y, width, height],
COORDTYPE_SCREEN_RELATIVE);
testTextBounds(
inputNode,
0,
-1,
[x, y, width, height],
COORDTYPE_SCREEN_RELATIVE
);
testTextBounds(
inputNode,
0,
0,
[x, y, width, height],
COORDTYPE_SCREEN_RELATIVE
);
}
loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR });
@ -49,8 +64,10 @@ async function runTests(browser, accDoc) {
/**
* Test the text range boundary when page is zoomed
*/
addAccessibleTask(`
addAccessibleTask(
`
<p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
<p id='p2'>ل</p>
<form><input id='i1' /></form>`, runTests
<form><input id='i1' /></form>`,
runTests
);

Просмотреть файл

@ -11,16 +11,24 @@
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR },
{ name: "layout.js", dir: MOCHITESTS_DIR }, "events.js");
loadScripts(
{ name: "common.js", dir: MOCHITESTS_DIR },
{ name: "layout.js", dir: MOCHITESTS_DIR },
"events.js"
);
/**
* Get content window DPR that can be different from parent window DPR.
*/
async function getContentDPR(browser) {
return ContentTask.spawn(browser, null, () => content.window.devicePixelRatio);
return ContentTask.spawn(
browser,
null,
() => content.window.devicePixelRatio
);
}

Просмотреть файл

@ -8,7 +8,8 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized");
@ -31,8 +32,12 @@ add_task(async function() {
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");

Просмотреть файл

@ -8,7 +8,8 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized");
@ -23,8 +24,12 @@ add_task(async function() {
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");

Просмотреть файл

@ -8,7 +8,8 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized");
@ -34,8 +35,12 @@ add_task(async function() {
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");

Просмотреть файл

@ -8,7 +8,8 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized");
@ -34,8 +35,12 @@ add_task(async function() {
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");

Просмотреть файл

@ -9,67 +9,77 @@ add_task(async function() {
await setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
"body"
);
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized");
await a11yInit;
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"><div id="div"></div></body>
</html>`
}, async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
</html>`,
},
async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let acc = docAcc.getChildAt(0);
ok(acc, "Accessible proxy is created");
let acc = docAcc.getChildAt(0);
ok(acc, "Accessible proxy is created");
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible proxy.
acc = null;
ok(!acc, "Accessible proxy is removed");
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible document proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible proxy.
acc = null;
ok(!acc, "Accessible proxy is removed");
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible document proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
});
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
}
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();

Просмотреть файл

@ -9,67 +9,77 @@ add_task(async function() {
await setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
"body"
);
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized");
await a11yInit;
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"><div id="div"></div></body>
</html>`
}, async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
</html>`,
},
async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let acc = docAcc.getChildAt(0);
ok(acc, "Accessible proxy is created");
let acc = docAcc.getChildAt(0);
ok(acc, "Accessible proxy is created");
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
acc = null;
ok(!acc, "Accessible proxy is removed");
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
acc = null;
ok(!acc, "Accessible proxy is removed");
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
});
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
}
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();

Просмотреть файл

@ -9,14 +9,16 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService1 = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService1, "Service initialized");
// Add another reference to a11y service. This will not trigger
// 'a11y-init-or-shutdown' event
let accService2 = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService2, "Service initialized");
info("Removing all service references");
@ -25,8 +27,12 @@ add_task(async function() {
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ?
resolve() : reject("Accessible service was shut down incorrectly")));
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
// Remove first a11y service reference.
accService1 = null;
ok(!accService1, "Service is removed");

Просмотреть файл

@ -8,65 +8,85 @@ add_task(async function() {
// Making sure that the e10s is enabled on Windows for testing.
await setE10sPrefs();
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body></body>
</html>`
}, async function(browser) {
info("Creating a service in parent and waiting for service to be created " +
"in content");
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
</html>`,
},
async function(browser) {
info(
"Creating a service in parent and waiting for service to be created " +
"in content"
);
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
info("Adding additional reference to accessibility service in content " +
"process");
// Add a new reference to the a11y service inside the content process.
loadFrameScripts(browser, `let accService = Components.classes[
info(
"Adding additional reference to accessibility service in content " +
"process"
);
// Add a new reference to the a11y service inside the content process.
loadFrameScripts(
browser,
`let accService = Components.classes[
'@mozilla.org/accessibilityService;1'].getService(
Components.interfaces.nsIAccessibilityService);`);
Components.interfaces.nsIAccessibilityService);`
);
info("Trying to shut down a service in content and making sure it stays " +
"alive as it was started by parent");
let contentCanShutdown = false;
// This promise will resolve only if contentCanShutdown flag is set to true.
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
// it can be shut down, the promise will reject.
let contentA11yShutdown = new Promise((resolve, reject) =>
shutdownPromise(browser).then(flag => contentCanShutdown ?
resolve() : reject("Accessible service was shut down incorrectly")));
// Remove a11y service reference in content and force garbage collection.
// This should not trigger shutdown since a11y was originally initialized by
// the main process.
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
info(
"Trying to shut down a service in content and making sure it stays " +
"alive as it was started by parent"
);
let contentCanShutdown = false;
// This promise will resolve only if contentCanShutdown flag is set to true.
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
// it can be shut down, the promise will reject.
let contentA11yShutdown = new Promise((resolve, reject) =>
shutdownPromise(browser).then(flag =>
contentCanShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
// Remove a11y service reference in content and force garbage collection.
// This should not trigger shutdown since a11y was originally initialized by
// the main process.
loadFrameScripts(
browser,
`accService = null; Components.utils.forceGC();`
);
// Have some breathing room between a11y service shutdowns.
await new Promise(resolve => executeSoon(resolve));
// Have some breathing room between a11y service shutdowns.
await new Promise(resolve => executeSoon(resolve));
info("Removing a service in parent");
// Now allow a11y service to shutdown in content.
contentCanShutdown = true;
// Remove the a11y service reference in the main process.
let parentA11yShutdown = shutdownPromise();
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should trigger shutdown in both parent and
// content.
forceGC();
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
info("Removing a service in parent");
// Now allow a11y service to shutdown in content.
contentCanShutdown = true;
// Remove the a11y service reference in the main process.
let parentA11yShutdown = shutdownPromise();
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should trigger shutdown in both parent and
// content.
forceGC();
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
// Unsetting e10s related preferences.
await unsetE10sPrefs();
});
// Unsetting e10s related preferences.
await unsetE10sPrefs();
}
);
});

Просмотреть файл

@ -7,7 +7,10 @@
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
add_task(async function testForceDisable() {
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled by default");
ok(
!Services.appinfo.accessibilityEnabled,
"Accessibility is disabled by default"
);
info("Reset force disabled preference");
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
@ -15,7 +18,8 @@ add_task(async function testForceDisable() {
info("Enable accessibility service via XPCOM");
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");
@ -27,12 +31,16 @@ add_task(async function testForceDisable() {
info("Attempt to get an instance of a11y service and call its method.");
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
try {
accService.getAccesssibleFor(document);
ok(false, "getAccesssibleFor should've triggered an exception.");
} catch (e) {
ok(true, "getAccesssibleFor triggers an exception as a11y service is shutdown.");
ok(
true,
"getAccesssibleFor triggers an exception as a11y service is shutdown."
);
}
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled");
@ -42,7 +50,8 @@ add_task(async function testForceDisable() {
info("Create a11y service again");
a11yInit = initPromise();
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");

Просмотреть файл

@ -10,54 +10,62 @@ add_task(async function() {
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized");
await a11yInit;
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body><div id="div" style="visibility: hidden;"></div></body>
</html>`
}, async function(browser) {
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, "div");
await invokeSetStyle(browser, "div", "visibility", "visible");
let showEvent = await onShow;
let divAcc = showEvent.accessible;
ok(divAcc, "Accessible proxy is created");
// Remove unnecessary dangling references
onShow = null;
showEvent = null;
forceGC();
</html>`,
},
async function(browser) {
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, "div");
await invokeSetStyle(browser, "div", "visibility", "visible");
let showEvent = await onShow;
let divAcc = showEvent.accessible;
ok(divAcc, "Accessible proxy is created");
// Remove unnecessary dangling references
onShow = null;
showEvent = null;
forceGC();
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
divAcc = null;
ok(!divAcc, "Accessible proxy is removed");
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
divAcc = null;
ok(!divAcc, "Accessible proxy is removed");
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
});
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
}
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();

Просмотреть файл

@ -9,55 +9,65 @@ add_task(async function() {
await setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
"body"
);
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized");
await a11yInit;
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"></body>
</html>`
}, async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
</html>`,
},
async function(browser) {
let docLoadedEvent = await docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, "Accessible document proxy is created");
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject("Accessible service was shut down incorrectly")));
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag =>
canShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
accService = null;
ok(!accService, "Service is removed");
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
await new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, "Accessible document proxy is removed");
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
});
// Force garbage collection that should now trigger shutdown.
forceGC();
await a11yShutdown;
}
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();

Просмотреть файл

@ -8,62 +8,114 @@ add_task(async function() {
// Making sure that the e10s is enabled on Windows for testing.
await setE10sPrefs();
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body></body>
</html>`
}, async function(browser) {
info("Creating a service in parent and waiting for service to be created " +
"in content");
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let parentConsumersChanged = a11yConsumersChangedPromise();
let contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: true, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers in parent are correct."));
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: false, MainProcess: true, PlatformAPI: false
}, "Accessibility service consumers in content are correct."));
</html>`,
},
async function(browser) {
info(
"Creating a service in parent and waiting for service to be created " +
"in content"
);
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let parentConsumersChanged = a11yConsumersChangedPromise();
let contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
await parentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: true,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers in parent are correct."
)
);
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: false,
MainProcess: true,
PlatformAPI: false,
},
"Accessibility service consumers in content are correct."
)
);
Assert.deepEqual(JSON.parse(accService.getConsumers()), {
XPCOM: true, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers in parent are correct.");
Assert.deepEqual(
JSON.parse(accService.getConsumers()),
{
XPCOM: true,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers in parent are correct."
);
info("Removing a service in parent and waiting for service to be shut " +
"down in content");
// Remove a11y service reference in the main process.
let parentA11yShutdown = shutdownPromise();
let contentA11yShutdown = shutdownPromise(browser);
parentConsumersChanged = a11yConsumersChangedPromise();
contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should trigger shutdown in both main and
// content process.
forceGC();
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: false, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers are correct."));
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: false, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers are correct."));
});
info(
"Removing a service in parent and waiting for service to be shut " +
"down in content"
);
// Remove a11y service reference in the main process.
let parentA11yShutdown = shutdownPromise();
let contentA11yShutdown = shutdownPromise(browser);
parentConsumersChanged = a11yConsumersChangedPromise();
contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should trigger shutdown in both main and
// content process.
forceGC();
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
await parentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: false,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers are correct."
)
);
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: false,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers are correct."
)
);
}
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();

Просмотреть файл

@ -8,33 +8,42 @@ add_task(async function() {
// Making sure that the e10s is enabled on Windows for testing.
await setE10sPrefs();
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body></body>
</html>`
}, async function(browser) {
info("Creating a service in content");
// Create a11y service in the content process.
let a11yInit = initPromise(browser);
loadFrameScripts(browser, `let accService = Components.classes[
</html>`,
},
async function(browser) {
info("Creating a service in content");
// Create a11y service in the content process.
let a11yInit = initPromise(browser);
loadFrameScripts(
browser,
`let accService = Components.classes[
'@mozilla.org/accessibilityService;1'].getService(
Components.interfaces.nsIAccessibilityService);`);
await a11yInit;
Components.interfaces.nsIAccessibilityService);`
);
await a11yInit;
info("Removing a service in content");
// Remove a11y service reference from the content process.
let a11yShutdown = shutdownPromise(browser);
// Force garbage collection that should trigger shutdown.
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
await a11yShutdown;
info("Removing a service in content");
// Remove a11y service reference from the content process.
let a11yShutdown = shutdownPromise(browser);
// Force garbage collection that should trigger shutdown.
loadFrameScripts(
browser,
`accService = null; Components.utils.forceGC();`
);
await a11yShutdown;
// Unsetting e10s related preferences.
await unsetE10sPrefs();
});
// Unsetting e10s related preferences.
await unsetE10sPrefs();
}
);
});

Просмотреть файл

@ -8,94 +8,165 @@ add_task(async function() {
// Making sure that the e10s is enabled on Windows for testing.
await setE10sPrefs();
await BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body></body>
</html>`
}, async function(browser) {
info("Creating a service in parent and waiting for service to be created " +
"in content");
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: false, MainProcess: true, PlatformAPI: false
}, "Accessibility service consumers in content are correct."));
</html>`,
},
async function(browser) {
info(
"Creating a service in parent and waiting for service to be created " +
"in content"
);
// Create a11y service in the main process. This will trigger creating of
// the a11y service in parent as well.
let parentA11yInit = initPromise();
let contentA11yInit = initPromise(browser);
let contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized in parent");
await Promise.all([parentA11yInit, contentA11yInit]);
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: false,
MainProcess: true,
PlatformAPI: false,
},
"Accessibility service consumers in content are correct."
)
);
info("Adding additional reference to accessibility service in content " +
"process");
contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
// Add a new reference to the a11y service inside the content process.
loadFrameScripts(browser, `var accService = Components.classes[
info(
"Adding additional reference to accessibility service in content " +
"process"
);
contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
// Add a new reference to the a11y service inside the content process.
loadFrameScripts(
browser,
`var accService = Components.classes[
'@mozilla.org/accessibilityService;1'].getService(
Components.interfaces.nsIAccessibilityService);`);
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: true, MainProcess: true, PlatformAPI: false
}, "Accessibility service consumers in content are correct."));
Components.interfaces.nsIAccessibilityService);`
);
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: true,
MainProcess: true,
PlatformAPI: false,
},
"Accessibility service consumers in content are correct."
)
);
const contentConsumers = await ContentTask.spawn(browser, {}, () =>
accService.getConsumers());
Assert.deepEqual(JSON.parse(contentConsumers), {
XPCOM: true, MainProcess: true, PlatformAPI: false
}, "Accessibility service consumers in parent are correct.");
const contentConsumers = await ContentTask.spawn(browser, {}, () =>
accService.getConsumers()
);
Assert.deepEqual(
JSON.parse(contentConsumers),
{
XPCOM: true,
MainProcess: true,
PlatformAPI: false,
},
"Accessibility service consumers in parent are correct."
);
info("Shutting down a service in parent and making sure the one in " +
"content stays alive");
let contentCanShutdown = false;
let parentA11yShutdown = shutdownPromise();
contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
// This promise will resolve only if contentCanShutdown flag is set to true.
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
// it can be shut down, the promise will reject.
let contentA11yShutdown = new Promise((resolve, reject) =>
shutdownPromise(browser).then(flag => contentCanShutdown ?
resolve() : reject("Accessible service was shut down incorrectly")));
// Remove a11y service reference in the main process and force garbage
// collection. This should not trigger shutdown in content since a11y
// service is used by XPCOM.
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should not trigger shutdown because there
// is a reference in a content process.
forceGC();
loadFrameScripts(browser, `Components.utils.forceGC();`);
await parentA11yShutdown;
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: true, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers in content are correct."));
info(
"Shutting down a service in parent and making sure the one in " +
"content stays alive"
);
let contentCanShutdown = false;
let parentA11yShutdown = shutdownPromise();
contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
// This promise will resolve only if contentCanShutdown flag is set to true.
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
// it can be shut down, the promise will reject.
let contentA11yShutdown = new Promise((resolve, reject) =>
shutdownPromise(browser).then(flag =>
contentCanShutdown
? resolve()
: reject("Accessible service was shut down incorrectly")
)
);
// Remove a11y service reference in the main process and force garbage
// collection. This should not trigger shutdown in content since a11y
// service is used by XPCOM.
accService = null;
ok(!accService, "Service is removed in parent");
// Force garbage collection that should not trigger shutdown because there
// is a reference in a content process.
forceGC();
loadFrameScripts(browser, `Components.utils.forceGC();`);
await parentA11yShutdown;
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: true,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers in content are correct."
)
);
// Have some breathing room between a11y service shutdowns.
await new Promise(resolve => executeSoon(resolve));
// Have some breathing room between a11y service shutdowns.
await new Promise(resolve => executeSoon(resolve));
info("Removing a service in content");
// Now allow a11y service to shutdown in content.
contentCanShutdown = true;
contentConsumersChanged =
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
// Remove last reference to a11y service in content and force garbage
// collection that should trigger shutdown.
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
await contentA11yShutdown;
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
XPCOM: false, MainProcess: false, PlatformAPI: false
}, "Accessibility service consumers in content are correct."));
info("Removing a service in content");
// Now allow a11y service to shutdown in content.
contentCanShutdown = true;
contentConsumersChanged = ContentTask.spawn(
browser,
{},
a11yConsumersChangedPromise
);
// Remove last reference to a11y service in content and force garbage
// collection that should trigger shutdown.
loadFrameScripts(
browser,
`accService = null; Components.utils.forceGC();`
);
await contentA11yShutdown;
await contentConsumersChanged.then(data =>
Assert.deepEqual(
data,
{
XPCOM: false,
MainProcess: false,
PlatformAPI: false,
},
"Accessibility service consumers in content are correct."
)
);
// Unsetting e10s related preferences.
await unsetE10sPrefs();
});
// Unsetting e10s related preferences.
await unsetE10sPrefs();
}
);
});

Просмотреть файл

@ -11,7 +11,8 @@ add_task(async function() {
(function() {
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
ok(accService, "Service initialized");
})();

Просмотреть файл

@ -9,7 +9,8 @@ add_task(async function() {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized");
@ -26,7 +27,8 @@ add_task(async function() {
// Re-create a11y service.
a11yInit = initPromise();
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await a11yInit;
ok(accService, "Service initialized again");

Просмотреть файл

@ -17,9 +17,9 @@ const defaultAttributes = {
"margin-left": "0px",
"text-align": "start",
"text-indent": "0px",
"id": "textbox",
"tag": "input",
"display": "inline-block"
id: "textbox",
tag: "input",
display: "inline-block",
};
/**
@ -35,64 +35,81 @@ const defaultAttributes = {
* waitFor {?Number} an optional event to wait for
* }
*/
const attributesTests = [{
desc: "Initiall accessible attributes",
expected: defaultAttributes,
unexpected: {
"line-number": "1",
"explicit-name": "true",
"container-live": "polite",
"live": "polite"
}
}, {
desc: "@line-number attribute is present when textbox is focused",
async action(browser) {
await invokeFocus(browser, "textbox");
const attributesTests = [
{
desc: "Initiall accessible attributes",
expected: defaultAttributes,
unexpected: {
"line-number": "1",
"explicit-name": "true",
"container-live": "polite",
live: "polite",
},
},
waitFor: EVENT_FOCUS,
expected: Object.assign({}, defaultAttributes, { "line-number": "1" }),
unexpected: {
"explicit-name": "true",
"container-live": "polite",
"live": "polite"
}
}, {
desc: "@aria-live sets container-live and live attributes",
attrs: [{
attr: "aria-live",
value: "polite"
}],
expected: Object.assign({}, defaultAttributes, {
"line-number": "1",
"container-live": "polite",
"live": "polite"
}),
unexpected: {
"explicit-name": "true"
}
}, {
desc: "@title attribute sets explicit-name attribute to true",
attrs: [{
attr: "title",
value: "textbox"
}],
expected: Object.assign({}, defaultAttributes, {
"line-number": "1",
"explicit-name": "true",
"container-live": "polite",
"live": "polite"
}),
unexpected: {}
}];
{
desc: "@line-number attribute is present when textbox is focused",
async action(browser) {
await invokeFocus(browser, "textbox");
},
waitFor: EVENT_FOCUS,
expected: Object.assign({}, defaultAttributes, { "line-number": "1" }),
unexpected: {
"explicit-name": "true",
"container-live": "polite",
live: "polite",
},
},
{
desc: "@aria-live sets container-live and live attributes",
attrs: [
{
attr: "aria-live",
value: "polite",
},
],
expected: Object.assign({}, defaultAttributes, {
"line-number": "1",
"container-live": "polite",
live: "polite",
}),
unexpected: {
"explicit-name": "true",
},
},
{
desc: "@title attribute sets explicit-name attribute to true",
attrs: [
{
attr: "title",
value: "textbox",
},
],
expected: Object.assign({}, defaultAttributes, {
"line-number": "1",
"explicit-name": "true",
"container-live": "polite",
live: "polite",
}),
unexpected: {},
},
];
/**
* Test caching of accessible object attributes
*/
addAccessibleTask(`
addAccessibleTask(
`
<input id="textbox" value="hello">`,
async function(browser, accDoc) {
let textbox = findAccessibleChildByID(accDoc, "textbox");
for (let { desc, action, attrs, expected, waitFor, unexpected } of attributesTests) {
for (let {
desc,
action,
attrs,
expected,
waitFor,
unexpected,
} of attributesTests) {
info(desc);
let onUpdate;

Просмотреть файл

@ -17,123 +17,173 @@ loadScripts({ name: "name.js", dir: MOCHITESTS_DIR });
* attributes are updated
* }
*/
const tests = [{
desc: "No description when there are no @alt, @title and @aria-describedby",
expected: ""
}, {
desc: "Description from @aria-describedby attribute",
attrs: [{
attr: "aria-describedby",
value: "description"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "aria description"
}, {
desc: "No description from @aria-describedby since it is the same as the " +
"@alt attribute which is used as the name",
attrs: [{
attr: "alt",
value: "aria description"
}],
waitFor: [[EVENT_REORDER, "body"]],
expected: ""
}, {
desc: "Description from @aria-describedby attribute when @alt and " +
"@aria-describedby are not the same",
attrs: [{
attr: "aria-describedby",
value: "description2"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "another description"
}, {
desc: "Description from @aria-describedby attribute when @title (used for " +
"name) and @aria-describedby are not the same",
attrs: [{
attr: "alt"
}, {
attr: "title",
value: "title"
}],
waitFor: [[EVENT_REORDER, "body"]],
expected: "another description"
}, {
desc: "No description from @aria-describedby since it is the same as the " +
"@title attribute which is used as the name",
attrs: [{
attr: "title",
value: "another description"
}],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: ""
}, {
desc: "No description with only @title attribute which is used as the name",
attrs: [{
attr: "aria-describedby"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: ""
}, {
desc: "Description from @title attribute when @alt and @atitle are not the " +
"same",
attrs: [{
attr: "alt",
value: "aria description"
}],
waitFor: [[EVENT_REORDER, "body"]],
expected: "another description"
}, {
desc: "No description from @title since it is the same as the @alt " +
"attribute which is used as the name",
attrs: [{
attr: "alt",
value: "another description"
}],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: ""
}, {
desc: "No description from @aria-describedby since it is the same as the " +
"@alt (used for name) and @title attributes",
attrs: [{
attr: "aria-describedby",
value: "description2"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: ""
}, {
desc: "Description from @aria-describedby attribute when it is different " +
"from @alt (used for name) and @title attributes",
attrs: [{
attr: "aria-describedby",
value: "description"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "aria description"
}, {
desc: "No description from @aria-describedby since it is the same as the " +
"@alt attribute (used for name) but different from title",
attrs: [{
attr: "alt",
value: "aria description"
}],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: ""
}, {
desc: "Description from @aria-describedby attribute when @alt (used for " +
"name) and @aria-describedby are not the same but @title and " +
"aria-describedby are",
attrs: [{
attr: "aria-describedby",
value: "description2"
}],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "another description"
}];
const tests = [
{
desc: "No description when there are no @alt, @title and @aria-describedby",
expected: "",
},
{
desc: "Description from @aria-describedby attribute",
attrs: [
{
attr: "aria-describedby",
value: "description",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "aria description",
},
{
desc:
"No description from @aria-describedby since it is the same as the " +
"@alt attribute which is used as the name",
attrs: [
{
attr: "alt",
value: "aria description",
},
],
waitFor: [[EVENT_REORDER, "body"]],
expected: "",
},
{
desc:
"Description from @aria-describedby attribute when @alt and " +
"@aria-describedby are not the same",
attrs: [
{
attr: "aria-describedby",
value: "description2",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "another description",
},
{
desc:
"Description from @aria-describedby attribute when @title (used for " +
"name) and @aria-describedby are not the same",
attrs: [
{
attr: "alt",
},
{
attr: "title",
value: "title",
},
],
waitFor: [[EVENT_REORDER, "body"]],
expected: "another description",
},
{
desc:
"No description from @aria-describedby since it is the same as the " +
"@title attribute which is used as the name",
attrs: [
{
attr: "title",
value: "another description",
},
],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: "",
},
{
desc: "No description with only @title attribute which is used as the name",
attrs: [
{
attr: "aria-describedby",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "",
},
{
desc:
"Description from @title attribute when @alt and @atitle are not the " +
"same",
attrs: [
{
attr: "alt",
value: "aria description",
},
],
waitFor: [[EVENT_REORDER, "body"]],
expected: "another description",
},
{
desc:
"No description from @title since it is the same as the @alt " +
"attribute which is used as the name",
attrs: [
{
attr: "alt",
value: "another description",
},
],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: "",
},
{
desc:
"No description from @aria-describedby since it is the same as the " +
"@alt (used for name) and @title attributes",
attrs: [
{
attr: "aria-describedby",
value: "description2",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "",
},
{
desc:
"Description from @aria-describedby attribute when it is different " +
"from @alt (used for name) and @title attributes",
attrs: [
{
attr: "aria-describedby",
value: "description",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "aria description",
},
{
desc:
"No description from @aria-describedby since it is the same as the " +
"@alt attribute (used for name) but different from title",
attrs: [
{
attr: "alt",
value: "aria description",
},
],
waitFor: [[EVENT_NAME_CHANGE, "image"]],
expected: "",
},
{
desc:
"Description from @aria-describedby attribute when @alt (used for " +
"name) and @aria-describedby are not the same but @title and " +
"aria-describedby are",
attrs: [
{
attr: "aria-describedby",
value: "description2",
},
],
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
expected: "another description",
},
];
/**
* Test caching of accessible object description
*/
addAccessibleTask(`
addAccessibleTask(
`
<p id="description">aria description</p>
<p id="description2">another description</p>
<img id="image" />`,

Просмотреть файл

@ -31,33 +31,59 @@ const HTMLControlHeadRule = [...ARIARule, { elm: "label", isSibling: true }];
const rules = {
CSSContent: [{ elm: "style", isSibling: true }, { fromsubtree: true }],
HTMLARIAGridCell: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
HTMLControl: [...HTMLControlHeadRule, { fromsubtree: true },
{ attr: "title" }],
HTMLControl: [
...HTMLControlHeadRule,
{ fromsubtree: true },
{ attr: "title" },
],
HTMLElm: [...ARIARule, { attr: "title" }],
HTMLImg: [...ARIARule, { attr: "alt", recreated: true }, { attr: "title" }],
HTMLImgEmptyAlt: [...ARIARule, { attr: "title" }, { attr: "alt" }],
HTMLInputButton: [...HTMLControlHeadRule, { attr: "value" },
{ attr: "title" }],
HTMLInputImage: [...HTMLControlHeadRule, { attr: "alt", recreated: true },
{ attr: "value", recreated: true }, { attr: "title" }],
HTMLInputImageNoValidSrc: [...HTMLControlHeadRule,
{ attr: "alt", recreated: true }, { attr: "value", recreated: true }],
HTMLInputReset: [...HTMLControlHeadRule,
{ attr: "value", textchanged: true }],
HTMLInputSubmit: [...HTMLControlHeadRule,
{ attr: "value", textchanged: true }],
HTMLInputButton: [
...HTMLControlHeadRule,
{ attr: "value" },
{ attr: "title" },
],
HTMLInputImage: [
...HTMLControlHeadRule,
{ attr: "alt", recreated: true },
{ attr: "value", recreated: true },
{ attr: "title" },
],
HTMLInputImageNoValidSrc: [
...HTMLControlHeadRule,
{ attr: "alt", recreated: true },
{ attr: "value", recreated: true },
],
HTMLInputReset: [
...HTMLControlHeadRule,
{ attr: "value", textchanged: true },
],
HTMLInputSubmit: [
...HTMLControlHeadRule,
{ attr: "value", textchanged: true },
],
HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
HTMLLinkImage: [...ARIARule, { elm: "img" }, { attr: "title" }],
HTMLOption: [...ARIARule, { attr: "label" }, { fromsubtree: true },
{ attr: "title" }],
HTMLTable: [...ARIARule, { elm: "caption" }, { attr: "summary" },
{ attr: "title" }]
HTMLOption: [
...ARIARule,
{ attr: "label" },
{ fromsubtree: true },
{ attr: "title" },
],
HTMLTable: [
...ARIARule,
{ elm: "caption" },
{ attr: "summary" },
{ attr: "title" },
],
};
const markupTests = [{
id: "btn",
ruleset: "HTMLControl",
markup: `
const markupTests = [
{
id: "btn",
ruleset: "HTMLControl",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn">test4</label>
@ -65,11 +91,12 @@ const markupTests = [{
aria-label="test1"
aria-labelledby="l1 l2"
title="test5">press me</button>`,
expected: ["test2 test3", "test1", "test4", "press me", "test5"]
}, {
id: "btn",
ruleset: "HTMLInputButton",
markup: `
expected: ["test2 test3", "test1", "test4", "press me", "test5"],
},
{
id: "btn",
ruleset: "HTMLInputButton",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn">test4</label>
@ -82,12 +109,18 @@ const markupTests = [{
src="no name from src"
data="no name from data"
title="name from title"/>`,
expected: ["test2 test3", "test1", "test4", "name from value",
"name from title"]
}, {
id: "btn-submit",
ruleset: "HTMLInputSubmit",
markup: `
expected: [
"test2 test3",
"test1",
"test4",
"name from value",
"name from title",
],
},
{
id: "btn-submit",
ruleset: "HTMLInputSubmit",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn-submit">test4</label>
@ -100,11 +133,12 @@ const markupTests = [{
src="no name from src"
data="no name from data"
title="no name from title"/>`,
expected: ["test2 test3", "test1", "test4", "name from value"]
}, {
id: "btn-reset",
ruleset: "HTMLInputReset",
markup: `
expected: ["test2 test3", "test1", "test4", "name from value"],
},
{
id: "btn-reset",
ruleset: "HTMLInputReset",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn-reset">test4</label>
@ -117,11 +151,12 @@ const markupTests = [{
src="no name from src"
data="no name from data"
title="no name from title"/>`,
expected: ["test2 test3", "test1", "test4", "name from value"]
}, {
id: "btn-image",
ruleset: "HTMLInputImage",
markup: `
expected: ["test2 test3", "test1", "test4", "name from value"],
},
{
id: "btn-image",
ruleset: "HTMLInputImage",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn-image">test4</label>
@ -134,12 +169,19 @@ const markupTests = [{
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"
data="no name from data"
title="name from title"/>`,
expected: ["test2 test3", "test1", "test4", "name from alt",
"name from value", "name from title"]
}, {
id: "btn-image",
ruleset: "HTMLInputImageNoValidSrc",
markup: `
expected: [
"test2 test3",
"test1",
"test4",
"name from alt",
"name from value",
"name from title",
],
},
{
id: "btn-image",
ruleset: "HTMLInputImageNoValidSrc",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="btn-image">test4</label>
@ -151,12 +193,18 @@ const markupTests = [{
value="name from value"
data="no name from data"
title="no name from title"/>`,
expected: ["test2 test3", "test1", "test4", "name from alt",
"name from value"]
}, {
id: "opt",
ruleset: "HTMLOption",
markup: `
expected: [
"test2 test3",
"test1",
"test4",
"name from alt",
"name from value",
],
},
{
id: "opt",
ruleset: "HTMLOption",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<select>
@ -167,11 +215,12 @@ const markupTests = [{
title="test5">option1</option>
<option>option2</option>
</select>`,
expected: ["test2 test3", "test1", "test4", "option1", "test5"]
}, {
id: "img",
ruleset: "HTMLImg",
markup: `
expected: ["test2 test3", "test1", "test4", "option1", "test5"],
},
{
id: "img",
ruleset: "HTMLImg",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<img id="img"
@ -180,11 +229,17 @@ const markupTests = [{
alt="Mozilla logo"
title="This is a logo"
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
expected: ["test2 test3", "Logo of Mozilla", "Mozilla logo", "This is a logo"]
}, {
id: "imgemptyalt",
ruleset: "HTMLImgEmptyAlt",
markup: `
expected: [
"test2 test3",
"Logo of Mozilla",
"Mozilla logo",
"This is a logo",
],
},
{
id: "imgemptyalt",
ruleset: "HTMLImgEmptyAlt",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<img id="imgemptyalt"
@ -193,11 +248,12 @@ const markupTests = [{
title="This is a logo"
alt=""
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
expected: ["test2 test3", "Logo of Mozilla", "This is a logo", ""]
}, {
id: "tc",
ruleset: "HTMLElm",
markup: `
expected: ["test2 test3", "Logo of Mozilla", "This is a logo", ""],
},
{
id: "tc",
ruleset: "HTMLElm",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="tc">test4</label>
@ -215,11 +271,12 @@ const markupTests = [{
</td>
</tr>
</table>`,
expected: ["test2 test3", "test1", "test5"]
}, {
id: "gc",
ruleset: "HTMLARIAGridCell",
markup: `
expected: ["test2 test3", "test1", "test5"],
},
{
id: "gc",
ruleset: "HTMLARIAGridCell",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<label for="gc">test4</label>
@ -239,13 +296,17 @@ const markupTests = [{
</td>
</tr>
</table>`,
expected: ["test2 test3", "test1",
"This is a paragraph This is a link \u2022 Listitem1 \u2022 Listitem2",
"This is a paragraph This is a link This is a list"]
}, {
id: "t",
ruleset: "HTMLTable",
markup: `
expected: [
"test2 test3",
"test1",
"This is a paragraph This is a link \u2022 Listitem1 \u2022 Listitem2",
"This is a paragraph This is a link This is a list",
],
},
{
id: "t",
ruleset: "HTMLTable",
markup: `
<span id="l1">lby_tst6_1</span>
<span id="l2">lby_tst6_2</span>
<label for="t">label_tst6</label>
@ -260,56 +321,65 @@ const markupTests = [{
<td>cell2</td>
</tr>
</table>`,
expected: ["lby_tst6_1 lby_tst6_2", "arialabel_tst6", "caption_tst6",
"summary_tst6", "title_tst6"]
}, {
id: "btn",
ruleset: "CSSContent",
markup: `
expected: [
"lby_tst6_1 lby_tst6_2",
"arialabel_tst6",
"caption_tst6",
"summary_tst6",
"title_tst6",
],
},
{
id: "btn",
ruleset: "CSSContent",
markup: `
<style>
button::before {
content: "do not ";
}
</style>
<button id="btn">press me</button>`,
expected: ["do not press me", "press me"]
}, {
// TODO: uncomment when Bug-1256382 is resoved.
// id: 'li',
// ruleset: 'CSSContent',
// markup: `
// <style>
// ul {
// list-style-type: decimal;
// }
// </style>
// <ul id="ul">
// <li id="li">Listitem</li>
// </ul>`,
// expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
// }, {
id: "a",
ruleset: "HTMLLink",
markup: `
expected: ["do not press me", "press me"],
},
{
// TODO: uncomment when Bug-1256382 is resoved.
// id: 'li',
// ruleset: 'CSSContent',
// markup: `
// <style>
// ul {
// list-style-type: decimal;
// }
// </style>
// <ul id="ul">
// <li id="li">Listitem</li>
// </ul>`,
// expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
// }, {
id: "a",
ruleset: "HTMLLink",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<a id="a"
aria-label="test1"
aria-labelledby="l1 l2"
title="test4">test5</a>`,
expected: ["test2 test3", "test1", "test5", "test4"]
}, {
id: "a-img",
ruleset: "HTMLLinkImage",
markup: `
expected: ["test2 test3", "test1", "test5", "test4"],
},
{
id: "a-img",
ruleset: "HTMLLinkImage",
markup: `
<span id="l1">test2</span>
<span id="l2">test3</span>
<a id="a-img"
aria-label="test1"
aria-labelledby="l1 l2"
title="test4"><img alt="test5"/></a>`,
expected: ["test2 test3", "test1", "test5", "test4"]
}];
expected: ["test2 test3", "test1", "test5", "test4"],
},
];
/**
* Test accessible name that is calculated from an attribute, remove the
@ -325,16 +395,23 @@ const markupTests = [{
* @param {[type]} expected expected name value
*/
async function testAttrRule(browser, target, rule, expected) {
let {id, parent, acc} = target;
let {recreated, textchanged, attr} = rule;
let { id, parent, acc } = target;
let { recreated, textchanged, attr } = rule;
testName(acc, expected);
if (recreated || textchanged) {
let [event] = await contentSpawnMutation(browser, {
expected: [recreated ? [EVENT_REORDER, parent] : [EVENT_TEXT_INSERTED, id]]
}, ([contentId, contentAttr]) =>
content.document.getElementById(contentId).removeAttribute(contentAttr), [id, attr]);
let [event] = await contentSpawnMutation(
browser,
{
expected: [
recreated ? [EVENT_REORDER, parent] : [EVENT_TEXT_INSERTED, id],
],
},
([contentId, contentAttr]) =>
content.document.getElementById(contentId).removeAttribute(contentAttr),
[id, attr]
);
// Update accessible just in case it is now defunct.
target.acc = findAccessibleChildByID(event.accessible, id);
@ -356,13 +433,18 @@ async function testAttrRule(browser, target, rule, expected) {
* @param {[type]} expected expected name value
*/
async function testElmRule(browser, target, rule, expected) {
let {id, parent, acc} = target;
let {isSibling, elm} = rule;
let { id, parent, acc } = target;
let { isSibling, elm } = rule;
testName(acc, expected);
let [event] = await contentSpawnMutation(browser, {
expected: [[EVENT_REORDER, isSibling ? parent : id]]
}, contentElm => content.document.querySelector(`${contentElm}`).remove(), elm);
let [event] = await contentSpawnMutation(
browser,
{
expected: [[EVENT_REORDER, isSibling ? parent : id]],
},
contentElm => content.document.querySelector(`${contentElm}`).remove(),
elm
);
// Update accessible just in case it is now defunct.
target.acc = findAccessibleChildByID(event.accessible, id);
@ -381,17 +463,22 @@ async function testElmRule(browser, target, rule, expected) {
* @param {[type]} expected expected name value
*/
async function testSubtreeRule(browser, target, rule, expected) {
let {id, acc} = target;
let { id, acc } = target;
testName(acc, expected);
let [event] = await contentSpawnMutation(browser, {
expected: [[EVENT_REORDER, id]]
}, contentId => {
let elm = content.document.getElementById(contentId);
while (elm.firstChild) {
elm.firstChild.remove();
}
}, id);
let [event] = await contentSpawnMutation(
browser,
{
expected: [[EVENT_REORDER, id]],
},
contentId => {
let elm = content.document.getElementById(contentId);
while (elm.firstChild) {
elm.firstChild.remove();
}
},
id
);
// Update accessible just in case it is now defunct.
target.acc = findAccessibleChildByID(event.accessible, id);
@ -430,4 +517,5 @@ markupTests.forEach(({ id, ruleset, markup, expected }) =>
let parent = getAccessibleDOMNodeID(acc.parent);
let target = { id, parent, acc };
await testNameRule(browser, target, rules[ruleset], expected);
}));
})
);

Просмотреть файл

@ -19,10 +19,16 @@ const attrRelationsSpec = [
["aria-labelledby", RELATION_LABELLED_BY, RELATION_LABEL_FOR],
["aria-describedby", RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR],
["aria-controls", RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY],
["aria-flowto", RELATION_FLOWS_TO, RELATION_FLOWS_FROM]
["aria-flowto", RELATION_FLOWS_TO, RELATION_FLOWS_FROM],
];
async function testRelated(browser, accDoc, attr, hostRelation, dependantRelation) {
async function testRelated(
browser,
accDoc,
attr,
hostRelation,
dependantRelation
) {
let host = findAccessibleChildByID(accDoc, "host");
let dependant1 = findAccessibleChildByID(accDoc, "dependant1");
let dependant2 = findAccessibleChildByID(accDoc, "dependant2");
@ -36,22 +42,27 @@ async function testRelated(browser, accDoc, attr, hostRelation, dependantRelatio
* and host respectively.
* }
*/
const tests = [{
desc: "No attribute",
expected: [ null, null, null ]
}, {
desc: "Set attribute",
attrs: [{ key: attr, value: "dependant1" }],
expected: [ host, null, dependant1 ]
}, {
desc: "Change attribute",
attrs: [{ key: attr, value: "dependant2" }],
expected: [ null, host, dependant2 ]
}, {
desc: "Remove attribute",
attrs: [{ key: attr }],
expected: [ null, null, null ]
}];
const tests = [
{
desc: "No attribute",
expected: [null, null, null],
},
{
desc: "Set attribute",
attrs: [{ key: attr, value: "dependant1" }],
expected: [host, null, dependant1],
},
{
desc: "Change attribute",
attrs: [{ key: attr, value: "dependant2" }],
expected: [null, host, dependant2],
},
{
desc: "Remove attribute",
attrs: [{ key: attr }],
expected: [null, null, null],
},
];
for (let { desc, attrs, expected } of tests) {
info(desc);
@ -71,7 +82,8 @@ async function testRelated(browser, accDoc, attr, hostRelation, dependantRelatio
/**
* Test caching of relations between accessible objects.
*/
addAccessibleTask(`
addAccessibleTask(
`
<div id="dependant1">label</div>
<div id="dependant2">label2</div>
<div role="checkbox" id="host"></div>`,

Просмотреть файл

@ -6,8 +6,10 @@
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR }
);
/**
* Test data has the format of:
@ -26,70 +28,101 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
*/
// State caching tests for attribute changes
const attributeTests = [{
desc: "Checkbox with @checked attribute set to true should have checked " +
"state",
attrs: [{
attr: "checked",
value: "true"
}],
expected: [STATE_CHECKED, 0]
}, {
desc: "Checkbox with no @checked attribute should not have checked state",
attrs: [{
attr: "checked"
}],
expected: [0, 0, STATE_CHECKED]
}];
const attributeTests = [
{
desc:
"Checkbox with @checked attribute set to true should have checked " +
"state",
attrs: [
{
attr: "checked",
value: "true",
},
],
expected: [STATE_CHECKED, 0],
},
{
desc: "Checkbox with no @checked attribute should not have checked state",
attrs: [
{
attr: "checked",
},
],
expected: [0, 0, STATE_CHECKED],
},
];
// State caching tests for ARIA changes
const ariaTests = [{
desc: "File input has busy state when @aria-busy attribute is set to true",
attrs: [{
attr: "aria-busy",
value: "true"
}],
expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID]
}, {
desc: "File input has required state when @aria-required attribute is set " +
"to true",
attrs: [{
attr: "aria-required",
value: "true"
}],
expected: [STATE_REQUIRED, 0, STATE_INVALID]
}, {
desc: "File input has invalid state when @aria-invalid attribute is set to " +
"true",
attrs: [{
attr: "aria-invalid",
value: "true"
}],
expected: [STATE_INVALID, 0]
}];
const ariaTests = [
{
desc: "File input has busy state when @aria-busy attribute is set to true",
attrs: [
{
attr: "aria-busy",
value: "true",
},
],
expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID],
},
{
desc:
"File input has required state when @aria-required attribute is set " +
"to true",
attrs: [
{
attr: "aria-required",
value: "true",
},
],
expected: [STATE_REQUIRED, 0, STATE_INVALID],
},
{
desc:
"File input has invalid state when @aria-invalid attribute is set to " +
"true",
attrs: [
{
attr: "aria-invalid",
value: "true",
},
],
expected: [STATE_INVALID, 0],
},
];
// Extra state caching tests
const extraStateTests = [{
desc: "Input has no extra enabled state when aria and native disabled " +
"attributes are set at once",
attrs: [{
attr: "aria-disabled",
value: "true"
}, {
attr: "disabled",
value: "true"
}],
expected: [0, 0, 0, EXT_STATE_ENABLED]
}, {
desc: "Input has an extra enabled state when aria and native disabled " +
"attributes are unset at once",
attrs: [{
attr: "aria-disabled"
}, {
attr: "disabled"
}],
expected: [0, EXT_STATE_ENABLED]
}];
const extraStateTests = [
{
desc:
"Input has no extra enabled state when aria and native disabled " +
"attributes are set at once",
attrs: [
{
attr: "aria-disabled",
value: "true",
},
{
attr: "disabled",
value: "true",
},
],
expected: [0, 0, 0, EXT_STATE_ENABLED],
},
{
desc:
"Input has an extra enabled state when aria and native disabled " +
"attributes are unset at once",
attrs: [
{
attr: "aria-disabled",
},
{
attr: "disabled",
},
],
expected: [0, EXT_STATE_ENABLED],
},
];
async function runStateTests(browser, accDoc, id, tests) {
let acc = findAccessibleChildByID(accDoc, id);
@ -107,7 +140,8 @@ async function runStateTests(browser, accDoc, id, tests) {
/**
* Test caching of accessible object states
*/
addAccessibleTask(`
addAccessibleTask(
`
<input id="checkbox" type="checkbox">
<input id="file" type="file">
<input id="text">`,

Просмотреть файл

@ -18,102 +18,130 @@ loadScripts({ name: "value.js", dir: MOCHITESTS_DIR });
* waitFor {?Number} an optional value change event to wait for
* }
*/
const valueTests = [{
desc: "Initially value is set to 1st element of select",
id: "select",
expected: "1st"
}, {
desc: "Value should update to 3rd when 3 is pressed",
id: "select",
async action(browser) {
await invokeFocus(browser, "select");
await BrowserTestUtils.synthesizeKey("3", {}, browser);
const valueTests = [
{
desc: "Initially value is set to 1st element of select",
id: "select",
expected: "1st",
},
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: "3rd"
}, {
desc: "Initially value is set to @aria-valuenow for slider",
id: "slider",
expected: ["5", 5, 0, 7, 0]
}, {
desc: "Value should change when @aria-valuenow is updated",
id: "slider",
attrs: [{
attr: "aria-valuenow",
value: "6"
}],
waitFor: EVENT_VALUE_CHANGE,
expected: ["6", 6, 0, 7, 0]
}, {
desc: "Value should change when @aria-valuetext is set",
id: "slider",
attrs: [{
attr: "aria-valuetext",
value: "plain"
}],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: ["plain", 6, 0, 7, 0]
}, {
desc: "Value should change when @aria-valuetext is updated",
id: "slider",
attrs: [{
attr: "aria-valuetext",
value: "hey!"
}],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: ["hey!", 6, 0, 7, 0]
}, {
desc: "Value should change to @aria-valuetext when @aria-valuenow is removed",
id: "slider",
attrs: [{
attr: "aria-valuenow"
}],
expected: ["hey!", 0, 0, 7, 0]
}, {
desc: "Initially value is not set for combobox",
id: "combobox",
expected: ""
}, {
desc: "Value should change when @value attribute is updated",
id: "combobox",
attrs: [{
attr: "value",
value: "hello"
}],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: "hello"
}, {
desc: "Initially value corresponds to @value attribute for progress",
id: "progress",
expected: "22%"
}, {
desc: "Value should change when @value attribute is updated",
id: "progress",
attrs: [{
attr: "value",
value: "50"
}],
waitFor: EVENT_VALUE_CHANGE,
expected: "50%"
}, {
desc: "Initially value corresponds to @value attribute for range",
id: "range",
expected: "6"
}, {
desc: "Value should change when slider is moved",
id: "range",
async action(browser) {
await invokeFocus(browser, "range");
await BrowserTestUtils.synthesizeKey("VK_LEFT", {}, browser);
{
desc: "Value should update to 3rd when 3 is pressed",
id: "select",
async action(browser) {
await invokeFocus(browser, "select");
await BrowserTestUtils.synthesizeKey("3", {}, browser);
},
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: "3rd",
},
waitFor: EVENT_VALUE_CHANGE,
expected: "5"
}];
{
desc: "Initially value is set to @aria-valuenow for slider",
id: "slider",
expected: ["5", 5, 0, 7, 0],
},
{
desc: "Value should change when @aria-valuenow is updated",
id: "slider",
attrs: [
{
attr: "aria-valuenow",
value: "6",
},
],
waitFor: EVENT_VALUE_CHANGE,
expected: ["6", 6, 0, 7, 0],
},
{
desc: "Value should change when @aria-valuetext is set",
id: "slider",
attrs: [
{
attr: "aria-valuetext",
value: "plain",
},
],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: ["plain", 6, 0, 7, 0],
},
{
desc: "Value should change when @aria-valuetext is updated",
id: "slider",
attrs: [
{
attr: "aria-valuetext",
value: "hey!",
},
],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: ["hey!", 6, 0, 7, 0],
},
{
desc:
"Value should change to @aria-valuetext when @aria-valuenow is removed",
id: "slider",
attrs: [
{
attr: "aria-valuenow",
},
],
expected: ["hey!", 0, 0, 7, 0],
},
{
desc: "Initially value is not set for combobox",
id: "combobox",
expected: "",
},
{
desc: "Value should change when @value attribute is updated",
id: "combobox",
attrs: [
{
attr: "value",
value: "hello",
},
],
waitFor: EVENT_TEXT_VALUE_CHANGE,
expected: "hello",
},
{
desc: "Initially value corresponds to @value attribute for progress",
id: "progress",
expected: "22%",
},
{
desc: "Value should change when @value attribute is updated",
id: "progress",
attrs: [
{
attr: "value",
value: "50",
},
],
waitFor: EVENT_VALUE_CHANGE,
expected: "50%",
},
{
desc: "Initially value corresponds to @value attribute for range",
id: "range",
expected: "6",
},
{
desc: "Value should change when slider is moved",
id: "range",
async action(browser) {
await invokeFocus(browser, "range");
await BrowserTestUtils.synthesizeKey("VK_LEFT", {}, browser);
},
waitFor: EVENT_VALUE_CHANGE,
expected: "5",
},
];
/**
* Test caching of accessible object values
*/
addAccessibleTask(`
addAccessibleTask(
`
<div id="slider" role="slider" aria-valuenow="5"
aria-valuemin="0" aria-valuemax="7">slider</div>
<select id="select">

Просмотреть файл

@ -4,20 +4,23 @@
"use strict";
addAccessibleTask(`<p id="p">abc</p>`,
async function(browser, accDoc) {
let acc = findAccessibleChildByID(accDoc, "p");
let onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
acc.announce("please", nsIAccessibleAnnouncementEvent.POLITE);
let evt = await onAnnounce;
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
is(evt.announcement, "please", "announcement matches.");
is(evt.priority, nsIAccessibleAnnouncementEvent.POLITE, "priority matches");
addAccessibleTask(`<p id="p">abc</p>`, async function(browser, accDoc) {
let acc = findAccessibleChildByID(accDoc, "p");
let onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
acc.announce("please", nsIAccessibleAnnouncementEvent.POLITE);
let evt = await onAnnounce;
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
is(evt.announcement, "please", "announcement matches.");
is(evt.priority, nsIAccessibleAnnouncementEvent.POLITE, "priority matches");
onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
acc.announce("do it", nsIAccessibleAnnouncementEvent.ASSERTIVE);
evt = await onAnnounce;
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
is(evt.announcement, "do it", "announcement matches.");
is(evt.priority, nsIAccessibleAnnouncementEvent.ASSERTIVE, "priority matches");
});
onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
acc.announce("do it", nsIAccessibleAnnouncementEvent.ASSERTIVE);
evt = await onAnnounce;
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
is(evt.announcement, "do it", "announcement matches.");
is(
evt.priority,
nsIAccessibleAnnouncementEvent.ASSERTIVE,
"priority matches"
);
});

Просмотреть файл

@ -8,12 +8,13 @@
* Test caret move event and its interface:
* - caretOffset
*/
addAccessibleTask('<input id="textbox" value="hello"/>', async function(browser) {
addAccessibleTask('<input id="textbox" value="hello"/>', async function(
browser
) {
let onCaretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, "textbox");
await invokeFocus(browser, "textbox");
let event = await onCaretMoved;
let caretMovedEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
is(caretMovedEvent.caretOffset, 5,
"Correct caret offset.");
is(caretMovedEvent.caretOffset, 5, "Correct caret offset.");
});

Просмотреть файл

@ -10,7 +10,8 @@
* - targetNextSibling
* - targetPrevSibling
*/
addAccessibleTask(`
addAccessibleTask(
`
<div id="parent">
<div id="previous"></div>
<div id="to-hide"></div>
@ -23,11 +24,20 @@ addAccessibleTask(`
let event = await onHide;
let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent);
is(getAccessibleDOMNodeID(hideEvent.targetParent), "parent",
"Correct target parent.");
is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), "next",
"Correct target next sibling.");
is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), "previous",
"Correct target previous sibling.");
is(
getAccessibleDOMNodeID(hideEvent.targetParent),
"parent",
"Correct target parent."
);
is(
getAccessibleDOMNodeID(hideEvent.targetNextSibling),
"next",
"Correct target next sibling."
);
is(
getAccessibleDOMNodeID(hideEvent.targetPrevSibling),
"previous",
"Correct target previous sibling."
);
}
);

Просмотреть файл

@ -7,11 +7,15 @@
/**
* Test show event
*/
addAccessibleTask('<div id="div" style="visibility: hidden;"></div>',
addAccessibleTask(
'<div id="div" style="visibility: hidden;"></div>',
async function(browser) {
let onShow = waitForEvent(EVENT_SHOW, "div");
await invokeSetStyle(browser, "div", "visibility", "visible");
let showEvent = await onShow;
ok(showEvent.accessibleDocument instanceof nsIAccessibleDocument,
"Accessible document not present.");
});
ok(
showEvent.accessibleDocument instanceof nsIAccessibleDocument,
"Accessible document not present."
);
}
);

Просмотреть файл

@ -6,14 +6,19 @@
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR }
);
function checkStateChangeEvent(event, state, isExtraState, isEnabled) {
let scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
is(scEvent.state, state, "Correct state of the statechange event.");
is(scEvent.isExtraState, isExtraState,
"Correct extra state bit of the statechange event.");
is(
scEvent.isExtraState,
isExtraState,
"Correct extra state bit of the statechange event."
);
is(scEvent.isEnabled, isEnabled, "Correct state of statechange event state");
}
@ -34,28 +39,32 @@ let iframeSrc = `data:text/html,
* - isExtraState
* - isEnabled
*/
addAccessibleTask(`
addAccessibleTask(
`
<iframe id="iframe" src="${iframeSrc}"></iframe>
<input id="checkbox" type="checkbox" />`, async function(browser) {
// Test state change
let onStateChange = waitForEvent(EVENT_STATE_CHANGE, "checkbox");
// Set checked for a checkbox.
await ContentTask.spawn(browser, {}, () => {
content.document.getElementById("checkbox").checked = true;
});
let event = await onStateChange;
<input id="checkbox" type="checkbox" />`,
async function(browser) {
// Test state change
let onStateChange = waitForEvent(EVENT_STATE_CHANGE, "checkbox");
// Set checked for a checkbox.
await ContentTask.spawn(browser, {}, () => {
content.document.getElementById("checkbox").checked = true;
});
let event = await onStateChange;
checkStateChangeEvent(event, STATE_CHECKED, false, true);
testStates(event.accessible, STATE_CHECKED, 0);
checkStateChangeEvent(event, STATE_CHECKED, false, true);
testStates(event.accessible, STATE_CHECKED, 0);
// Test extra state
onStateChange = waitForEvent(EVENT_STATE_CHANGE, "iframe");
// Set design mode on.
await ContentTask.spawn(browser, {}, () => {
content.document.getElementById("iframe").contentDocument.designMode = "on";
});
event = await onStateChange;
// Test extra state
onStateChange = waitForEvent(EVENT_STATE_CHANGE, "iframe");
// Set design mode on.
await ContentTask.spawn(browser, {}, () => {
content.document.getElementById("iframe").contentDocument.designMode =
"on";
});
event = await onStateChange;
checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
testStates(event.accessible, 0, EXT_STATE_EDITABLE);
});
checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
testStates(event.accessible, 0, EXT_STATE_EDITABLE);
}
);

Просмотреть файл

@ -4,44 +4,75 @@
"use strict";
function checkTextChangeEvent(event, id, text, start, end, isInserted, isFromUserInput) {
function checkTextChangeEvent(
event,
id,
text,
start,
end,
isInserted,
isFromUserInput
) {
let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent);
is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`);
is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`);
is(tcEvent.isInserted, isInserted,
`Correct isInserted flag for ${prettyName(id)}`);
is(
tcEvent.isInserted,
isInserted,
`Correct isInserted flag for ${prettyName(id)}`
);
is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`);
is(tcEvent.isFromUserInput, isFromUserInput,
`Correct value of isFromUserInput for ${prettyName(id)}`);
ok(tcEvent.accessibleDocument instanceof nsIAccessibleDocument,
"Accessible document not present.");
is(
tcEvent.isFromUserInput,
isFromUserInput,
`Correct value of isFromUserInput for ${prettyName(id)}`
);
ok(
tcEvent.accessibleDocument instanceof nsIAccessibleDocument,
"Accessible document not present."
);
}
async function changeText(browser, id, value, events) {
let onEvents = waitForOrderedEvents(events.map(({ isInserted }) => {
let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
return [ eventType, id ];
}));
let onEvents = waitForOrderedEvents(
events.map(({ isInserted }) => {
let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
return [eventType, id];
})
);
// Change text in the subtree.
await ContentTask.spawn(browser, [id, value], ([contentId, contentValue]) => {
content.document.getElementById(contentId).firstChild.textContent =
contentValue;
content.document.getElementById(
contentId
).firstChild.textContent = contentValue;
});
let resolvedEvents = await onEvents;
events.forEach(({ isInserted, str, offset }, idx) =>
checkTextChangeEvent(resolvedEvents[idx],
id, str, offset, offset + str.length, isInserted, false));
checkTextChangeEvent(
resolvedEvents[idx],
id,
str,
offset,
offset + str.length,
isInserted,
false
)
);
}
async function removeTextFromInput(browser, id, value, start, end) {
let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id);
// Select text and delete it.
await ContentTask.spawn(browser, [id, start, end], ([contentId, contentStart, contentEnd]) => {
let el = content.document.getElementById(contentId);
el.focus();
el.setSelectionRange(contentStart, contentEnd);
});
await ContentTask.spawn(
browser,
[id, start, end],
([contentId, contentStart, contentEnd]) => {
let el = content.document.getElementById(contentId);
el.focus();
el.setSelectionRange(contentStart, contentEnd);
}
);
await BrowserTestUtils.sendChar("VK_DELETE", browser);
let event = await onTextRemoved;
@ -56,18 +87,21 @@ async function removeTextFromInput(browser, id, value, start, end) {
* - modifiedText
* - isFromUserInput
*/
addAccessibleTask(`
addAccessibleTask(
`
<p id="p">abc</p>
<input id="input" value="input" />`, async function(browser) {
let events = [
{ isInserted: false, str: "abc", offset: 0 },
{ isInserted: true, str: "def", offset: 0 }
];
await changeText(browser, "p", "def", events);
<input id="input" value="input" />`,
async function(browser) {
let events = [
{ isInserted: false, str: "abc", offset: 0 },
{ isInserted: true, str: "def", offset: 0 },
];
await changeText(browser, "p", "def", events);
events = [{ isInserted: true, str: "DEF", offset: 2 }];
await changeText(browser, "p", "deDEFf", events);
events = [{ isInserted: true, str: "DEF", offset: 2 }];
await changeText(browser, "p", "deDEFf", events);
// Test isFromUserInput property.
await removeTextFromInput(browser, "input", "n", 1, 2);
});
// Test isFromUserInput property.
await removeTextFromInput(browser, "input", "n", 1, 2);
}
);

Просмотреть файл

@ -4,18 +4,21 @@
"use strict";
addAccessibleTask(`
addAccessibleTask(
`
<p id="p1">abc</p>
<input id="input1" value="input" />`,
async function(browser, accDoc) {
let onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
await ContentTask.spawn(browser, null, () => {
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
.virtualCursor;
vc.position = getAccessible("p1");
});
let vccEvent = (await onVCChanged).QueryInterface(
nsIAccessibleVirtualCursorChangeEvent);
nsIAccessibleVirtualCursorChangeEvent
);
is(vccEvent.newAccessible.id, "p1", "New position is correct");
is(vccEvent.newStartOffset, -1, "New start offset is correct");
is(vccEvent.newEndOffset, -1, "New end offset is correct");
@ -23,11 +26,13 @@ addAccessibleTask(`
onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
await ContentTask.spawn(browser, null, () => {
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
.virtualCursor;
vc.moveNextByText(Ci.nsIAccessiblePivot.CHAR_BOUNDARY);
});
vccEvent = (await onVCChanged).QueryInterface(
nsIAccessibleVirtualCursorChangeEvent);
nsIAccessibleVirtualCursorChangeEvent
);
is(vccEvent.newAccessible.id, vccEvent.oldAccessible.id, "Same position");
is(vccEvent.newStartOffset, 0, "New start offset is correct");
is(vccEvent.newEndOffset, 1, "New end offset is correct");
@ -35,15 +40,18 @@ addAccessibleTask(`
onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
await ContentTask.spawn(browser, null, () => {
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
.virtualCursor;
vc.position = getAccessible("input1");
});
vccEvent = (await onVCChanged).QueryInterface(
nsIAccessibleVirtualCursorChangeEvent);
nsIAccessibleVirtualCursorChangeEvent
);
isnot(vccEvent.oldAccessible, vccEvent.newAccessible, "positions differ");
is(vccEvent.oldAccessible.id, "p1", "Old position is correct");
is(vccEvent.newAccessible.id, "input1", "New position is correct");
is(vccEvent.newStartOffset, -1, "New start offset is correct");
is(vccEvent.newEndOffset, -1, "New end offset is correct");
ok(!vccEvent.isFromUserInput, "not user initiated");
});
}
);

Просмотреть файл

@ -8,10 +8,13 @@
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
// Test ARIA Dialog
addAccessibleTask("doc_treeupdate_ariadialog.html", async function(browser, accDoc) {
addAccessibleTask("doc_treeupdate_ariadialog.html", async function(
browser,
accDoc
) {
testAccessibleTree(accDoc, {
role: ROLE_DOCUMENT,
children: [ ]
children: [],
});
// Make dialog visible and update its inner content.
@ -29,13 +32,13 @@ addAccessibleTask("doc_treeupdate_ariadialog.html", async function(browser, accD
children: [
{
role: ROLE_PUSHBUTTON,
children: [ { role: ROLE_TEXT_LEAF } ]
children: [{ role: ROLE_TEXT_LEAF }],
},
{
role: ROLE_ENTRY
}
]
}
]
role: ROLE_ENTRY,
},
],
},
],
});
});

Просмотреть файл

@ -15,12 +15,7 @@ async function testContainer1(browser, accDoc) {
/* ================= Initial tree test ==================================== */
// children are swapped by ARIA owns
let tree = {
SECTION: [
{ CHECKBUTTON: [
{ SECTION: [] }
] },
{ PUSHBUTTON: [ ] }
]
SECTION: [{ CHECKBUTTON: [{ SECTION: [] }] }, { PUSHBUTTON: [] }],
};
testAccessibleTree(acc, tree);
@ -33,10 +28,10 @@ async function testContainer1(browser, accDoc) {
// the children.
tree = {
SECTION: [
{ CHECKBUTTON: [ ] }, // checkbox, native order
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
]
{ CHECKBUTTON: [] }, // checkbox, native order
{ PUSHBUTTON: [] }, // button, rearranged by ARIA own
{ SECTION: [] }, // subdiv from the subtree, ARIA owned
],
};
testAccessibleTree(acc, tree);
@ -47,12 +42,7 @@ async function testContainer1(browser, accDoc) {
// children follow the DOM order
tree = {
SECTION: [
{ PUSHBUTTON: [ ] },
{ CHECKBUTTON: [
{ SECTION: [] }
] }
]
SECTION: [{ PUSHBUTTON: [] }, { CHECKBUTTON: [{ SECTION: [] }] }],
};
testAccessibleTree(acc, tree);
@ -65,28 +55,32 @@ async function testContainer1(browser, accDoc) {
// the children.
tree = {
SECTION: [
{ CHECKBUTTON: [ ] }, // checkbox
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
]
{ CHECKBUTTON: [] }, // checkbox
{ PUSHBUTTON: [] }, // button, rearranged by ARIA own
{ SECTION: [] }, // subdiv from the subtree, ARIA owned
],
};
testAccessibleTree(acc, tree);
/* ================ Add ID to ARIA owns =================================== */
onReorder = waitForEvent(EVENT_REORDER, docID);
await invokeSetAttribute(browser, id, "aria-owns",
"t1_button t1_subdiv t1_group");
await invokeSetAttribute(
browser,
id,
"aria-owns",
"t1_button t1_subdiv t1_group"
);
await onReorder;
// children are swapped again, button and subdiv are appended to
// the children.
tree = {
SECTION: [
{ CHECKBUTTON: [ ] }, // t1_checkbox
{ PUSHBUTTON: [ ] }, // button, t1_button
{ SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
{ GROUPING: [ ] } // group from outside, t1_group
]
{ CHECKBUTTON: [] }, // t1_checkbox
{ PUSHBUTTON: [] }, // button, t1_button
{ SECTION: [] }, // subdiv from the subtree, t1_subdiv
{ GROUPING: [] }, // group from outside, t1_group
],
};
testAccessibleTree(acc, tree);
@ -104,29 +98,30 @@ async function testContainer1(browser, accDoc) {
// newly inserted child.
tree = {
SECTION: [
{ CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
{ RADIOBUTTON: [ ] }, // new explicit, t1_child3
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ SECTION: [ ] }, // ARIA owned, t1_subdiv
{ GROUPING: [ ] } // ARIA owned, t1_group
]
{ CHECKBUTTON: [] }, // existing explicit, t1_checkbox
{ RADIOBUTTON: [] }, // new explicit, t1_child3
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
{ SECTION: [] }, // ARIA owned, t1_subdiv
{ GROUPING: [] }, // ARIA owned, t1_group
],
};
testAccessibleTree(acc, tree);
/* ================ Remove element ======================================== */
onReorder = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, {}, () =>
content.document.getElementById("t1_span").remove());
content.document.getElementById("t1_span").remove()
);
await onReorder;
// subdiv should go away
tree = {
SECTION: [
{ CHECKBUTTON: [ ] }, // explicit, t1_checkbox
{ RADIOBUTTON: [ ] }, // explicit, t1_child3
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ GROUPING: [ ] } // ARIA owned, t1_group
]
{ CHECKBUTTON: [] }, // explicit, t1_checkbox
{ RADIOBUTTON: [] }, // explicit, t1_child3
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
{ GROUPING: [] }, // ARIA owned, t1_group
],
};
testAccessibleTree(acc, tree);
@ -137,10 +132,10 @@ async function testContainer1(browser, accDoc) {
tree = {
SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] } // ARIA owned, t1_button
]
{ CHECKBUTTON: [] },
{ RADIOBUTTON: [] },
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
],
};
testAccessibleTree(acc, tree);
@ -151,11 +146,11 @@ async function testContainer1(browser, accDoc) {
tree = {
SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
]
{ CHECKBUTTON: [] },
{ RADIOBUTTON: [] },
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
{ GROUPING: [] }, // ARIA owned, t1_group, previously t1_grouptmp
],
};
testAccessibleTree(acc, tree);
}
@ -166,19 +161,21 @@ async function removeContainer(browser, accDoc) {
let tree = {
SECTION: [
{ CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
]
{ CHECKBUTTON: [] }, // ARIA owned, 't2_owned'
],
};
testAccessibleTree(acc, tree);
let onReorder = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, {}, () =>
content.document.getElementById("t2_container2").removeChild(
content.document.getElementById("t2_container3")));
content.document
.getElementById("t2_container2")
.removeChild(content.document.getElementById("t2_container3"))
);
await onReorder;
tree = {
SECTION: [ ]
SECTION: [],
};
testAccessibleTree(acc, tree);
}
@ -201,15 +198,13 @@ async function stealAndRecacheChildren(browser, accDoc) {
let tree = {
SECTION: [
{ CHECKBUTTON: [ ] } // ARIA owned
]
{ CHECKBUTTON: [] }, // ARIA owned
],
};
testAccessibleTree(acc1, tree);
tree = {
SECTION: [
{ RADIOBUTTON: [ ] }
]
SECTION: [{ RADIOBUTTON: [] }],
};
testAccessibleTree(acc2, tree);
}
@ -219,9 +214,7 @@ async function showHiddenElement(browser, accDoc) {
const acc = findAccessibleChildByID(accDoc, id);
let tree = {
SECTION: [
{ RADIOBUTTON: [] }
]
SECTION: [{ RADIOBUTTON: [] }],
};
testAccessibleTree(acc, tree);
@ -230,10 +223,7 @@ async function showHiddenElement(browser, accDoc) {
await onReorder;
tree = {
SECTION: [
{ CHECKBUTTON: [] },
{ RADIOBUTTON: [] }
]
SECTION: [{ CHECKBUTTON: [] }, { RADIOBUTTON: [] }],
};
testAccessibleTree(acc, tree);
}
@ -241,20 +231,23 @@ async function showHiddenElement(browser, accDoc) {
async function rearrangeARIAOwns(browser, accDoc) {
const id = "t5_container";
const acc = findAccessibleChildByID(accDoc, id);
const tests = [{
val: "t5_checkbox t5_radio t5_button",
roleList: [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ]
}, {
val: "t5_radio t5_button t5_checkbox",
roleList: [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]
}];
const tests = [
{
val: "t5_checkbox t5_radio t5_button",
roleList: ["CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON"],
},
{
val: "t5_radio t5_button t5_checkbox",
roleList: ["RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON"],
},
];
for (let { val, roleList } of tests) {
let onReorder = waitForEvent(EVENT_REORDER, id);
await invokeSetAttribute(browser, id, "aria-owns", val);
await onReorder;
let tree = { SECTION: [ ] };
let tree = { SECTION: [] };
for (let role of roleList) {
let ch = {};
ch[role] = [];
@ -269,29 +262,28 @@ async function removeNotARIAOwnedEl(browser, accDoc) {
const acc = findAccessibleChildByID(accDoc, id);
let tree = {
SECTION: [
{ TEXT_LEAF: [ ] },
{ GROUPING: [ ] }
]
SECTION: [{ TEXT_LEAF: [] }, { GROUPING: [] }],
};
testAccessibleTree(acc, tree);
let onReorder = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
content.document.getElementById(contentId).removeChild(
content.document.getElementById("t6_span"));
content.document
.getElementById(contentId)
.removeChild(content.document.getElementById("t6_span"));
});
await onReorder;
tree = {
SECTION: [
{ GROUPING: [ ] }
]
SECTION: [{ GROUPING: [] }],
};
testAccessibleTree(acc, tree);
}
addAccessibleTask("doc_treeupdate_ariaowns.html", async function(browser, accDoc) {
addAccessibleTask("doc_treeupdate_ariaowns.html", async function(
browser,
accDoc
) {
await testContainer1(browser, accDoc);
await removeContainer(browser, accDoc);
await stealAndRecacheChildren(browser, accDoc);

Просмотреть файл

@ -7,18 +7,21 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask(`
addAccessibleTask(
`
<canvas id="canvas">
<div id="dialog" role="dialog" style="display: none;"></div>
</canvas>`, async function(browser, accDoc) {
let canvas = findAccessibleChildByID(accDoc, "canvas");
let dialog = findAccessibleChildByID(accDoc, "dialog");
</canvas>`,
async function(browser, accDoc) {
let canvas = findAccessibleChildByID(accDoc, "canvas");
let dialog = findAccessibleChildByID(accDoc, "dialog");
testAccessibleTree(canvas, { CANVAS: [] });
testAccessibleTree(canvas, { CANVAS: [] });
let onShow = waitForEvent(EVENT_SHOW, "dialog");
await invokeSetStyle(browser, "dialog", "display", "block");
await onShow;
let onShow = waitForEvent(EVENT_SHOW, "dialog");
await invokeSetStyle(browser, "dialog", "display", "block");
await onShow;
testAccessibleTree(dialog, { DIALOG: [] });
});
testAccessibleTree(dialog, { DIALOG: [] });
}
);

Просмотреть файл

@ -7,61 +7,79 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask(`
addAccessibleTask(
`
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>
</div></div>
<div id="container2"><div id="scrollarea2" style="overflow:hidden;">
</div></div>`, async function(browser, accDoc) {
const id1 = "container";
const id2 = "container2";
const container = findAccessibleChildByID(accDoc, id1);
const container2 = findAccessibleChildByID(accDoc, id2);
</div></div>`,
async function(browser, accDoc) {
const id1 = "container";
const id2 = "container2";
const container = findAccessibleChildByID(accDoc, id1);
const container2 = findAccessibleChildByID(accDoc, id2);
/* ================= Change scroll range ================================== */
let tree = {
SECTION: [ {// container
SECTION: [ {// scroll area
ENTRY: [ ] // child content
} ]
} ]
};
testAccessibleTree(container, tree);
/* ================= Change scroll range ================================== */
let tree = {
SECTION: [
{
// container
SECTION: [
{
// scroll area
ENTRY: [], // child content
},
],
},
],
};
testAccessibleTree(container, tree);
let onReorder = waitForEvent(EVENT_REORDER, id1);
await ContentTask.spawn(browser, id1, id => {
let doc = content.document;
doc.getElementById("scrollarea").style.width = "20px";
doc.getElementById(id).appendChild(doc.createElement("input"));
});
await onReorder;
let onReorder = waitForEvent(EVENT_REORDER, id1);
await ContentTask.spawn(browser, id1, id => {
let doc = content.document;
doc.getElementById("scrollarea").style.width = "20px";
doc.getElementById(id).appendChild(doc.createElement("input"));
});
await onReorder;
tree = {
SECTION: [ {// container
SECTION: [ {// scroll area
ENTRY: [ ] // child content
} ]
}, {
ENTRY: [ ] // inserted input
} ]
};
testAccessibleTree(container, tree);
tree = {
SECTION: [
{
// container
SECTION: [
{
// scroll area
ENTRY: [], // child content
},
],
},
{
ENTRY: [], // inserted input
},
],
};
testAccessibleTree(container, tree);
/* ================= Change scrollbar styles ============================== */
tree = {
SECTION: [ // container2
{ SECTION: [] } // scroll area because of its ID
]
};
testAccessibleTree(container2, tree);
/* ================= Change scrollbar styles ============================== */
tree = {
SECTION: [
// container2
{ SECTION: [] }, // scroll area because of its ID
],
};
testAccessibleTree(container2, tree);
onReorder = waitForEvent(EVENT_REORDER, id2);
await invokeSetStyle(browser, "scrollarea2", "overflow", "auto");
await onReorder;
onReorder = waitForEvent(EVENT_REORDER, id2);
await invokeSetStyle(browser, "scrollarea2", "overflow", "auto");
await onReorder;
tree = {
SECTION: [ // container
{ SECTION: [] } // scroll area
]
};
testAccessibleTree(container2, tree);
});
tree = {
SECTION: [
// container
{ SECTION: [] }, // scroll area
],
};
testAccessibleTree(container2, tree);
}
);

Просмотреть файл

@ -16,102 +16,104 @@ const iframeSrc = `data:text/html,
<body id='inner-iframe'></body>
</html>`;
addAccessibleTask(`
<iframe id="iframe" src="${iframeSrc}"></iframe>`, async function(browser, accDoc) {
// ID of the iframe that is being tested
const id = "inner-iframe";
addAccessibleTask(
`
<iframe id="iframe" src="${iframeSrc}"></iframe>`,
async function(browser, accDoc) {
// ID of the iframe that is being tested
const id = "inner-iframe";
let iframe = findAccessibleChildByID(accDoc, id);
let iframe = findAccessibleChildByID(accDoc, id);
/* ================= Initial tree check =================================== */
let tree = {
role: ROLE_DOCUMENT,
children: [ ]
};
testAccessibleTree(iframe, tree);
/* ================= Initial tree check =================================== */
let tree = {
role: ROLE_DOCUMENT,
children: [],
};
testAccessibleTree(iframe, tree);
/* ================= Write iframe document ================================ */
let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newHTMLNode = docNode.createElement("html");
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Wave");
newBodyNode.id = contentId;
newBodyNode.appendChild(newTextNode);
newHTMLNode.appendChild(newBodyNode);
docNode.replaceChild(newHTMLNode, docNode.documentElement);
});
await reorderEventPromise;
/* ================= Write iframe document ================================ */
let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newHTMLNode = docNode.createElement("html");
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Wave");
newBodyNode.id = contentId;
newBodyNode.appendChild(newTextNode);
newHTMLNode.appendChild(newBodyNode);
docNode.replaceChild(newHTMLNode, docNode.documentElement);
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Wave"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Wave",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Replace iframe HTML element ========================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
// We can't use open/write/close outside of iframe document because of
// security error.
let script = docNode.createElement("script");
script.textContent = `
/* ================= Replace iframe HTML element ========================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
// We can't use open/write/close outside of iframe document because of
// security error.
let script = docNode.createElement("script");
script.textContent = `
document.open();
document.write('<body id="${contentId}">hello</body>');
document.close();`;
docNode.body.appendChild(script);
});
await reorderEventPromise;
docNode.body.appendChild(script);
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "hello"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "hello",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Replace iframe body ================================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Hello");
newBodyNode.id = contentId;
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
});
await reorderEventPromise;
/* ================= Replace iframe body ================================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Hello");
newBodyNode.id = contentId;
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
});
await reorderEventPromise;
tree = {
role: ROLE_PUSHBUTTON,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_PUSHBUTTON,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Open iframe document ================================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Open document.
let docNode = content.document.getElementById("iframe").contentDocument;
let script = docNode.createElement("script");
script.textContent = `
/* ================= Open iframe document ================================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Open document.
let docNode = content.document.getElementById("iframe").contentDocument;
let script = docNode.createElement("script");
script.textContent = `
function closeMe() {
document.write('Works?');
document.close();
@ -119,192 +121,199 @@ addAccessibleTask(`
window.closeMe = closeMe;
document.open();
document.write('<body id="${contentId}"></body>');`;
docNode.body.appendChild(script);
});
await reorderEventPromise;
docNode.body.appendChild(script);
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [ ]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [],
};
testAccessibleTree(iframe, tree);
/* ================= Close iframe document ================================ */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, {}, () => {
// Write and close document.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.write("Works?");
docNode.close();
});
await reorderEventPromise;
/* ================= Close iframe document ================================ */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, {}, () => {
// Write and close document.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.write("Works?");
docNode.close();
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Works?"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Works?",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Remove HTML from iframe document ===================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
// Remove HTML element.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.firstChild.remove();
});
let event = await reorderEventPromise;
/* ================= Remove HTML from iframe document ===================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
// Remove HTML element.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.firstChild.remove();
});
let event = await reorderEventPromise;
ok(event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document");
tree = {
role: ROLE_DOCUMENT,
children: [ ]
};
testAccessibleTree(iframe, tree);
ok(
event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document"
);
tree = {
role: ROLE_DOCUMENT,
children: [],
};
testAccessibleTree(iframe, tree);
/* ================= Insert HTML to iframe document ======================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Insert HTML element.
let docNode = content.document.getElementById("iframe").contentDocument;
let html = docNode.createElement("html");
let body = docNode.createElement("body");
let text = docNode.createTextNode("Haha");
body.appendChild(text);
body.id = contentId;
html.appendChild(body);
docNode.appendChild(html);
});
await reorderEventPromise;
/* ================= Insert HTML to iframe document ======================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Insert HTML element.
let docNode = content.document.getElementById("iframe").contentDocument;
let html = docNode.createElement("html");
let body = docNode.createElement("body");
let text = docNode.createTextNode("Haha");
body.appendChild(text);
body.id = contentId;
html.appendChild(body);
docNode.appendChild(html);
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Haha"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Haha",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Remove body from iframe document ===================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
// Remove body element.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.documentElement.removeChild(docNode.body);
});
event = await reorderEventPromise;
/* ================= Remove body from iframe document ===================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
// Remove body element.
let docNode = content.document.getElementById("iframe").contentDocument;
docNode.documentElement.removeChild(docNode.body);
});
event = await reorderEventPromise;
ok(event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document");
tree = {
role: ROLE_DOCUMENT,
children: [ ]
};
testAccessibleTree(iframe, tree);
ok(
event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document"
);
tree = {
role: ROLE_DOCUMENT,
children: [],
};
testAccessibleTree(iframe, tree);
/* ================ Insert element under document element while body missed */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
let docNode = content.document.getElementById("iframe").contentDocument;
let inputNode = content.window.inputNode = docNode.createElement("input");
docNode.documentElement.appendChild(inputNode);
});
event = await reorderEventPromise;
/* ================ Insert element under document element while body missed */
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
let docNode = content.document.getElementById("iframe").contentDocument;
let inputNode = (content.window.inputNode = docNode.createElement(
"input"
));
docNode.documentElement.appendChild(inputNode);
});
event = await reorderEventPromise;
ok(event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document");
tree = {
DOCUMENT: [
{ ENTRY: [ ] }
]
};
testAccessibleTree(iframe, tree);
ok(
event.accessible instanceof nsIAccessibleDocument,
"Reorder should happen on the document"
);
tree = {
DOCUMENT: [{ ENTRY: [] }],
};
testAccessibleTree(iframe, tree);
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
let docEl =
content.document.getElementById("iframe").contentDocument.documentElement;
// Remove aftermath of this test before next test starts.
docEl.firstChild.remove();
});
// Make sure reorder event was fired and that the input was removed.
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [ ]
};
testAccessibleTree(iframe, tree);
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
await ContentTask.spawn(browser, {}, () => {
let docEl = content.document.getElementById("iframe").contentDocument
.documentElement;
// Remove aftermath of this test before next test starts.
docEl.firstChild.remove();
});
// Make sure reorder event was fired and that the input was removed.
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [],
};
testAccessibleTree(iframe, tree);
/* ================= Insert body to iframe document ======================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Write and close document.
let docNode = content.document.getElementById("iframe").contentDocument;
// Insert body element.
let body = docNode.createElement("body");
let text = docNode.createTextNode("Yo ho ho i butylka roma!");
body.appendChild(text);
body.id = contentId;
docNode.documentElement.appendChild(body);
});
await reorderEventPromise;
/* ================= Insert body to iframe document ======================= */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
// Write and close document.
let docNode = content.document.getElementById("iframe").contentDocument;
// Insert body element.
let body = docNode.createElement("body");
let text = docNode.createTextNode("Yo ho ho i butylka roma!");
body.appendChild(text);
body.id = contentId;
docNode.documentElement.appendChild(body);
});
await reorderEventPromise;
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Yo ho ho i butylka roma!"
}
]
};
testAccessibleTree(iframe, tree);
tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "Yo ho ho i butylka roma!",
},
],
};
testAccessibleTree(iframe, tree);
/* ================= Change source ======================================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, "iframe");
await invokeSetAttribute(browser, "iframe", "src",
`data:text/html,<html><body id="${id}"><input></body></html>`);
event = await reorderEventPromise;
/* ================= Change source ======================================== */
reorderEventPromise = waitForEvent(EVENT_REORDER, "iframe");
await invokeSetAttribute(
browser,
"iframe",
"src",
`data:text/html,<html><body id="${id}"><input></body></html>`
);
event = await reorderEventPromise;
tree = {
INTERNAL_FRAME: [
{ DOCUMENT: [
{ ENTRY: [ ] }
] }
]
};
testAccessibleTree(event.accessible, tree);
iframe = findAccessibleChildByID(event.accessible, id);
tree = {
INTERNAL_FRAME: [{ DOCUMENT: [{ ENTRY: [] }] }],
};
testAccessibleTree(event.accessible, tree);
iframe = findAccessibleChildByID(event.accessible, id);
/* ================= Replace iframe body on ARIA role body ================ */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Hello");
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
newBodyNode.id = contentId;
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
});
await reorderEventPromise;
/* ================= Replace iframe body on ARIA role body ================ */
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
await ContentTask.spawn(browser, id, contentId => {
let docNode = content.document.getElementById("iframe").contentDocument;
let newBodyNode = docNode.createElement("body");
let newTextNode = docNode.createTextNode("New Hello");
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
newBodyNode.id = contentId;
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
});
await reorderEventPromise;
tree = {
role: ROLE_PUSHBUTTON,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello"
}
]
};
testAccessibleTree(iframe, tree);
});
tree = {
role: ROLE_PUSHBUTTON,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello",
},
],
};
testAccessibleTree(iframe, tree);
}
);

Просмотреть файл

@ -7,7 +7,8 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask(`
addAccessibleTask(
`
<style>
.gentext:before {
content: "START"
@ -25,16 +26,22 @@ addAccessibleTask(`
let container2 = findAccessibleChildByID(accDoc, id2);
let tree = {
SECTION: [ ] // container
SECTION: [], // container
};
testAccessibleTree(container1, tree);
tree = {
SECTION: [ { // container2
SECTION: [ { // container2 child
TEXT_LEAF: [ ] // primary text
} ]
} ]
SECTION: [
{
// container2
SECTION: [
{
// container2 child
TEXT_LEAF: [], // primary text
},
],
},
],
};
testAccessibleTree(container2, tree);
@ -49,13 +56,17 @@ addAccessibleTask(`
await onReorder;
tree = {
SECTION: [ // container
{ SECTION: [ // inserted node
{ STATICTEXT: [] }, // :before
{ TEXT_LEAF: [] }, // primary text
{ STATICTEXT: [] } // :after
] }
]
SECTION: [
// container
{
SECTION: [
// inserted node
{ STATICTEXT: [] }, // :before
{ TEXT_LEAF: [] }, // primary text
{ STATICTEXT: [] }, // :after
],
},
],
};
testAccessibleTree(container1, tree);
@ -65,13 +76,18 @@ addAccessibleTask(`
await onReorder;
tree = {
SECTION: [ // container2
{ SECTION: [ // container2 child
{ STATICTEXT: [] }, // :before
{ TEXT_LEAF: [] }, // primary text
{ STATICTEXT: [] } // :after
] }
]
SECTION: [
// container2
{
SECTION: [
// container2 child
{ STATICTEXT: [] }, // :before
{ TEXT_LEAF: [] }, // primary text
{ STATICTEXT: [] }, // :after
],
},
],
};
testAccessibleTree(container2, tree);
});
}
);

Просмотреть файл

@ -13,17 +13,19 @@ async function setHidden(browser, value) {
await onReorder;
}
addAccessibleTask('<div id="container"><input id="child"></div>',
addAccessibleTask(
'<div id="container"><input id="child"></div>',
async function(browser, accDoc) {
let container = findAccessibleChildByID(accDoc, "container");
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
testAccessibleTree(container, { SECTION: [{ ENTRY: [] }] });
// Set @hidden attribute
await setHidden(browser, "true");
testAccessibleTree(container, { SECTION: [ ] });
testAccessibleTree(container, { SECTION: [] });
// Remove @hidden attribute
await setHidden(browser);
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
});
testAccessibleTree(container, { SECTION: [{ ENTRY: [] }] });
}
);

Просмотреть файл

@ -13,9 +13,7 @@ async function testImageMap(browser, accDoc) {
/* ================= Initial tree test ==================================== */
let tree = {
IMAGE_MAP: [
{ role: ROLE_LINK, name: "b", children: [ ] }
]
IMAGE_MAP: [{ role: ROLE_LINK, name: "b", children: [] }],
};
testAccessibleTree(acc, tree);
@ -24,8 +22,10 @@ async function testImageMap(browser, accDoc) {
await ContentTask.spawn(browser, {}, () => {
let areaElm = content.document.createElement("area");
let mapNode = content.document.getElementById("map");
areaElm.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#a");
areaElm.setAttribute(
"href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
);
areaElm.setAttribute("coords", "0,0,13,14");
areaElm.setAttribute("alt", "a");
areaElm.setAttribute("shape", "rect");
@ -35,9 +35,9 @@ async function testImageMap(browser, accDoc) {
tree = {
IMAGE_MAP: [
{ role: ROLE_LINK, name: "a", children: [ ] },
{ role: ROLE_LINK, name: "b", children: [ ] }
]
{ role: ROLE_LINK, name: "a", children: [] },
{ role: ROLE_LINK, name: "b", children: [] },
],
};
testAccessibleTree(acc, tree);
@ -46,8 +46,10 @@ async function testImageMap(browser, accDoc) {
await ContentTask.spawn(browser, {}, () => {
let areaElm = content.document.createElement("area");
let mapNode = content.document.getElementById("map");
areaElm.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#c");
areaElm.setAttribute(
"href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#c"
);
areaElm.setAttribute("coords", "34,0,47,14");
areaElm.setAttribute("alt", "c");
areaElm.setAttribute("shape", "rect");
@ -57,10 +59,10 @@ async function testImageMap(browser, accDoc) {
tree = {
IMAGE_MAP: [
{ role: ROLE_LINK, name: "a", children: [ ] },
{ role: ROLE_LINK, name: "b", children: [ ] },
{ role: ROLE_LINK, name: "c", children: [ ] }
]
{ role: ROLE_LINK, name: "a", children: [] },
{ role: ROLE_LINK, name: "b", children: [] },
{ role: ROLE_LINK, name: "c", children: [] },
],
};
testAccessibleTree(acc, tree);
@ -74,9 +76,9 @@ async function testImageMap(browser, accDoc) {
tree = {
IMAGE_MAP: [
{ role: ROLE_LINK, name: "b", children: [ ] },
{ role: ROLE_LINK, name: "c", children: [ ] }
]
{ role: ROLE_LINK, name: "b", children: [] },
{ role: ROLE_LINK, name: "c", children: [] },
],
};
testAccessibleTree(acc, tree);
}
@ -90,9 +92,7 @@ async function testContainer(browser) {
const acc = event.accessible;
let tree = {
SECTION: [
{ GRAPHIC: [ ] }
]
SECTION: [{ GRAPHIC: [] }],
};
testAccessibleTree(acc, tree);
@ -100,17 +100,21 @@ async function testContainer(browser) {
onReorder = waitForEvent(EVENT_REORDER, id);
await invokeSetAttribute(browser, "map", "name", "atoz_map");
// XXX: force repainting of the image (see bug 745788 for details).
await BrowserTestUtils.synthesizeMouse("#imgmap", 10, 10,
{ type: "mousemove" }, browser);
await BrowserTestUtils.synthesizeMouse(
"#imgmap",
10,
10,
{ type: "mousemove" },
browser
);
await onReorder;
tree = {
SECTION: [ {
IMAGE_MAP: [
{ LINK: [ ] },
{ LINK: [ ] }
]
} ]
SECTION: [
{
IMAGE_MAP: [{ LINK: [] }, { LINK: [] }],
},
],
};
testAccessibleTree(acc, tree);
@ -123,9 +127,7 @@ async function testContainer(browser) {
await onReorder;
tree = {
SECTION: [
{ GRAPHIC: [ ] }
]
SECTION: [{ GRAPHIC: [] }],
};
testAccessibleTree(acc, tree);
@ -138,8 +140,7 @@ async function testContainer(browser) {
map.setAttribute("name", "atoz_map");
map.setAttribute("id", "map");
area.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
area.setAttribute("href", "http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
area.setAttribute("coords", "17,0,30,14");
area.setAttribute("alt", "b");
area.setAttribute("shape", "rect");
@ -150,11 +151,11 @@ async function testContainer(browser) {
await onReorder;
tree = {
SECTION: [ {
IMAGE_MAP: [
{ LINK: [ ] }
]
} ]
SECTION: [
{
IMAGE_MAP: [{ LINK: [] }],
},
],
};
testAccessibleTree(acc, tree);
@ -164,7 +165,7 @@ async function testContainer(browser) {
await onReorder;
tree = {
SECTION: [ ]
SECTION: [],
};
testAccessibleTree(acc, tree);
}
@ -178,12 +179,20 @@ async function waitForImageMap(browser, accDoc) {
const onReorder = waitForEvent(EVENT_REORDER, id);
// Wave over image map
await BrowserTestUtils.synthesizeMouse(`#${id}`, 10, 10,
{ type: "mousemove" }, browser);
await BrowserTestUtils.synthesizeMouse(
`#${id}`,
10,
10,
{ type: "mousemove" },
browser
);
await onReorder;
}
addAccessibleTask("doc_treeupdate_imagemap.html", async function(browser, accDoc) {
addAccessibleTask("doc_treeupdate_imagemap.html", async function(
browser,
accDoc
) {
await waitForImageMap(browser, accDoc);
await testImageMap(browser, accDoc);
await testContainer(browser);

Просмотреть файл

@ -13,30 +13,39 @@ async function setDisplayAndWaitForReorder(browser, value) {
return onReorder;
}
addAccessibleTask(`
addAccessibleTask(
`
<ul id="ul">
<li id="li">item1</li>
</ul>`, async function(browser, accDoc) {
let li = findAccessibleChildByID(accDoc, "li");
let bullet = li.firstChild;
let accTree = {
role: ROLE_LISTITEM,
children: [ {
role: ROLE_STATICTEXT,
children: []
}, {
role: ROLE_TEXT_LEAF,
children: []
} ]
};
testAccessibleTree(li, accTree);
</ul>`,
async function(browser, accDoc) {
let li = findAccessibleChildByID(accDoc, "li");
let bullet = li.firstChild;
let accTree = {
role: ROLE_LISTITEM,
children: [
{
role: ROLE_STATICTEXT,
children: [],
},
{
role: ROLE_TEXT_LEAF,
children: [],
},
],
};
testAccessibleTree(li, accTree);
await setDisplayAndWaitForReorder(browser, "none");
await setDisplayAndWaitForReorder(browser, "none");
ok(isDefunct(li), "Check that li is defunct.");
ok(isDefunct(bullet), "Check that bullet is defunct.");
ok(isDefunct(li), "Check that li is defunct.");
ok(isDefunct(bullet), "Check that bullet is defunct.");
let event = await setDisplayAndWaitForReorder(browser, "list-item");
let event = await setDisplayAndWaitForReorder(browser, "list-item");
testAccessibleTree(findAccessibleChildByID(event.accessible, "li"), accTree);
});
testAccessibleTree(
findAccessibleChildByID(event.accessible, "li"),
accTree
);
}
);

Просмотреть файл

@ -12,7 +12,7 @@ addAccessibleTask('<ol id="list"></ol>', async function(browser, accDoc) {
testAccessibleTree(list, {
role: ROLE_LIST,
children: [ ]
children: [],
});
await invokeSetAttribute(browser, "body", "contentEditable", "true");
@ -26,12 +26,14 @@ addAccessibleTask('<ol id="list"></ol>', async function(browser, accDoc) {
testAccessibleTree(list, {
role: ROLE_LIST,
children: [ {
role: ROLE_LISTITEM,
children: [
{ role: ROLE_STATICTEXT, name: "1. ", children: [] },
{ role: ROLE_TEXT_LEAF, children: [] }
]
} ]
children: [
{
role: ROLE_LISTITEM,
children: [
{ role: ROLE_STATICTEXT, name: "1. ", children: [] },
{ role: ROLE_TEXT_LEAF, children: [] },
],
},
],
});
});

Просмотреть файл

@ -7,22 +7,31 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask('<span id="parent"><span id="child"></span></span>',
addAccessibleTask(
'<span id="parent"><span id="child"></span></span>',
async function(browser, accDoc) {
is(findAccessibleChildByID(accDoc, "parent"), null,
"Check that parent is not accessible.");
is(findAccessibleChildByID(accDoc, "child"), null,
"Check that child is not accessible.");
is(
findAccessibleChildByID(accDoc, "parent"),
null,
"Check that parent is not accessible."
);
is(
findAccessibleChildByID(accDoc, "child"),
null,
"Check that child is not accessible."
);
let onReorder = waitForEvent(EVENT_REORDER, "body");
// Add an event listener to parent.
await ContentTask.spawn(browser, {}, () => {
content.window.dummyListener = () => {};
content.document.getElementById("parent").addEventListener(
"click", content.window.dummyListener);
content.document
.getElementById("parent")
.addEventListener("click", content.window.dummyListener);
});
await onReorder;
let tree = { TEXT: [] };
testAccessibleTree(findAccessibleChildByID(accDoc, "parent"), tree);
});
}
);

Просмотреть файл

@ -7,7 +7,10 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask('<select id="select"></select>', async function(browser, accDoc) {
addAccessibleTask('<select id="select"></select>', async function(
browser,
accDoc
) {
let select = findAccessibleChildByID(accDoc, "select");
let onEvent = waitForEvent(EVENT_REORDER, "select");
@ -35,18 +38,24 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
let option1Node = findAccessibleChildByID(event.accessible, "option1Node");
let tree = {
COMBOBOX: [ {
COMBOBOX_LIST: [ {
GROUPING: [
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] },
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] }
]
}, {
COMBOBOX_OPTION: []
}, {
COMBOBOX_OPTION: []
} ]
} ]
COMBOBOX: [
{
COMBOBOX_LIST: [
{
GROUPING: [
{ COMBOBOX_OPTION: [{ TEXT_LEAF: [] }] },
{ COMBOBOX_OPTION: [{ TEXT_LEAF: [] }] },
],
},
{
COMBOBOX_OPTION: [],
},
{
COMBOBOX_OPTION: [],
},
],
},
],
};
testAccessibleTree(select, tree);
ok(!isDefunct(option1Node), "option shouldn't be defunct");
@ -60,16 +69,14 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
await onEvent;
tree = {
COMBOBOX: [ {
COMBOBOX_LIST: [
{ COMBOBOX_OPTION: [] },
{ COMBOBOX_OPTION: [] }
]
} ]
COMBOBOX: [
{
COMBOBOX_LIST: [{ COMBOBOX_OPTION: [] }, { COMBOBOX_OPTION: [] }],
},
],
};
testAccessibleTree(select, tree);
ok(isDefunct(option1Node),
"removed option shouldn't be accessible anymore!");
ok(isDefunct(option1Node), "removed option shouldn't be accessible anymore!");
onEvent = waitForEvent(EVENT_REORDER, "select");
// Remove all options from combobox
@ -82,9 +89,11 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
await onEvent;
tree = {
COMBOBOX: [ {
COMBOBOX_LIST: [ ]
} ]
COMBOBOX: [
{
COMBOBOX_LIST: [],
},
],
};
testAccessibleTree(select, tree);
});

Просмотреть файл

@ -7,32 +7,51 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask("doc_treeupdate_removal.xhtml", async function(browser, accDoc) {
ok(isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table should be accessible");
addAccessibleTask("doc_treeupdate_removal.xhtml", async function(
browser,
accDoc
) {
ok(
isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table should be accessible"
);
// Move the_table element into hidden subtree.
let onReorder = waitForEvent(EVENT_REORDER, "body");
await ContentTask.spawn(browser, {}, () => content.document.getElementById(
"the_displaynone").appendChild(content.document.getElementById(
"the_table")));
await ContentTask.spawn(browser, {}, () =>
content.document
.getElementById("the_displaynone")
.appendChild(content.document.getElementById("the_table"))
);
await onReorder;
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table in display none tree shouldn't be accessible");
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
"row shouldn't be accessible");
ok(
!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table in display none tree shouldn't be accessible"
);
ok(
!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
"row shouldn't be accessible"
);
// Remove the_row element (since it did not have accessible, no event needed).
await ContentTask.spawn(browser, {}, () =>
content.document.body.removeChild(
content.document.getElementById("the_row")));
content.document.getElementById("the_row")
)
);
// make sure no accessibles have stuck around.
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
"row shouldn't be accessible");
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table shouldn't be accessible");
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_displayNone")),
"display none things shouldn't be accessible");
ok(
!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
"row shouldn't be accessible"
);
ok(
!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
"table shouldn't be accessible"
);
ok(
!isAccessible(findAccessibleChildByID(accDoc, "the_displayNone")),
"display none things shouldn't be accessible"
);
});

Просмотреть файл

@ -7,44 +7,41 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask(`
addAccessibleTask(
`
<table id="table">
<tr>
<td>cell1</td>
<td>cell2</td>
</tr>
</table>`, async function(browser, accDoc) {
let table = findAccessibleChildByID(accDoc, "table");
</table>`,
async function(browser, accDoc) {
let table = findAccessibleChildByID(accDoc, "table");
let tree = {
TABLE: [
{ ROW: [
{ CELL: [ {TEXT_LEAF: [] }]},
{ CELL: [ {TEXT_LEAF: [] }]}
] }
]
};
testAccessibleTree(table, tree);
let tree = {
TABLE: [
{ ROW: [{ CELL: [{ TEXT_LEAF: [] }] }, { CELL: [{ TEXT_LEAF: [] }] }] },
],
};
testAccessibleTree(table, tree);
let onReorder = waitForEvent(EVENT_REORDER, "table");
await ContentTask.spawn(browser, {}, () => {
// append a caption, it should appear as a first element in the
// accessible tree.
let doc = content.document;
let caption = doc.createElement("caption");
caption.textContent = "table caption";
doc.getElementById("table").appendChild(caption);
});
await onReorder;
let onReorder = waitForEvent(EVENT_REORDER, "table");
await ContentTask.spawn(browser, {}, () => {
// append a caption, it should appear as a first element in the
// accessible tree.
let doc = content.document;
let caption = doc.createElement("caption");
caption.textContent = "table caption";
doc.getElementById("table").appendChild(caption);
});
await onReorder;
tree = {
TABLE: [
{ CAPTION: [ { TEXT_LEAF: [] } ] },
{ ROW: [
{ CELL: [ {TEXT_LEAF: [] }]},
{ CELL: [ {TEXT_LEAF: [] }]}
] }
]
};
testAccessibleTree(table, tree);
});
tree = {
TABLE: [
{ CAPTION: [{ TEXT_LEAF: [] }] },
{ ROW: [{ CELL: [{ TEXT_LEAF: [] }] }, { CELL: [{ TEXT_LEAF: [] }] }] },
],
};
testAccessibleTree(table, tree);
}
);

Просмотреть файл

@ -10,7 +10,7 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
async function removeTextData(browser, accessible, id, role) {
let tree = {
role,
children: [ { role: ROLE_TEXT_LEAF, name: "text" } ]
children: [{ role: ROLE_TEXT_LEAF, name: "text" }],
};
testAccessibleTree(accessible, tree);
@ -24,11 +24,14 @@ async function removeTextData(browser, accessible, id, role) {
testAccessibleTree(accessible, tree);
}
addAccessibleTask(`
addAccessibleTask(
`
<p id="p">text</p>
<pre id="pre">text</pre>`, async function(browser, accDoc) {
let p = findAccessibleChildByID(accDoc, "p");
let pre = findAccessibleChildByID(accDoc, "pre");
await removeTextData(browser, p, "p", ROLE_PARAGRAPH);
await removeTextData(browser, pre, "pre", ROLE_TEXT_CONTAINER);
});
<pre id="pre">text</pre>`,
async function(browser, accDoc) {
let p = findAccessibleChildByID(accDoc, "p");
let pre = findAccessibleChildByID(accDoc, "pre");
await removeTextData(browser, p, "p", ROLE_PARAGRAPH);
await removeTextData(browser, pre, "pre", ROLE_TEXT_CONTAINER);
}
);

Просмотреть файл

@ -20,18 +20,32 @@ async function testTreeOnHide(browser, accDoc, containerID, id, before, after) {
async function test3(browser, accessible) {
let tree = {
SECTION: [ // container
{ SECTION: [ // parent
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] }
] },
{ SECTION: [ // parent2
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] }
] }
] };
SECTION: [
// container
{
SECTION: [
// parent
{
SECTION: [
// child
{ TEXT_LEAF: [] },
],
},
],
},
{
SECTION: [
// parent2
{
SECTION: [
// child2
{ TEXT_LEAF: [] },
],
},
],
},
],
};
testAccessibleTree(accessible, tree);
let onReorder = waitForEvent(EVENT_REORDER, "t3_container");
@ -44,26 +58,29 @@ async function test3(browser, accessible) {
await onReorder;
tree = {
SECTION: [ // container
{ SECTION: [ // child
{ TEXT_LEAF: [] }
] },
{ SECTION: [ // child2
{ TEXT_LEAF: [] }
] }
] };
SECTION: [
// container
{
SECTION: [
// child
{ TEXT_LEAF: [] },
],
},
{
SECTION: [
// child2
{ TEXT_LEAF: [] },
],
},
],
};
testAccessibleTree(accessible, tree);
}
async function test4(browser, accessible) {
let tree = {
SECTION: [
{ TABLE: [
{ ROW: [
{ CELL: [ ] }
] }
] }
] };
SECTION: [{ TABLE: [{ ROW: [{ CELL: [] }] }] }],
};
testAccessibleTree(accessible, tree);
let onReorder = waitForEvent(EVENT_REORDER, "t4_parent");
@ -75,121 +92,250 @@ async function test4(browser, accessible) {
await onReorder;
tree = {
SECTION: [{
TABLE: [{
ROW: [{
CELL: [{
SECTION: [{
TEXT_LEAF: []
}]
}]
}]
}]
}]
SECTION: [
{
TABLE: [
{
ROW: [
{
CELL: [
{
SECTION: [
{
TEXT_LEAF: [],
},
],
},
],
},
],
},
],
},
],
};
testAccessibleTree(accessible, tree);
}
addAccessibleTask("doc_treeupdate_visibility.html", async function(browser, accDoc) {
addAccessibleTask("doc_treeupdate_visibility.html", async function(
browser,
accDoc
) {
let t3Container = findAccessibleChildByID(accDoc, "t3_container");
let t4Container = findAccessibleChildByID(accDoc, "t4_container");
await testTreeOnHide(browser, accDoc, "t1_container", "t1_parent", {
SECTION: [{
SECTION: [{
SECTION: [ { TEXT_LEAF: [] } ]
}]
}]
}, {
SECTION: [ {
SECTION: [ { TEXT_LEAF: [] } ]
} ]
});
await testTreeOnHide(
browser,
accDoc,
"t1_container",
"t1_parent",
{
SECTION: [
{
SECTION: [
{
SECTION: [{ TEXT_LEAF: [] }],
},
],
},
],
},
{
SECTION: [
{
SECTION: [{ TEXT_LEAF: [] }],
},
],
}
);
await testTreeOnHide(browser, accDoc, "t2_container", "t2_grandparent", {
SECTION: [{ // container
SECTION: [{ // grand parent
SECTION: [{
SECTION: [{ // child
TEXT_LEAF: []
}]
}, {
SECTION: [{ // child2
TEXT_LEAF: []
}]
}]
}]
}]
}, {
SECTION: [{ // container
SECTION: [{ // child
TEXT_LEAF: []
}]
}, {
SECTION: [{ // child2
TEXT_LEAF: []
}]
}]
});
await testTreeOnHide(
browser,
accDoc,
"t2_container",
"t2_grandparent",
{
SECTION: [
{
// container
SECTION: [
{
// grand parent
SECTION: [
{
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
{
SECTION: [
{
// child2
TEXT_LEAF: [],
},
],
},
],
},
],
},
],
},
{
SECTION: [
{
// container
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
{
SECTION: [
{
// child2
TEXT_LEAF: [],
},
],
},
],
}
);
await test3(browser, t3Container);
await test4(browser, t4Container);
await testTreeOnHide(browser, accDoc, "t5_container", "t5_subcontainer", {
SECTION: [{ // container
SECTION: [{ // subcontainer
TABLE: [{
ROW: [{
CELL: [{
SECTION: [{ // child
TEXT_LEAF: []
}]
}]
}]
}]
}]
}]
}, {
SECTION: [{ // container
SECTION: [{ // child
TEXT_LEAF: []
}]
}]
});
await testTreeOnHide(
browser,
accDoc,
"t5_container",
"t5_subcontainer",
{
SECTION: [
{
// container
SECTION: [
{
// subcontainer
TABLE: [
{
ROW: [
{
CELL: [
{
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
],
},
],
},
],
},
],
},
],
},
{
SECTION: [
{
// container
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
],
}
);
await testTreeOnHide(browser, accDoc, "t6_container", "t6_subcontainer", {
SECTION: [{ // container
SECTION: [{ // subcontainer
TABLE: [{
ROW: [{
CELL: [{
TABLE: [{ // nested table
ROW: [{
CELL: [{
SECTION: [{ // child
TEXT_LEAF: []
}]
}]
}]
}]
}]
}]
}]
}, {
SECTION: [{ // child2
TEXT_LEAF: []
}]
}]
}]
}, {
SECTION: [{ // container
SECTION: [{ // child
TEXT_LEAF: []
}]
}, {
SECTION: [{ // child2
TEXT_LEAF: []
}]
}]
});
await testTreeOnHide(
browser,
accDoc,
"t6_container",
"t6_subcontainer",
{
SECTION: [
{
// container
SECTION: [
{
// subcontainer
TABLE: [
{
ROW: [
{
CELL: [
{
TABLE: [
{
// nested table
ROW: [
{
CELL: [
{
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
},
{
SECTION: [
{
// child2
TEXT_LEAF: [],
},
],
},
],
},
],
},
{
SECTION: [
{
// container
SECTION: [
{
// child
TEXT_LEAF: [],
},
],
},
{
SECTION: [
{
// child2
TEXT_LEAF: [],
},
],
},
],
}
);
});

Просмотреть файл

@ -7,7 +7,10 @@
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accDoc) {
addAccessibleTask("doc_treeupdate_whitespace.html", async function(
browser,
accDoc
) {
let container1 = findAccessibleChildByID(accDoc, "container1");
let container2Parent = findAccessibleChildByID(accDoc, "container2-parent");
@ -17,8 +20,8 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
{ TEXT_LEAF: [] },
{ GRAPHIC: [] },
{ TEXT_LEAF: [] },
{ GRAPHIC: [] }
]
{ GRAPHIC: [] },
],
};
testAccessibleTree(container1, tree);
@ -26,25 +29,17 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
// Remove img1 from container1
await ContentTask.spawn(browser, {}, () => {
let doc = content.document;
doc.getElementById("container1").removeChild(
doc.getElementById("img1"));
doc.getElementById("container1").removeChild(doc.getElementById("img1"));
});
await onReorder;
tree = {
SECTION: [
{ GRAPHIC: [] },
{ TEXT_LEAF: [] },
{ GRAPHIC: [] }
]
SECTION: [{ GRAPHIC: [] }, { TEXT_LEAF: [] }, { GRAPHIC: [] }],
};
testAccessibleTree(container1, tree);
tree = {
SECTION: [
{ LINK: [] },
{ LINK: [ { GRAPHIC: [] } ] }
]
SECTION: [{ LINK: [] }, { LINK: [{ GRAPHIC: [] }] }],
};
testAccessibleTree(container2Parent, tree);
@ -53,18 +48,20 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
await ContentTask.spawn(browser, {}, () => {
let doc = content.document;
let img = doc.createElement("img");
img.setAttribute("src",
"http://example.com/a11y/accessible/tests/mochitest/moz.png");
img.setAttribute(
"src",
"http://example.com/a11y/accessible/tests/mochitest/moz.png"
);
doc.getElementById("container2").appendChild(img);
});
await onReorder;
tree = {
SECTION: [
{ LINK: [ { GRAPHIC: [ ] } ] },
{ TEXT_LEAF: [ ] },
{ LINK: [ { GRAPHIC: [ ] } ] }
]
{ LINK: [{ GRAPHIC: [] }] },
{ TEXT_LEAF: [] },
{ LINK: [{ GRAPHIC: [] }] },
],
};
testAccessibleTree(container2Parent, tree);
});

Просмотреть файл

@ -8,7 +8,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.

Просмотреть файл

@ -19,7 +19,8 @@
waitForOrderedEvents */
const EVENT_ANNOUNCEMENT = nsIAccessibleEvent.EVENT_ANNOUNCEMENT;
const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
const EVENT_DOCUMENT_LOAD_COMPLETE =
nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
const EVENT_SCROLLING = nsIAccessibleEvent.EVENT_SCROLLING;
@ -35,7 +36,8 @@ const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE;
const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
const EVENT_VIRTUALCURSOR_CHANGED = nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
const EVENT_VIRTUALCURSOR_CHANGED =
nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
/**
* Describe an event in string format.
@ -46,12 +48,16 @@ function eventToString(event) {
let info = `Event type: ${type}`;
if (event instanceof nsIAccessibleStateChangeEvent) {
let stateStr = statesToString(event.isExtraState ? 0 : event.state,
event.isExtraState ? event.state : 0);
let stateStr = statesToString(
event.isExtraState ? 0 : event.state,
event.isExtraState ? event.state : 0
);
info += `, state: ${stateStr}, is enabled: ${event.isEnabled}`;
} else if (event instanceof nsIAccessibleTextChangeEvent) {
let tcType = event.isInserted ? "inserted" : "removed";
info += `, start: ${event.start}, length: ${event.length}, ${tcType} text: ${event.modifiedText}`;
info += `, start: ${event.start}, length: ${
event.length
}, ${tcType} text: ${event.modifiedText}`;
}
info += `. Target: ${prettyName(event.accessible)}`;
@ -121,7 +127,7 @@ function waitForEvent(eventType, matchCriteria) {
Services.obs.removeObserver(this, "accessible-event");
resolve(event);
}
}
},
};
Services.obs.addObserver(eventObserver, "accessible-event");
});
@ -142,8 +148,10 @@ class UnexpectedEvents {
let event = subject.QueryInterface(nsIAccessibleEvent);
let unexpectedEvent = this.unexpected.find(([etype, criteria]) =>
etype === event.eventType && matchEvent(event, criteria));
let unexpectedEvent = this.unexpected.find(
([etype, criteria]) =>
etype === event.eventType && matchEvent(event, criteria)
);
if (unexpectedEvent) {
ok(false, `Got unexpected event: ${eventToString(event)}`);
@ -171,16 +179,17 @@ function waitForEvents(events, ordered = false) {
let unexpectedListener = new UnexpectedEvents(unexpected);
return Promise.all(expected.map((evt, idx) => {
let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
return promise.then(result => {
if (ordered) {
is(idx, currentIdx++,
`Unexpected event order: ${result}`);
}
return result;
});
})).then(results => {
return Promise.all(
expected.map((evt, idx) => {
let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
return promise.then(result => {
if (ordered) {
is(idx, currentIdx++, `Unexpected event order: ${result}`);
}
return result;
});
})
).then(results => {
unexpectedListener.stop();
return results;
});

Просмотреть файл

@ -35,23 +35,28 @@ async function runTests(browser, accDoc) {
expected: [
[EVENT_REORDER, getAccessible(browser)],
[EVENT_DOCUMENT_LOAD_COMPLETE, "body2"],
[EVENT_STATE_CHANGE, busyChecker(false)]],
[EVENT_STATE_CHANGE, busyChecker(false)],
],
unexpected: [
[EVENT_DOCUMENT_LOAD_COMPLETE, inIframeChecker("iframe1")],
[EVENT_STATE_CHANGE, inIframeChecker("iframe1")]]
[EVENT_STATE_CHANGE, inIframeChecker("iframe1")],
],
});
BrowserTestUtils.loadURI(browser, `data:text/html;charset=utf-8,
BrowserTestUtils.loadURI(
browser,
`data:text/html;charset=utf-8,
<html><body id="body2">
<iframe id="iframe1" src="http://example.com"></iframe>
</body></html>`);
</body></html>`
);
await onLoadEvents;
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:about")],
[EVENT_STATE_CHANGE, busyChecker(false)],
[EVENT_REORDER, getAccessible(browser)]
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:about")],
[EVENT_STATE_CHANGE, busyChecker(false)],
[EVENT_REORDER, getAccessible(browser)],
]);
BrowserTestUtils.loadURI(browser, "about:about");
@ -61,7 +66,7 @@ async function runTests(browser, accDoc) {
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_RELOAD, evt => evt.isFromUserInput],
[EVENT_REORDER, getAccessible(browser)],
[EVENT_STATE_CHANGE, busyChecker(false)]
[EVENT_STATE_CHANGE, busyChecker(false)],
]);
EventUtils.synthesizeKey("VK_F5", {}, browser.ownerGlobal);
@ -71,7 +76,7 @@ async function runTests(browser, accDoc) {
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:mozilla")],
[EVENT_STATE_CHANGE, busyChecker(false)],
[EVENT_REORDER, getAccessible(browser)]
[EVENT_REORDER, getAccessible(browser)],
]);
BrowserTestUtils.loadURI(browser, "about:mozilla");
@ -81,7 +86,7 @@ async function runTests(browser, accDoc) {
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_RELOAD, evt => !evt.isFromUserInput],
[EVENT_REORDER, getAccessible(browser)],
[EVENT_STATE_CHANGE, busyChecker(false)]
[EVENT_STATE_CHANGE, busyChecker(false)],
]);
browser.reload();
@ -91,7 +96,7 @@ async function runTests(browser, accDoc) {
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("http://www.wronguri.wronguri/")],
[EVENT_STATE_CHANGE, busyChecker(false)],
[EVENT_REORDER, getAccessible(browser)]
[EVENT_REORDER, getAccessible(browser)],
]);
BrowserTestUtils.loadURI(browser, "http://www.wronguri.wronguri/");
@ -101,7 +106,7 @@ async function runTests(browser, accDoc) {
onLoadEvents = waitForEvents([
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("https://nocert.example.com/")],
[EVENT_STATE_CHANGE, busyChecker(false)],
[EVENT_REORDER, getAccessible(browser)]
[EVENT_REORDER, getAccessible(browser)],
]);
BrowserTestUtils.loadURI(browser, "https://nocert.example.com:443/");

Просмотреть файл

@ -6,8 +6,10 @@
/* import-globals-from ../../mochitest/states.js */
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR }
);
async function runTests(browser, accDoc) {
let onFocus = waitForEvent(EVENT_FOCUS, "input");
@ -16,9 +18,11 @@ async function runTests(browser, accDoc) {
testStates(evt.accessible, STATE_FOCUSED);
onFocus = waitForEvent(EVENT_FOCUS, "buttonInputDoc");
let url = snippetToURL(`<input id="input" type="button" value="button">`, { id: "buttonInputDoc" });
let url = snippetToURL(`<input id="input" type="button" value="button">`, {
id: "buttonInputDoc",
});
browser.loadURI(url, {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
evt = await onFocus;
testStates(evt.accessible, STATE_FOCUSED);

Просмотреть файл

@ -6,8 +6,10 @@
/* import-globals-from ../../mochitest/states.js */
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR }
);
async function runTests(browser, accDoc) {
let onFocus = waitForEvent(EVENT_FOCUS, "button");
@ -32,7 +34,9 @@ async function runTests(browser, accDoc) {
onFocus = waitForEvent(EVENT_FOCUS, "body2");
await ContentTask.spawn(browser, {}, () => {
content.document.getElementById("editabledoc").contentWindow.document.body.focus();
content.document
.getElementById("editabledoc")
.contentWindow.document.body.focus();
});
testStates((await onFocus).accessible, STATE_FOCUSED);
@ -55,13 +59,16 @@ async function runTests(browser, accDoc) {
/**
* Accessible dialog focus testing
*/
addAccessibleTask(`
addAccessibleTask(
`
<button id="button">button</button>
<iframe id="editabledoc"
src="${snippetToURL("", { id: "body2", contentEditable: "true"})}">
src="${snippetToURL("", { id: "body2", contentEditable: "true" })}">
</iframe>
<div id="alertdialog" style="display: none" tabindex="-1" role="alertdialog" aria-labelledby="title2" aria-describedby="desc2">
<div id="title2">Blah blah</div>
<div id="desc2">Woof woof woof.</div>
<button>Close</button>
</div>`, runTests);
</div>`,
runTests
);

Просмотреть файл

@ -5,12 +5,20 @@
/* import-globals-from ../../mochitest/states.js */
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR });
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
loadScripts(
{ name: "states.js", dir: MOCHITESTS_DIR },
{ name: "role.js", dir: MOCHITESTS_DIR }
);
ChromeUtils.defineModuleGetter(
this,
"PlacesTestUtils",
"resource://testing-common/PlacesTestUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm"
);
function isEventForAutocompleteItem(event) {
return event.accessible.role == ROLE_COMBOBOX_OPTION;
@ -26,13 +34,16 @@ function waitForSearchFinish() {
if (UrlbarPrefs.get("quantumbar")) {
return Promise.all([
gURLBar.lastQueryContextPromise,
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen)
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen),
]);
}
return BrowserTestUtils.waitForCondition(() =>
(gURLBar.popupOpen && gURLBar.controller.searchStatus >=
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH),
"Waiting for search to complete");
return BrowserTestUtils.waitForCondition(
() =>
gURLBar.popupOpen &&
gURLBar.controller.searchStatus >=
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH,
"Waiting for search to complete"
);
}
// Check that the URL bar manages accessibility focus appropriately.
@ -42,14 +53,16 @@ async function runTests() {
});
await PlacesTestUtils.addVisits([
{uri: makeURI("http://example1.com/blah")},
{uri: makeURI("http://example2.com/blah")},
{uri: makeURI("http://example1.com/")},
{uri: makeURI("http://example2.com/")}
{ uri: makeURI("http://example1.com/blah") },
{ uri: makeURI("http://example2.com/blah") },
{ uri: makeURI("http://example1.com/") },
{ uri: makeURI("http://example2.com/") },
]);
let focused = waitForEvent(EVENT_FOCUS,
event => event.accessible.role == ROLE_ENTRY);
let focused = waitForEvent(
EVENT_FOCUS,
event => event.accessible.role == ROLE_ENTRY
);
gURLBar.focus();
let event = await focused;
let textBox = event.accessible;
@ -75,7 +88,7 @@ async function runTests() {
testStates(textBox, STATE_FOCUSED);
info("Ensuring no focus change on text selection and delete");
EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
EventUtils.synthesizeKey("KEY_Delete");
await waitForSearchFinish();
// Wait a tick for a11y events to fire.
@ -97,13 +110,13 @@ async function runTests() {
if (AppConstants.platform == "macosx") {
info("Ensuring focus of another autocomplete item on ctrl-n");
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
EventUtils.synthesizeKey("n", {ctrlKey: true});
EventUtils.synthesizeKey("n", { ctrlKey: true });
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring focus of another autocomplete item on ctrl-p");
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
EventUtils.synthesizeKey("p", {ctrlKey: true});
EventUtils.synthesizeKey("p", { ctrlKey: true });
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
}
@ -164,7 +177,7 @@ async function runTests() {
info("Ensuring text box focus on text selection");
focused = waitForEvent(EVENT_FOCUS, textBox);
EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
await focused;
testStates(textBox, STATE_FOCUSED);
@ -175,7 +188,7 @@ async function runTests() {
info("Ensuring autocomplete focus on ctrl-n");
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
EventUtils.synthesizeKey("n", {ctrlKey: true});
EventUtils.synthesizeKey("n", { ctrlKey: true });
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
}

Просмотреть файл

@ -4,47 +4,71 @@
"use strict";
addAccessibleTask(`
addAccessibleTask(
`
<div style="height: 100vh" id="one">one</div>
<div style="height: 100vh" id="two">two</div>
<div style="height: 100vh; width: 200vw" id="three">three</div>`,
async function(browser, accDoc) {
let onScrolling = waitForEvents([
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
[EVENT_SCROLLING, accDoc],
[EVENT_SCROLLING_END, accDoc],
]);
await ContentTask.spawn(browser, null, () => {
content.location.hash = "#two";
});
let [scrollEvent1, scrollEndEvent1] = await onScrolling;
scrollEvent1.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEvent1.maxScrollY >= scrollEvent1.scrollY, "scrollY is within max");
ok(
scrollEvent1.maxScrollY >= scrollEvent1.scrollY,
"scrollY is within max"
);
scrollEndEvent1.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEndEvent1.maxScrollY >= scrollEndEvent1.scrollY,
"scrollY is within max");
ok(
scrollEndEvent1.maxScrollY >= scrollEndEvent1.scrollY,
"scrollY is within max"
);
onScrolling = waitForEvents([
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
[EVENT_SCROLLING, accDoc],
[EVENT_SCROLLING_END, accDoc],
]);
await ContentTask.spawn(browser, null, () => {
content.location.hash = "#three";
});
let [scrollEvent2, scrollEndEvent2] = await onScrolling;
scrollEvent2.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEvent2.scrollY > scrollEvent1.scrollY,
`${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}`);
ok(
scrollEvent2.scrollY > scrollEvent1.scrollY,
`${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}`
);
scrollEndEvent2.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEndEvent2.maxScrollY >= scrollEndEvent2.scrollY,
"scrollY is within max");
ok(
scrollEndEvent2.maxScrollY >= scrollEndEvent2.scrollY,
"scrollY is within max"
);
onScrolling = waitForEvents([
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
[EVENT_SCROLLING, accDoc],
[EVENT_SCROLLING_END, accDoc],
]);
await ContentTask.spawn(browser, null, () => {
content.scrollTo(10, 0);
});
let [scrollEvent3, scrollEndEvent3] = await onScrolling;
scrollEvent3.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEvent3.maxScrollX >= scrollEvent3.scrollX, "scrollX is within max");
ok(
scrollEvent3.maxScrollX >= scrollEvent3.scrollX,
"scrollX is within max"
);
scrollEndEvent3.QueryInterface(nsIAccessibleScrollingEvent);
ok(scrollEndEvent3.maxScrollX >= scrollEndEvent3.scrollX,
"scrollY is within max");
ok(scrollEvent3.scrollX > scrollEvent2.scrollX,
`${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}`);
});
ok(
scrollEndEvent3.maxScrollX >= scrollEndEvent3.scrollX,
"scrollY is within max"
);
ok(
scrollEvent3.scrollX > scrollEvent2.scrollX,
`${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}`
);
}
);

Просмотреть файл

@ -9,7 +9,10 @@
function caretMoveChecker(target, caretOffset) {
return function(event) {
let cmEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
return cmEvent.accessible == getAccessible(target) && cmEvent.caretOffset == caretOffset;
return (
cmEvent.accessible == getAccessible(target) &&
cmEvent.caretOffset == caretOffset
);
};
}
@ -18,24 +21,21 @@ async function checkURLBarCaretEvents() {
let newWin = await BrowserTestUtils.openNewBrowserWindow();
BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, kURL);
await waitForEvent(
EVENT_DOCUMENT_LOAD_COMPLETE,
event => {
try {
return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
} catch (e) {
return false;
}
await waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, event => {
try {
return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
} catch (e) {
return false;
}
);
});
info("Loaded " + kURL);
let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
let urlbarInput = getAccessible(urlbarInputEl, [ nsIAccessibleText ]);
let urlbarInput = getAccessible(urlbarInputEl, [nsIAccessibleText]);
let onCaretMove = waitForEvents([
[ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length) ],
[ EVENT_FOCUS, urlbarInput ]
[EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length)],
[EVENT_FOCUS, urlbarInput],
]);
urlbarInput.caretOffset = -1;
@ -43,7 +43,8 @@ async function checkURLBarCaretEvents() {
ok(true, "Caret move in URL bar #1");
onCaretMove = waitForEvent(
EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, 0)
EVENT_TEXT_CARET_MOVED,
caretMoveChecker(urlbarInput, 0)
);
urlbarInput.caretOffset = 0;

Просмотреть файл

@ -8,7 +8,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.

Просмотреть файл

@ -37,11 +37,13 @@ add_task(async function testDocumentCreation() {
info("Verifying that each tab content document is in accessible cache.");
for (const browser of [...gBrowser.browsers]) {
await ContentTask.spawn(browser, null, async () => {
let accServiceContent =
Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
ok(!!accServiceContent.getAccessibleFromCache(content.document),
"Document accessible is in cache.");
let accServiceContent = Cc[
"@mozilla.org/accessibilityService;1"
].getService(Ci.nsIAccessibilityService);
ok(
!!accServiceContent.getAccessibleFromCache(content.document),
"Document accessible is in cache."
);
});
}

Просмотреть файл

@ -4,7 +4,9 @@
"use strict";
const {UrlbarTestUtils} = ChromeUtils.import("resource://testing-common/UrlbarTestUtils.jsm");
const { UrlbarTestUtils } = ChromeUtils.import(
"resource://testing-common/UrlbarTestUtils.jsm"
);
// Checking that the awesomebar popup gets COMBOBOX_LIST role instead of
// LISTBOX, since its parent is a <panel> (see Bug 1422465)
@ -12,22 +14,32 @@ add_task(async function testAutocompleteRichResult() {
let tab = await openNewTab("data:text/html;charset=utf-8,");
let accService = await initAccessibilityService();
info("Opening the URL bar and entering a key to show the PopupAutoCompleteRichResult panel");
info(
"Opening the URL bar and entering a key to show the PopupAutoCompleteRichResult panel"
);
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
waitForFocus,
value: "a"
value: "a",
});
info("Waiting for accessibility to be created for the richlistbox");
let resultsView;
if (UrlbarPrefs.get("quantumbar")) {
resultsView = gURLBar.view.panel.querySelector("#urlbarView-results");
await BrowserTestUtils.waitForCondition(() => accService.getAccessibleFor(resultsView));
await BrowserTestUtils.waitForCondition(() =>
accService.getAccessibleFor(resultsView)
);
} else {
let urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
resultsView = document.getAnonymousElementByAttribute(urlbarPopup, "anonid", "richlistbox");
await BrowserTestUtils.waitForCondition(() => accService.getAccessibleFor(resultsView));
resultsView = document.getAnonymousElementByAttribute(
urlbarPopup,
"anonid",
"richlistbox"
);
await BrowserTestUtils.waitForCondition(() =>
accService.getAccessibleFor(resultsView)
);
}
info("Confirming that the special case is handled in XULListboxAccessible");

Просмотреть файл

@ -10,7 +10,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
const nsIAccessibleRole = Ci.nsIAccessibleRole; // eslint-disable-line no-unused-vars
@ -20,14 +21,18 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
async function openNewTab(url) {
const forceNewProcess = true;
return BrowserTestUtils.openNewForegroundTab(
{ gBrowser, url, forceNewProcess });
return BrowserTestUtils.openNewForegroundTab({
gBrowser,
url,
forceNewProcess,
});
}
async function initAccessibilityService() {
info("Create accessibility service.");
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
Ci.nsIAccessibilityService
);
await new Promise(resolve => {
if (Services.appinfo.accessibilityEnabled) {

Просмотреть файл

@ -13,11 +13,13 @@
*/
function setE10sPrefs() {
return new Promise(resolve =>
SpecialPowers.pushPrefEnv({
set: [
["browser.tabs.remote.autostart", true]
]
}, resolve));
SpecialPowers.pushPrefEnv(
{
set: [["browser.tabs.remote.autostart", true]],
},
resolve
)
);
}
/**
@ -34,7 +36,8 @@ function unsetE10sPrefs() {
/* import-globals-from shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
/**
* Returns a promise that resolves when 'a11y-consumers-changed' event is fired.
@ -81,7 +84,8 @@ function contentA11yInitOrShutdownPromise(browser) {
*/
function promiseOK(promise, expected) {
return promise.then(flag =>
flag === expected ? Promise.resolve() : Promise.reject());
flag === expected ? Promise.resolve() : Promise.reject()
);
}
/**
@ -94,12 +98,13 @@ function promiseOK(promise, expected) {
* service initialized correctly.
*/
function initPromise(contentBrowser) {
let a11yInitPromise = contentBrowser ?
contentA11yInitOrShutdownPromise(contentBrowser) :
a11yInitOrShutdownPromise();
let a11yInitPromise = contentBrowser
? contentA11yInitOrShutdownPromise(contentBrowser)
: a11yInitOrShutdownPromise();
return promiseOK(a11yInitPromise, "1").then(
() => ok(true, "Service initialized correctly"),
() => ok(false, "Service shutdown incorrectly"));
() => ok(false, "Service shutdown incorrectly")
);
}
/**
@ -112,12 +117,13 @@ function initPromise(contentBrowser) {
* service shuts down correctly.
*/
function shutdownPromise(contentBrowser) {
let a11yShutdownPromise = contentBrowser ?
contentA11yInitOrShutdownPromise(contentBrowser) :
a11yInitOrShutdownPromise();
let a11yShutdownPromise = contentBrowser
? contentA11yInitOrShutdownPromise(contentBrowser)
: a11yInitOrShutdownPromise();
return promiseOK(a11yShutdownPromise, "0").then(
() => ok(true, "Service shutdown correctly"),
() => ok(false, "Service initialized incorrectly"));
() => ok(false, "Service initialized incorrectly")
);
}
/**
@ -135,12 +141,11 @@ function waitForEvent(eventType, expectedId) {
} catch (e) {
// This can throw NS_ERROR_FAILURE.
}
if (event.eventType === eventType &&
id === expectedId) {
if (event.eventType === eventType && id === expectedId) {
Services.obs.removeObserver(this, "accessible-event");
resolve(event);
}
}
},
};
Services.obs.addObserver(eventObserver, "accessible-event");
});

Просмотреть файл

@ -10,32 +10,47 @@ loadScripts({ name: "layout.js", dir: MOCHITESTS_DIR });
async function runTests(browser, accDoc) {
loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR });
let paragraph = findAccessibleChildByID(accDoc, "paragraph", [nsIAccessibleText]);
let paragraph = findAccessibleChildByID(accDoc, "paragraph", [
nsIAccessibleText,
]);
let offset = 64; // beginning of 4th stanza
let [x /* ,y*/] = getPos(paragraph);
let [docX, docY] = getPos(accDoc);
paragraph.scrollSubstringToPoint(offset, offset,
COORDTYPE_SCREEN_RELATIVE, docX, docY);
paragraph.scrollSubstringToPoint(
offset,
offset,
COORDTYPE_SCREEN_RELATIVE,
docX,
docY
);
testTextPos(paragraph, offset, [x, docY], COORDTYPE_SCREEN_RELATIVE);
await ContentTask.spawn(browser, {}, () => {
zoomDocument(content.document, 2.0);
});
paragraph = findAccessibleChildByID(accDoc, "paragraph2", [nsIAccessibleText]);
paragraph = findAccessibleChildByID(accDoc, "paragraph2", [
nsIAccessibleText,
]);
offset = 52; // // beginning of 4th stanza
[x /* ,y*/] = getPos(paragraph);
paragraph.scrollSubstringToPoint(offset, offset,
COORDTYPE_SCREEN_RELATIVE, docX, docY);
paragraph.scrollSubstringToPoint(
offset,
offset,
COORDTYPE_SCREEN_RELATIVE,
docX,
docY
);
testTextPos(paragraph, offset, [x, docY], COORDTYPE_SCREEN_RELATIVE);
}
/**
* Test caching of accessible object states
*/
addAccessibleTask(`
addAccessibleTask(
`
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>

Просмотреть файл

@ -8,7 +8,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.

Просмотреть файл

@ -79,7 +79,7 @@ let Logger = {
if (this.dumpToAppConsole) {
Services.console.logStringMessage(`${msg}`);
}
}
},
};
/**
@ -98,7 +98,9 @@ function invokeSetAttribute(browser, id, attr, value) {
} else {
Logger.log(`Removing ${attr} attribute from node with id: ${id}`);
}
return ContentTask.spawn(browser, [id, attr, value],
return ContentTask.spawn(
browser,
[id, attr, value],
([contentId, contentAttr, contentValue]) => {
let elm = content.document.getElementById(contentId);
if (contentValue) {
@ -106,7 +108,8 @@ function invokeSetAttribute(browser, id, attr, value) {
} else {
elm.removeAttribute(contentAttr);
}
});
}
);
}
/**
@ -125,7 +128,9 @@ function invokeSetStyle(browser, id, style, value) {
} else {
Logger.log(`Removing ${style} style from node with id: ${id}`);
}
return ContentTask.spawn(browser, [id, style, value],
return ContentTask.spawn(
browser,
[id, style, value],
([contentId, contentStyle, contentValue]) => {
let elm = content.document.getElementById(contentId);
if (contentValue) {
@ -133,7 +138,8 @@ function invokeSetStyle(browser, id, style, value) {
} else {
delete elm.style[contentStyle];
}
});
}
);
}
/**
@ -160,8 +166,10 @@ function invokeFocus(browser, id) {
*/
function loadScripts(...scripts) {
for (let script of scripts) {
let path = typeof script === "string" ? `${CURRENT_DIR}${script}` :
`${script.dir}${script.name}`;
let path =
typeof script === "string"
? `${CURRENT_DIR}${script}`
: `${script.dir}${script.name}`;
Services.scriptloader.loadSubScript(path, this);
}
}
@ -213,8 +221,9 @@ function loadFrameScripts(browser, ...scripts) {
**/
function snippetToURL(snippet, bodyAttrs = {}) {
let attrs = Object.assign({}, { id: "body" }, bodyAttrs);
let attrsString = Object.entries(attrs).map(
([attr, value]) => `${attr}=${JSON.stringify(value)}`).join(" ");
let attrsString = Object.entries(attrs)
.map(([attr, value]) => `${attr}=${JSON.stringify(value)}`)
.join(" ");
let encodedDoc = encodeURIComponent(
`<html>
<head>
@ -222,7 +231,8 @@ function snippetToURL(snippet, bodyAttrs = {}) {
<title>Accessibility Test</title>
</head>
<body ${attrsString}>${snippet}</body>
</html>`);
</html>`
);
return `data:text/html;charset=utf-8,${encodedDoc}`;
}
@ -246,39 +256,47 @@ function addAccessibleTask(doc, task) {
}
registerCleanupFunction(() => {
for (let observer of Services.obs.enumerateObservers("accessible-event")) {
for (let observer of Services.obs.enumerateObservers(
"accessible-event"
)) {
Services.obs.removeObserver(observer, "accessible-event");
}
});
let onDocLoad = waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, "body");
await BrowserTestUtils.withNewTab({
gBrowser,
url
}, async function(browser) {
registerCleanupFunction(() => {
if (browser) {
let tab = gBrowser.getTabForBrowser(browser);
if (tab && !tab.closing && tab.linkedBrowser) {
gBrowser.removeTab(tab);
await BrowserTestUtils.withNewTab(
{
gBrowser,
url,
},
async function(browser) {
registerCleanupFunction(() => {
if (browser) {
let tab = gBrowser.getTabForBrowser(browser);
if (tab && !tab.closing && tab.linkedBrowser) {
gBrowser.removeTab(tab);
}
}
}
});
});
await SimpleTest.promiseFocus(browser);
await SimpleTest.promiseFocus(browser);
loadFrameScripts(browser,
"let { document, window, navigator } = content;",
{ name: "common.js", dir: MOCHITESTS_DIR });
loadFrameScripts(
browser,
"let { document, window, navigator } = content;",
{ name: "common.js", dir: MOCHITESTS_DIR }
);
Logger.log(
`e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`);
Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
Logger.log(
`e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`
);
Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
let event = await onDocLoad;
await task(browser, event.accessible);
});
let event = await onDocLoad;
await task(browser, event.accessible);
}
);
});
}
@ -356,7 +374,8 @@ function queryInterfaces(accessible, interfaces) {
function arrayFromChildren(accessible) {
return Array.from({ length: accessible.childCount }, (c, i) =>
accessible.getChildAt(i));
accessible.getChildAt(i)
);
}
/**

Просмотреть файл

@ -6,8 +6,10 @@
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR }
);
async function runTests(browser, accDoc) {
let getAcc = id => findAccessibleChildByID(accDoc, id);
@ -18,8 +20,13 @@ async function runTests(browser, accDoc) {
let onStateChanged = waitForEvent(EVENT_STATE_CHANGE, "link_traversed");
let newWinOpened = BrowserTestUtils.waitForNewWindow();
await BrowserTestUtils.synthesizeMouse("#link_traversed",
1, 1, { shiftKey: true }, browser);
await BrowserTestUtils.synthesizeMouse(
"#link_traversed",
1,
1,
{ shiftKey: true },
browser
);
await onStateChanged;
testStates(getAcc("link_traversed"), STATE_TRAVERSED);
@ -31,8 +38,10 @@ async function runTests(browser, accDoc) {
/**
* Test caching of accessible object states
*/
addAccessibleTask(`
addAccessibleTask(
`
<a id="link_traversed" href="http://www.example.com" target="_top">
example.com
</a>`, runTests
</a>`,
runTests
);

Просмотреть файл

@ -6,8 +6,10 @@
/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR });
loadScripts(
{ name: "role.js", dir: MOCHITESTS_DIR },
{ name: "states.js", dir: MOCHITESTS_DIR }
);
async function runTest(browser, accDoc) {
let getAcc = id => findAccessibleChildByID(accDoc, id);
@ -38,11 +40,13 @@ async function runTest(browser, accDoc) {
BrowserTestUtils.removeTab(newTab);
}
addAccessibleTask(`
addAccessibleTask(
`
<div id="div" style="border:2px solid blue; width: 500px; height: 110vh;"></div>
<input id="input_scrolledoff">
<ul style="border:2px solid red; width: 100px; height: 50px; overflow: auto;">
<li id="li_first">item1</li><li>item2</li><li>item3</li>
<li>item4</li><li>item5</li><li id="li_last">item6</li>
</ul>`, runTest
</ul>`,
runTest
);

Просмотреть файл

@ -8,7 +8,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.

Просмотреть файл

@ -8,7 +8,8 @@ let NO_MOVE = { unexpected: [[EVENT_REORDER, "container"]] };
let MOVE = { expected: [[EVENT_REORDER, "container"]] };
// Set last ordinal child as aria-owned, should produce no reorder.
addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
addAccessibleTask(
`<ul id="container"><li id="a">Test</li></ul>`,
async function(browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc, "container");
@ -16,7 +17,9 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
await contentSpawnMutation(browser, NO_MOVE, function() {
// aria-own ordinal child in place, should be a no-op.
content.document.getElementById("container").setAttribute("aria-owns", "a");
content.document
.getElementById("container")
.setAttribute("aria-owns", "a");
});
testChildrenIds(containerAcc, ["a"]);
@ -25,7 +28,8 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
// Add a new ordinal child to a container with an aria-owned child.
// Order should respect aria-owns.
addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
addAccessibleTask(
`<ul id="container"><li id="a">Test</li></ul>`,
async function(browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc, "container");
@ -51,7 +55,8 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
);
// Remove a no-move aria-owns attribute, should result in a no-move.
addAccessibleTask(`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
addAccessibleTask(
`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
async function(browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc, "container");
@ -67,7 +72,8 @@ addAccessibleTask(`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
);
// Attempt to steal an aria-owned child. The attempt should fail.
addAccessibleTask(`
addAccessibleTask(
`
<ul>
<li id="a">Test</li>
</ul>
@ -79,7 +85,9 @@ addAccessibleTask(`
testChildrenIds(containerAcc, []);
await contentSpawnMutation(browser, NO_MOVE, function() {
content.document.getElementById("container").setAttribute("aria-owns", "a");
content.document
.getElementById("container")
.setAttribute("aria-owns", "a");
});
testChildrenIds(containerAcc, []);
@ -87,7 +95,8 @@ addAccessibleTask(`
);
// Don't aria-own children of <select>
addAccessibleTask(`
addAccessibleTask(
`
<div id="container" role="group" aria-owns="b"></div>
<select id="select">
<option id="a"></option>
@ -103,7 +112,8 @@ addAccessibleTask(`
);
// Don't allow <select> to aria-own
addAccessibleTask(`
addAccessibleTask(
`
<div id="container" role="group">
<div id="a"></div>
<div id="b"></div>
@ -121,7 +131,8 @@ addAccessibleTask(`
);
// Don't allow one <select> to aria-own an <option> from another <select>.
addAccessibleTask(`
addAccessibleTask(
`
<select id="select1" aria-owns="c">
<option id="a"></option>
<option id="b"></option>
@ -139,7 +150,8 @@ addAccessibleTask(`
);
// Don't allow a <select> to reorder its children with aria-owns.
addAccessibleTask(`
addAccessibleTask(
`
<select id="container" aria-owns="c b a">
<option id="a"></option>
<option id="b"></option>
@ -151,7 +163,9 @@ addAccessibleTask(`
testChildrenIds(containerAcc.firstChild, ["a", "b", "c"]);
await contentSpawnMutation(browser, NO_MOVE, function() {
content.document.getElementById("container").setAttribute("aria-owns", "a c b");
content.document
.getElementById("container")
.setAttribute("aria-owns", "a c b");
});
testChildrenIds(containerAcc.firstChild, ["a", "b", "c"]);
@ -159,14 +173,16 @@ addAccessibleTask(`
);
// Don't crash if ID in aria-owns does not exist
addAccessibleTask(`
addAccessibleTask(
`
<select id="container" aria-owns="boom" multiple></select>`,
async function(browser, accDoc) {
ok(true, "Did not crash");
}
);
addAccessibleTask(`
addAccessibleTask(
`
<ul id="one">
<li id="a">Test</li>
<li id="b">Test 2</li>
@ -177,9 +193,9 @@ addAccessibleTask(`
let one = findAccessibleChildByID(accDoc, "one");
let two = findAccessibleChildByID(accDoc, "two");
let waitfor = { expected: [
[EVENT_REORDER, "one"],
[EVENT_REORDER, "two"]] };
let waitfor = {
expected: [[EVENT_REORDER, "one"], [EVENT_REORDER, "two"]],
};
await contentSpawnMutation(browser, waitfor, function() {
// Put same id twice in aria-owns
@ -200,27 +216,29 @@ addAccessibleTask(`
}
);
addAccessibleTask(`<div id="a"></div><div id="b"></div>`,
async function(browser, accDoc) {
testChildrenIds(accDoc, ["a", "b"]);
addAccessibleTask(`<div id="a"></div><div id="b"></div>`, async function(
browser,
accDoc
) {
testChildrenIds(accDoc, ["a", "b"]);
let waitFor = {
expected: [[ EVENT_REORDER, e => e.accessible == accDoc ]]
};
let waitFor = {
expected: [[EVENT_REORDER, e => e.accessible == accDoc]],
};
await contentSpawnMutation(browser, waitFor, function() {
content.document.documentElement.style.display = "none";
content.document.documentElement.getBoundingClientRect();
content.document.body.setAttribute("aria-owns", "b a");
content.document.documentElement.remove();
});
await contentSpawnMutation(browser, waitFor, function() {
content.document.documentElement.style.display = "none";
content.document.documentElement.getBoundingClientRect();
content.document.body.setAttribute("aria-owns", "b a");
content.document.documentElement.remove();
});
testChildrenIds(accDoc, []);
}
);
testChildrenIds(accDoc, []);
});
// Don't allow ordinal child to be placed after aria-owned child (bug 1405796)
addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
addAccessibleTask(
`<div id="container"><div id="a">Hello</div></div>
<div><div id="c">There</div><div id="d">There</div></div>`,
async function(browser, accDoc) {
let containerAcc = findAccessibleChildByID(accDoc, "container");
@ -228,7 +246,9 @@ addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
testChildrenIds(containerAcc, ["a"]);
await contentSpawnMutation(browser, MOVE, function() {
content.document.getElementById("container").setAttribute("aria-owns", "c");
content.document
.getElementById("container")
.setAttribute("aria-owns", "c");
});
testChildrenIds(containerAcc, ["a", "c"]);
@ -245,7 +265,9 @@ addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
testChildrenIds(containerAcc, ["a", "b", "c"]);
await contentSpawnMutation(browser, MOVE, function() {
content.document.getElementById("container").setAttribute("aria-owns", "c d");
content.document
.getElementById("container")
.setAttribute("aria-owns", "c d");
});
testChildrenIds(containerAcc, ["a", "b", "c", "d"]);

Просмотреть файл

@ -10,7 +10,8 @@
/* import-globals-from ../shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
this
);
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
// well as events.js.
@ -22,6 +23,9 @@ loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
*/
function testChildrenIds(acc, expectedIds) {
let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
Assert.deepEqual(ids, expectedIds,
`Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
Assert.deepEqual(
ids,
expectedIds,
`Children for ${getAccessibleDOMNodeID(acc)} are wrong.`
);
}

Просмотреть файл

@ -56,33 +56,44 @@ function testActions(aArray) {
var actionIndex = actionObj.actionIndex;
var actionName = actionObj.actionName;
var events = actionObj.events;
var accOrElmOrIDOfTarget = actionObj.targetID ?
actionObj.targetID : accOrElmOrID;
var accOrElmOrIDOfTarget = actionObj.targetID
? actionObj.targetID
: accOrElmOrID;
var eventSeq = [];
if (events) {
var elm = getNode(accOrElmOrIDOfTarget);
if (events & MOUSEDOWN_EVENT)
if (events & MOUSEDOWN_EVENT) {
eventSeq.push(new checkerOfActionInvoker("mousedown", elm, actionObj));
}
if (events & MOUSEUP_EVENT)
if (events & MOUSEUP_EVENT) {
eventSeq.push(new checkerOfActionInvoker("mouseup", elm, actionObj));
}
if (events & CLICK_EVENT)
if (events & CLICK_EVENT) {
eventSeq.push(new checkerOfActionInvoker("click", elm, actionObj));
}
if (events & COMMAND_EVENT)
if (events & COMMAND_EVENT) {
eventSeq.push(new checkerOfActionInvoker("command", elm, actionObj));
}
if (events & FOCUS_EVENT)
if (events & FOCUS_EVENT) {
eventSeq.push(new focusChecker(elm));
}
}
if (actionObj.eventSeq)
if (actionObj.eventSeq) {
eventSeq = eventSeq.concat(actionObj.eventSeq);
}
var invoker = new actionInvoker(accOrElmOrID, actionIndex, actionName,
eventSeq);
var invoker = new actionInvoker(
accOrElmOrID,
actionIndex,
actionName,
eventSeq
);
gActionsQueue.push(invoker);
}
@ -93,15 +104,21 @@ function testActions(aArray) {
* Test action names and descriptions.
*/
function testActionNames(aID, aActions) {
var actions = (typeof aActions == "string") ?
[ aActions ] : (aActions || []);
var actions = typeof aActions == "string" ? [aActions] : aActions || [];
var acc = getAccessible(aID);
is(acc.actionCount, actions.length, "Wong number of actions.");
for (var i = 0; i < actions.length; i++ ) {
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
is(acc.getActionDescription(0), gActionDescrMap[actions[i]],
"Wrong action description at " + i + "index.");
for (var i = 0; i < actions.length; i++) {
is(
acc.getActionName(i),
actions[i],
"Wrong action name at " + i + " index."
);
is(
acc.getActionDescription(0),
gActionDescrMap[actions[i]],
"Wrong action description at " + i + "index."
);
}
}
@ -113,18 +130,25 @@ var gActionsQueue = null;
function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq) {
this.invoke = function actionInvoker_invoke() {
var acc = getAccessible(aAccOrElmOrId);
if (!acc)
if (!acc) {
return INVOKER_ACTION_FAILED;
}
var isThereActions = acc.actionCount > 0;
ok(isThereActions,
"No actions on the accessible for " + prettyName(aAccOrElmOrId));
ok(
isThereActions,
"No actions on the accessible for " + prettyName(aAccOrElmOrId)
);
if (!isThereActions)
if (!isThereActions) {
return INVOKER_ACTION_FAILED;
}
is(acc.getActionName(aActionIndex), aActionName,
"Wrong action name of the accessible for " + prettyName(aAccOrElmOrId));
is(
acc.getActionName(aActionIndex),
aActionName,
"Wrong action name of the accessible for " + prettyName(aAccOrElmOrId)
);
try {
acc.doAction(aActionIndex);
@ -138,8 +162,14 @@ function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq) {
this.eventSeq = aEventSeq;
this.getID = function actionInvoker_getID() {
return "invoke an action " + aActionName + " at index " + aActionIndex +
" on " + prettyName(aAccOrElmOrId);
return (
"invoke an action " +
aActionName +
" at index " +
aActionIndex +
" on " +
prettyName(aAccOrElmOrId)
);
};
}
@ -159,13 +189,13 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj) {
};
this.check = function check(aEvent) {
if (aType == "click" && aActionObj && "checkOnClickEvent" in aActionObj)
if (aType == "click" && aActionObj && "checkOnClickEvent" in aActionObj) {
aActionObj.checkOnClickEvent(aEvent);
}
};
}
var gActionDescrMap =
{
var gActionDescrMap = {
jump: "Jump",
press: "Press",
check: "Check",

Просмотреть файл

@ -34,13 +34,14 @@ function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs) {
*/
function todoAttr(aAccOrElmOrID, aKey, aExpectedValue) {
var accessible = getAccessible(aAccOrElmOrID);
if (!accessible)
if (!accessible) {
return;
}
var attrs = null;
try {
attrs = accessible.attributes;
} catch (e) { }
} catch (e) {}
todo_is(attrs.getStringProperty(aKey), aExpectedValue, "attributes match");
}
@ -53,7 +54,7 @@ function testCSSAttrs(aID) {
var computedStyle = document.defaultView.getComputedStyle(node);
var attrs = {
"display": computedStyle.display,
display: computedStyle.display,
"text-align": computedStyle.textAlign,
"text-indent": computedStyle.textIndent,
"margin-left": computedStyle.marginLeft,
@ -69,7 +70,7 @@ function testCSSAttrs(aID) {
*/
function testAbsentCSSAttrs(aID) {
var attrs = {
"display": "",
display: "",
"text-align": "",
"text-indent": "",
"margin-left": "",
@ -91,38 +92,53 @@ function testAbsentCSSAttrs(aID) {
*/
function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel) {
var acc = getAccessible(aAccOrElmOrID);
var levelObj = {}, posInSetObj = {}, setSizeObj = {};
var levelObj = {},
posInSetObj = {},
setSizeObj = {};
acc.groupPosition(levelObj, setSizeObj, posInSetObj);
if (aPosInSet && aSetSize) {
is(posInSetObj.value, aPosInSet,
"Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
is(setSizeObj.value, aSetSize,
"Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
is(
posInSetObj.value,
aPosInSet,
"Wrong group position (posinset) for " + prettyName(aAccOrElmOrID)
);
is(
setSizeObj.value,
aSetSize,
"Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID)
);
let attrs = {
"posinset": String(aPosInSet),
"setsize": String(aSetSize),
posinset: String(aPosInSet),
setsize: String(aSetSize),
};
testAttrs(aAccOrElmOrID, attrs, true);
}
if (aLevel) {
is(levelObj.value, aLevel,
"Wrong group level for " + prettyName(aAccOrElmOrID));
is(
levelObj.value,
aLevel,
"Wrong group level for " + prettyName(aAccOrElmOrID)
);
let attrs = { "level": String(aLevel) };
let attrs = { level: String(aLevel) };
testAttrs(aAccOrElmOrID, attrs, true);
}
}
function testGroupParentAttrs(aAccOrElmOrID, aChildItemCount, aIsHierarchical) {
testAttrs(aAccOrElmOrID, { "child-item-count": String(aChildItemCount) }, true);
testAttrs(
aAccOrElmOrID,
{ "child-item-count": String(aChildItemCount) },
true
);
if (aIsHierarchical) {
testAttrs(aAccOrElmOrID, { "hierarchical": "true" }, true);
testAttrs(aAccOrElmOrID, { hierarchical: "true" }, true);
} else {
testAbsentAttrs(aAccOrElmOrID, { "hierarchical": "true" });
testAbsentAttrs(aAccOrElmOrID, { hierarchical: "true" });
}
}
@ -148,21 +164,36 @@ function testGroupParentAttrs(aAccOrElmOrID, aChildItemCount, aIsHierarchical) {
* @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
* unexpected attribute is encountered
*/
function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
aStartOffset, aEndOffset, aSkipUnexpectedAttrs) {
function testTextAttrs(
aID,
aOffset,
aAttrs,
aDefAttrs,
aStartOffset,
aEndOffset,
aSkipUnexpectedAttrs
) {
var accessible = getAccessible(aID, [nsIAccessibleText]);
if (!accessible)
if (!accessible) {
return;
}
var startOffset = { value: -1 };
var endOffset = { value: -1 };
// do not include attributes exposed on hyper text accessible
var attrs = getTextAttributes(aID, accessible, false, aOffset,
startOffset, endOffset);
var attrs = getTextAttributes(
aID,
accessible,
false,
aOffset,
startOffset,
endOffset
);
if (!attrs)
if (!attrs) {
return;
}
var errorMsg = " for " + aID + " at offset " + aOffset;
@ -173,19 +204,28 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
// include attributes exposed on hyper text accessible
var expectedAttrs = {};
for (let name in aAttrs)
for (let name in aAttrs) {
expectedAttrs[name] = aAttrs[name];
for (let name in aDefAttrs) {
if (!(name in expectedAttrs))
expectedAttrs[name] = aDefAttrs[name];
}
attrs = getTextAttributes(aID, accessible, true, aOffset,
startOffset, endOffset);
for (let name in aDefAttrs) {
if (!(name in expectedAttrs)) {
expectedAttrs[name] = aDefAttrs[name];
}
}
if (!attrs)
attrs = getTextAttributes(
aID,
accessible,
true,
aOffset,
startOffset,
endOffset
);
if (!attrs) {
return;
}
compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
}
@ -202,14 +242,14 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
*/
function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) {
var accessible = getAccessible(aID, [nsIAccessibleText]);
if (!accessible)
if (!accessible) {
return;
}
var defAttrs = null;
try {
defAttrs = accessible.defaultTextAttributes;
} catch (e) {
}
} catch (e) {}
if (!defAttrs) {
ok(false, "Can't get default text attributes for " + aID);
@ -226,38 +266,56 @@ function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) {
function testTextAttrsWrongOffset(aID, aOffset) {
var res = false;
try {
var s = {}, e = {};
var acc = getAccessible(ID, [nsIAccessibleText]);
var s = {},
e = {};
var acc = getAccessible(ID, [nsIAccessibleText]);
acc.getTextAttributes(false, 157, s, e);
} catch (ex) {
res = true;
}
ok(res,
"text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID));
ok(
res,
"text attributes are calculated successfully at wrong offset " +
aOffset +
" for " +
prettyName(aID)
);
}
const kNormalFontWeight =
function equalsToNormal(aWeight) { return aWeight <= 400 ; };
const kNormalFontWeight = function equalsToNormal(aWeight) {
return aWeight <= 400;
};
const kBoldFontWeight =
function equalsToBold(aWeight) { return aWeight > 400; };
const kBoldFontWeight = function equalsToBold(aWeight) {
return aWeight > 400;
};
// The pt font size of the input element can vary by Linux distro.
const kInputFontSize = WIN ?
"10pt" : (MAC ? "8pt" : function() { return true; });
const kInputFontSize = WIN
? "10pt"
: MAC
? "8pt"
: function() {
return true;
};
const kAbsentFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; };
const kInputFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; };
const kAbsentFontFamily = function(aFontFamily) {
return aFontFamily != "sans-serif";
};
const kInputFontFamily = function(aFontFamily) {
return aFontFamily != "sans-serif";
};
const kMonospaceFontFamily =
function(aFontFamily) { return aFontFamily != "monospace"; };
const kSansSerifFontFamily =
function(aFontFamily) { return aFontFamily != "sans-serif"; };
const kSerifFontFamily =
function(aFontFamily) { return aFontFamily != "serif"; };
const kMonospaceFontFamily = function(aFontFamily) {
return aFontFamily != "monospace";
};
const kSansSerifFontFamily = function(aFontFamily) {
return aFontFamily != "sans-serif";
};
const kSerifFontFamily = function(aFontFamily) {
return aFontFamily != "serif";
};
const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS";
@ -289,15 +347,17 @@ function fontFamily(aComputedStyle) {
function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) {
var elm = getNode(aID);
var computedStyle = document.defaultView.getComputedStyle(elm);
var bgColor = computedStyle.backgroundColor == "rgba(0, 0, 0, 0)" ?
"rgb(255, 255, 255)" : computedStyle.backgroundColor;
var bgColor =
computedStyle.backgroundColor == "rgba(0, 0, 0, 0)"
? "rgb(255, 255, 255)"
: computedStyle.backgroundColor;
var defAttrs = {
"font-style": computedStyle.fontStyle,
"font-size": aFontSize,
"background-color": bgColor,
"font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
"color": computedStyle.color,
color: computedStyle.color,
"font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle),
"text-position": computedStyle.verticalAlign,
};
@ -308,34 +368,49 @@ function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) {
// //////////////////////////////////////////////////////////////////////////////
// Private.
function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset) {
function getTextAttributes(
aID,
aAccessible,
aIncludeDefAttrs,
aOffset,
aStartOffset,
aEndOffset
) {
// This function expects the passed in accessible to already be queried for
// nsIAccessibleText.
var attrs = null;
try {
attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
aStartOffset, aEndOffset);
} catch (e) {
}
attrs = aAccessible.getTextAttributes(
aIncludeDefAttrs,
aOffset,
aStartOffset,
aEndOffset
);
} catch (e) {}
if (attrs)
if (attrs) {
return attrs;
}
ok(false, "Can't get text attributes for " + aID);
return null;
}
function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
aAbsentAttrs) {
function testAttrsInternal(
aAccOrElmOrID,
aAttrs,
aSkipUnexpectedAttrs,
aAbsentAttrs
) {
var accessible = getAccessible(aAccOrElmOrID);
if (!accessible)
if (!accessible) {
return;
}
var attrs = null;
try {
attrs = accessible.attributes;
} catch (e) { }
} catch (e) {}
if (!attrs) {
ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID));
@ -346,22 +421,36 @@ function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs);
}
function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
aAbsentAttrs) {
function compareAttrs(
aErrorMsg,
aAttrs,
aExpectedAttrs,
aSkipUnexpectedAttrs,
aAbsentAttrs
) {
// Check if all obtained attributes are expected and have expected value.
for (let prop of aAttrs.enumerate()) {
if (!(prop.key in aExpectedAttrs)) {
if (!aSkipUnexpectedAttrs)
ok(false, "Unexpected attribute '" + prop.key + "' having '" +
prop.value + "'" + aErrorMsg);
if (!aSkipUnexpectedAttrs) {
ok(
false,
"Unexpected attribute '" +
prop.key +
"' having '" +
prop.value +
"'" +
aErrorMsg
);
}
} else {
var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg;
var expectedValue = aExpectedAttrs[prop.key];
if (typeof expectedValue == "function")
if (typeof expectedValue == "function") {
ok(expectedValue(prop.value), msg);
else
} else {
is(prop.value, expectedValue, msg);
}
}
}
@ -370,11 +459,11 @@ function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
var value = "";
try {
value = aAttrs.getStringProperty(name);
} catch (e) { }
} catch (e) {}
if (!value)
ok(false,
"There is no expected attribute '" + name + "' " + aErrorMsg);
if (!value) {
ok(false, "There is no expected attribute '" + name + "' " + aErrorMsg);
}
}
// Check if all unexpected attributes are absent.
@ -383,12 +472,15 @@ function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
var wasFound = false;
for (let prop of aAttrs.enumerate()) {
if (prop.key == name)
if (prop.key == name) {
wasFound = true;
}
}
}
ok(!wasFound,
"There is an unexpected attribute '" + name + "' " + aErrorMsg);
ok(
!wasFound,
"There is an unexpected attribute '" + name + "' " + aErrorMsg
);
}
}

Просмотреть файл

@ -1,4 +1,3 @@
const nsISupports = Ci.nsISupports;
const nsIAutoCompleteResult = Ci.nsIAutoCompleteResult;
const nsIAutoCompleteSearch = Ci.nsIAutoCompleteSearch;
@ -16,10 +15,14 @@ var gDefaultAutoCompleteSearch = null;
*/
function initAutoComplete(aValues, aComments) {
var allResults = new ResultsHeap(aValues, aComments);
gDefaultAutoCompleteSearch =
new AutoCompleteSearch("test-a11y-search", allResults);
registerAutoCompleteSearch(gDefaultAutoCompleteSearch,
"Accessibility Test AutoCompleteSearch");
gDefaultAutoCompleteSearch = new AutoCompleteSearch(
"test-a11y-search",
allResults
);
registerAutoCompleteSearch(
gDefaultAutoCompleteSearch,
"Accessibility Test AutoCompleteSearch"
);
}
/**
@ -31,7 +34,6 @@ function shutdownAutoComplete() {
gDefaultAutoCompleteSearch = null;
}
/**
* Register the given AutoCompleteSearch.
*
@ -41,11 +43,14 @@ function shutdownAutoComplete() {
function registerAutoCompleteSearch(aSearch, aDescription) {
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
getService(nsIUUIDGenerator);
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
nsIUUIDGenerator
);
var cid = uuidGenerator.generateUUID();
var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar);
var componentManager = Components.manager.QueryInterface(
nsIComponentRegistrar
);
componentManager.registerFactory(cid, aDescription, name, aSearch);
// Keep the id on the object so we can unregister later.
@ -56,11 +61,12 @@ function registerAutoCompleteSearch(aSearch, aDescription) {
* Unregister the given AutoCompleteSearch.
*/
function unregisterAutoCompleteSearch(aSearch) {
var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar);
var componentManager = Components.manager.QueryInterface(
nsIComponentRegistrar
);
componentManager.unregisterFactory(aSearch.cid, aSearch);
}
/**
* A container to keep all possible results of autocomplete search.
*/
@ -69,15 +75,15 @@ function ResultsHeap(aValues, aComments) {
this.comments = aComments;
}
ResultsHeap.prototype =
{
ResultsHeap.prototype = {
constructor: ResultsHeap,
/**
* Return AutoCompleteResult for the given search string.
*/
getAutoCompleteResultFor(aSearchString) {
var values = [], comments = [];
var values = [],
comments = [];
for (var idx = 0; idx < this.values.length; idx++) {
if (this.values[idx].includes(aSearchString)) {
values.push(this.values[idx]);
@ -88,7 +94,6 @@ ResultsHeap.prototype =
},
};
/**
* nsIAutoCompleteSearch implementation.
*
@ -100,8 +105,7 @@ function AutoCompleteSearch(aName, aAllResults) {
this.allResults = aAllResults;
}
AutoCompleteSearch.prototype =
{
AutoCompleteSearch.prototype = {
constructor: AutoCompleteSearch,
// nsIAutoCompleteSearch implementation
@ -113,7 +117,10 @@ AutoCompleteSearch.prototype =
stopSearch() {},
// nsISupports implementation
QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
QueryInterface: ChromeUtils.generateQI([
"nsIFactory",
"nsIAutoCompleteSearch",
]),
// nsIFactory implementation
createInstance(outer, iid) {
@ -127,7 +134,6 @@ AutoCompleteSearch.prototype =
allResults: null,
};
/**
* nsIAutoCompleteResult implementation.
*/
@ -135,14 +141,14 @@ function AutoCompleteResult(aValues, aComments) {
this.values = aValues;
this.comments = aComments;
if (this.values.length > 0)
if (this.values.length > 0) {
this.searchResult = nsIAutoCompleteResult.RESULT_SUCCESS;
else
} else {
this.searchResult = nsIAutoCompleteResult.NOMATCH;
}
}
AutoCompleteResult.prototype =
{
AutoCompleteResult.prototype = {
constructor: AutoCompleteResult,
searchString: "",

Просмотреть файл

@ -1,4 +1,6 @@
var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
var { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
/**
* Load the browser with the given url and then invokes the given function.
@ -91,10 +93,9 @@ function reloadButton() {
// //////////////////////////////////////////////////////////////////////////////
// private section
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var gBrowserContext =
{
var gBrowserContext = {
browserWnd: null,
testFunc: null,
startURL: "",
@ -104,20 +105,26 @@ function openBrowserWindowIntl() {
var params = "chrome,all,dialog=no,non-remote";
var rect = gBrowserContext.browserRect;
if (rect) {
if ("left" in rect)
if ("left" in rect) {
params += ",left=" + rect.left;
if ("top" in rect)
}
if ("top" in rect) {
params += ",top=" + rect.top;
if ("width" in rect)
}
if ("width" in rect) {
params += ",width=" + rect.width;
if ("height" in rect)
}
if ("height" in rect) {
params += ",height=" + rect.height;
}
}
gBrowserContext.browserWnd =
window.openDialog(AppConstants.BROWSER_CHROME_URL,
"_blank", params,
gBrowserContext.startURL || "data:text/html,<html></html>");
gBrowserContext.browserWnd = window.openDialog(
AppConstants.BROWSER_CHROME_URL,
"_blank",
params,
gBrowserContext.startURL || "data:text/html,<html></html>"
);
whenDelayedStartupFinished(browserWindow(), function() {
addA11yLoadEvent(startBrowserTests, browserWindow());
@ -125,10 +132,12 @@ function openBrowserWindowIntl() {
}
function startBrowserTests() {
if (gBrowserContext.startURL) // wait for load
if (gBrowserContext.startURL) {
// wait for load
addA11yLoadEvent(gBrowserContext.testFunc, currentBrowser().contentWindow);
else
} else {
gBrowserContext.testFunc();
}
}
function whenDelayedStartupFinished(aWindow, aCallback) {

Просмотреть файл

@ -4,20 +4,15 @@
const nsIAccessibilityService = Ci.nsIAccessibilityService;
const nsIAccessibleEvent = Ci.nsIAccessibleEvent;
const nsIAccessibleStateChangeEvent =
Ci.nsIAccessibleStateChangeEvent;
const nsIAccessibleCaretMoveEvent =
Ci.nsIAccessibleCaretMoveEvent;
const nsIAccessibleScrollingEvent =
Ci.nsIAccessibleScrollingEvent;
const nsIAccessibleTextChangeEvent =
Ci.nsIAccessibleTextChangeEvent;
const nsIAccessibleStateChangeEvent = Ci.nsIAccessibleStateChangeEvent;
const nsIAccessibleCaretMoveEvent = Ci.nsIAccessibleCaretMoveEvent;
const nsIAccessibleScrollingEvent = Ci.nsIAccessibleScrollingEvent;
const nsIAccessibleTextChangeEvent = Ci.nsIAccessibleTextChangeEvent;
const nsIAccessibleVirtualCursorChangeEvent =
Ci.nsIAccessibleVirtualCursorChangeEvent;
const nsIAccessibleObjectAttributeChangedEvent =
Ci.nsIAccessibleObjectAttributeChangedEvent;
const nsIAccessibleAnnouncementEvent =
Ci.nsIAccessibleAnnouncementEvent;
const nsIAccessibleAnnouncementEvent = Ci.nsIAccessibleAnnouncementEvent;
const nsIAccessibleStates = Ci.nsIAccessibleStates;
const nsIAccessibleRole = Ci.nsIAccessibleRole;
@ -55,10 +50,10 @@ const nsIPropertyElement = Ci.nsIPropertyElement;
// //////////////////////////////////////////////////////////////////////////////
// OS detect
const MAC = (navigator.platform.includes("Mac"));
const LINUX = (navigator.platform.includes("Linux"));
const SOLARIS = (navigator.platform.includes("SunOS"));
const WIN = (navigator.platform.includes("Win"));
const MAC = navigator.platform.includes("Mac");
const LINUX = navigator.platform.includes("Linux");
const SOLARIS = navigator.platform.includes("SunOS");
const WIN = navigator.platform.includes("Win");
// //////////////////////////////////////////////////////////////////////////////
// Application detect
@ -73,9 +68,12 @@ const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE;
const COORDTYPE_SCREEN_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
const COORDTYPE_WINDOW_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
const COORDTYPE_SCREEN_RELATIVE =
nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
const COORDTYPE_WINDOW_RELATIVE =
nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
const COORDTYPE_PARENT_RELATIVE =
nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
const kEmbedChar = String.fromCharCode(0xfffc);
@ -89,13 +87,14 @@ const MAX_TRIM_LENGTH = 100;
/**
* Services to determine if e10s is enabled.
*/
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* nsIAccessibilityService service.
*/
var gAccService = Cc["@mozilla.org/accessibilityService;1"].
getService(nsIAccessibilityService);
var gAccService = Cc["@mozilla.org/accessibilityService;1"].getService(
nsIAccessibilityService
);
/**
* Enable/disable logging.
@ -151,26 +150,25 @@ function dumpTree(aId, aMsg) {
*/
function addA11yLoadEvent(aFunc, aWindow) {
function waitForDocLoad() {
window.setTimeout(
function() {
var targetDocument = aWindow ? aWindow.document : document;
var accDoc = getAccessible(targetDocument);
var state = {};
accDoc.getState(state, {});
if (state.value & STATE_BUSY) {
waitForDocLoad();
return;
}
window.setTimeout(function() {
var targetDocument = aWindow ? aWindow.document : document;
var accDoc = getAccessible(targetDocument);
var state = {};
accDoc.getState(state, {});
if (state.value & STATE_BUSY) {
waitForDocLoad();
return;
}
window.setTimeout(aFunc, 0);
},
0
);
window.setTimeout(aFunc, 0);
}, 0);
}
if (aWindow &&
aWindow.document.activeElement &&
aWindow.document.activeElement.localName == "browser") {
if (
aWindow &&
aWindow.document.activeElement &&
aWindow.document.activeElement.localName == "browser"
) {
waitForDocLoad();
} else {
SimpleTest.waitForFocus(waitForDocLoad, aWindow);
@ -186,9 +184,15 @@ function isObject(aObj, aExpectedObj, aMsg) {
return;
}
ok(false,
aMsg + " - got '" + prettyName(aObj) +
"', expected '" + prettyName(aExpectedObj) + "'");
ok(
false,
aMsg +
" - got '" +
prettyName(aObj) +
"', expected '" +
prettyName(aExpectedObj) +
"'"
);
}
/**
@ -198,8 +202,10 @@ function isWithin(aExpected, aGot, aWithin, aMsg) {
if (Math.abs(aGot - aExpected) <= aWithin) {
ok(true, `${aMsg} - Got ${aGot}`);
} else {
ok(false,
`${aMsg} - Got ${aGot}, expected ${aExpected} with error of ${aWithin}`);
ok(
false,
`${aMsg} - Got ${aGot}, expected ${aExpected} with error of ${aWithin}`
);
}
}
@ -210,14 +216,17 @@ function isWithin(aExpected, aGot, aWithin, aMsg) {
* Return the DOM node by identifier (may be accessible, DOM node or ID).
*/
function getNode(aAccOrNodeOrID, aDocument) {
if (!aAccOrNodeOrID)
if (!aAccOrNodeOrID) {
return null;
}
if (Node.isInstance(aAccOrNodeOrID))
if (Node.isInstance(aAccOrNodeOrID)) {
return aAccOrNodeOrID;
}
if (aAccOrNodeOrID instanceof nsIAccessible)
if (aAccOrNodeOrID instanceof nsIAccessible) {
return aAccOrNodeOrID.DOMNode;
}
var node = (aDocument || document).getElementById(aAccOrNodeOrID);
if (!node) {
@ -253,13 +262,16 @@ const DONOTFAIL_IF_NO_INTERFACE = 2;
* constants above)
*/
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
if (!aAccOrElmOrID)
if (!aAccOrElmOrID) {
return null;
}
var elm = null;
if (aAccOrElmOrID instanceof nsIAccessible) {
try { elm = aAccOrElmOrID.DOMNode; } catch (e) { }
try {
elm = aAccOrElmOrID.DOMNode;
} catch (e) {}
} else if (Node.isInstance(aAccOrElmOrID)) {
elm = aAccOrElmOrID;
} else {
@ -270,29 +282,32 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
}
}
if (aElmObj && (typeof aElmObj == "object"))
if (aElmObj && typeof aElmObj == "object") {
aElmObj.value = elm;
}
var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null;
var acc = aAccOrElmOrID instanceof nsIAccessible ? aAccOrElmOrID : null;
if (!acc) {
try {
acc = gAccService.getAccessibleFor(elm);
} catch (e) {
}
} catch (e) {}
if (!acc) {
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC))
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC)) {
ok(false, "Can't get accessible for " + prettyName(aAccOrElmOrID));
}
return null;
}
}
if (!aInterfaces)
if (!aInterfaces) {
return acc;
}
if (!(aInterfaces instanceof Array))
aInterfaces = [ aInterfaces ];
if (!(aInterfaces instanceof Array)) {
aInterfaces = [aInterfaces];
}
for (var index = 0; index < aInterfaces.length; index++) {
if (acc instanceof aInterfaces[index]) {
@ -301,8 +316,12 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
try {
acc.QueryInterface(aInterfaces[index]);
} catch (e) {
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID);
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE)) {
ok(
false,
"Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID
);
}
return null;
}
@ -316,8 +335,12 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
* interfaces.
*/
function isAccessible(aAccOrElmOrID, aInterfaces) {
return !!getAccessible(aAccOrElmOrID, aInterfaces, null,
DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE);
return !!getAccessible(
aAccOrElmOrID,
aInterfaces,
null,
DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE
);
}
/**
@ -325,10 +348,11 @@ function isAccessible(aAccOrElmOrID, aInterfaces) {
*/
function getContainerAccessible(aAccOrElmOrID) {
var node = getNode(aAccOrElmOrID);
if (!node)
if (!node) {
return null;
}
while ((node = node.parentNode) && !isAccessible(node));
while ((node = node.parentNode) && !isAccessible(node)) {}
return node ? getAccessible(node) : null;
}
@ -350,8 +374,9 @@ function getTabDocAccessible(aAccOrElmOrID) {
var containerDocAcc = docAcc.parent.document;
// Test is running is stand-alone mode.
if (acc.rootDocument == containerDocAcc)
if (acc.rootDocument == containerDocAcc) {
return docAcc;
}
// In the case of running all tests together.
return containerDocAcc.QueryInterface(nsIAccessible);
@ -361,8 +386,9 @@ function getTabDocAccessible(aAccOrElmOrID) {
* Return application accessible.
*/
function getApplicationAccessible() {
return gAccService.getApplicationAccessible().
QueryInterface(nsIAccessibleApplication);
return gAccService
.getApplicationAccessible()
.QueryInterface(nsIAccessibleApplication);
}
/**
@ -393,8 +419,9 @@ const kSkipTreeFullCheck = 1;
// eslint-disable-next-line complexity
function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
if (!acc) {
return;
}
var accTree = aAccTree;
@ -403,80 +430,106 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
// Test accessible properties.
for (var prop in accTree) {
var msg = "Wrong value of property '" + prop + "' for " +
prettyName(acc) + ".";
var msg =
"Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
switch (prop) {
case "actions": {
testActionNames(acc, accTree.actions);
break;
}
case "attributes":
testAttrs(acc, accTree[prop], true);
break;
case "absentAttributes":
testAbsentAttrs(acc, accTree[prop]);
break;
case "interfaces": {
var ifaces = (accTree[prop] instanceof Array) ?
accTree[prop] : [ accTree[prop] ];
for (let i = 0; i < ifaces.length; i++) {
ok((acc instanceof ifaces[i]),
"No " + ifaces[i] + " interface on " + prettyName(acc));
case "actions": {
testActionNames(acc, accTree.actions);
break;
}
break;
}
case "relations": {
for (var rel in accTree[prop])
testRelation(acc, window[rel], accTree[prop][rel]);
break;
}
case "attributes":
testAttrs(acc, accTree[prop], true);
break;
case "role":
isRole(acc, accTree[prop], msg);
break;
case "absentAttributes":
testAbsentAttrs(acc, accTree[prop]);
break;
case "states":
case "extraStates":
case "absentStates":
case "absentExtraStates": {
testStates(acc, accTree.states, accTree.extraStates,
accTree.absentStates, accTree.absentExtraStates);
break;
}
case "tagName":
is(accTree[prop], acc.DOMNode.tagName, msg);
break;
case "textAttrs": {
var prevOffset = -1;
for (var offset in accTree[prop]) {
if (prevOffset != -1) {
let attrs = accTree[prop][prevOffset];
testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, +offset, true);
case "interfaces": {
var ifaces =
accTree[prop] instanceof Array ? accTree[prop] : [accTree[prop]];
for (let i = 0; i < ifaces.length; i++) {
ok(
acc instanceof ifaces[i],
"No " + ifaces[i] + " interface on " + prettyName(acc)
);
}
prevOffset = +offset;
break;
}
if (prevOffset != -1) {
var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount;
let attrs = accTree[prop][prevOffset];
testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true);
case "relations": {
for (var rel in accTree[prop]) {
testRelation(acc, window[rel], accTree[prop][rel]);
}
break;
}
break;
}
case "role":
isRole(acc, accTree[prop], msg);
break;
default:
if (prop.indexOf("todo_") == 0)
todo(false, msg);
else if (prop != "children")
is(acc[prop], accTree[prop], msg);
case "states":
case "extraStates":
case "absentStates":
case "absentExtraStates": {
testStates(
acc,
accTree.states,
accTree.extraStates,
accTree.absentStates,
accTree.absentExtraStates
);
break;
}
case "tagName":
is(accTree[prop], acc.DOMNode.tagName, msg);
break;
case "textAttrs": {
var prevOffset = -1;
for (var offset in accTree[prop]) {
if (prevOffset != -1) {
let attrs = accTree[prop][prevOffset];
testTextAttrs(
acc,
prevOffset,
attrs,
{},
prevOffset,
+offset,
true
);
}
prevOffset = +offset;
}
if (prevOffset != -1) {
var charCount = getAccessible(acc, [nsIAccessibleText])
.characterCount;
let attrs = accTree[prop][prevOffset];
testTextAttrs(
acc,
prevOffset,
attrs,
{},
prevOffset,
charCount,
true
);
}
break;
}
default:
if (prop.indexOf("todo_") == 0) {
todo(false, msg);
} else if (prop != "children") {
is(acc[prop], accTree[prop], msg);
}
}
}
@ -487,29 +540,62 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
if (accTree.children.length != childCount) {
for (let i = 0; i < Math.max(accTree.children.length, childCount); i++) {
var accChild = null, testChild = null;
var accChild = null,
testChild = null;
try {
testChild = accTree.children[i];
accChild = children.queryElementAt(i, nsIAccessible);
if (!testChild) {
ok(false, prettyName(acc) + " has an extra child at index " + i +
" : " + prettyName(accChild));
ok(
false,
prettyName(acc) +
" has an extra child at index " +
i +
" : " +
prettyName(accChild)
);
continue;
}
testChild = normalizeAccTreeObj(testChild);
if (accChild.role !== testChild.role) {
ok(false, prettyName(accTree) + " and " + prettyName(acc) +
" have different children at index " + i + " : " +
prettyName(testChild) + ", " + prettyName(accChild));
ok(
false,
prettyName(accTree) +
" and " +
prettyName(acc) +
" have different children at index " +
i +
" : " +
prettyName(testChild) +
", " +
prettyName(accChild)
);
}
info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
" child at index " + i + " : " + prettyName(accChild));
info(
"Matching " +
prettyName(accTree) +
" and " +
prettyName(acc) +
" child at index " +
i +
" : " +
prettyName(accChild)
);
} catch (e) {
ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
" : " + prettyName(testChild) + ", original tested: " +
prettyName(aAccOrElmOrID) + ", " + e);
ok(
false,
prettyName(accTree) +
" is expected to have a child at index " +
i +
" : " +
prettyName(testChild) +
", original tested: " +
prettyName(aAccOrElmOrID) +
", " +
e
);
}
}
} else {
@ -522,50 +608,77 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
}
// nsIAccessible::firstChild
var expectedFirstChild = childCount > 0 ?
children.queryElementAt(0, nsIAccessible) : null;
var expectedFirstChild =
childCount > 0 ? children.queryElementAt(0, nsIAccessible) : null;
var firstChild = null;
try { firstChild = acc.firstChild; } catch (e) {}
is(firstChild, expectedFirstChild,
"Wrong first child of " + prettyName(acc));
try {
firstChild = acc.firstChild;
} catch (e) {}
is(
firstChild,
expectedFirstChild,
"Wrong first child of " + prettyName(acc)
);
// nsIAccessible::lastChild
var expectedLastChild = childCount > 0 ?
children.queryElementAt(childCount - 1, nsIAccessible) : null;
var expectedLastChild =
childCount > 0
? children.queryElementAt(childCount - 1, nsIAccessible)
: null;
var lastChild = null;
try { lastChild = acc.lastChild; } catch (e) {}
is(lastChild, expectedLastChild,
"Wrong last child of " + prettyName(acc));
try {
lastChild = acc.lastChild;
} catch (e) {}
is(
lastChild,
expectedLastChild,
"Wrong last child of " + prettyName(acc)
);
for (var i = 0; i < childCount; i++) {
let child = children.queryElementAt(i, nsIAccessible);
// nsIAccessible::parent
var parent = null;
try { parent = child.parent; } catch (e) {}
try {
parent = child.parent;
} catch (e) {}
is(parent, acc, "Wrong parent of " + prettyName(child));
// nsIAccessible::indexInParent
var indexInParent = -1;
try { indexInParent = child.indexInParent; } catch (e) {}
is(indexInParent, i,
"Wrong index in parent of " + prettyName(child));
try {
indexInParent = child.indexInParent;
} catch (e) {}
is(indexInParent, i, "Wrong index in parent of " + prettyName(child));
// nsIAccessible::nextSibling
var expectedNextSibling = (i < childCount - 1) ?
children.queryElementAt(i + 1, nsIAccessible) : null;
var expectedNextSibling =
i < childCount - 1
? children.queryElementAt(i + 1, nsIAccessible)
: null;
var nextSibling = null;
try { nextSibling = child.nextSibling; } catch (e) {}
is(nextSibling, expectedNextSibling,
"Wrong next sibling of " + prettyName(child));
try {
nextSibling = child.nextSibling;
} catch (e) {}
is(
nextSibling,
expectedNextSibling,
"Wrong next sibling of " + prettyName(child)
);
// nsIAccessible::previousSibling
var expectedPrevSibling = (i > 0) ?
children.queryElementAt(i - 1, nsIAccessible) : null;
var expectedPrevSibling =
i > 0 ? children.queryElementAt(i - 1, nsIAccessible) : null;
var prevSibling = null;
try { prevSibling = child.previousSibling; } catch (e) {}
is(prevSibling, expectedPrevSibling,
"Wrong previous sibling of " + prettyName(child));
try {
prevSibling = child.previousSibling;
} catch (e) {}
is(
prevSibling,
expectedPrevSibling,
"Wrong previous sibling of " + prettyName(child)
);
// Go down through subtree
testAccessibleTree(child, accTree.children[i], aFlags);
@ -589,19 +702,22 @@ function isAccessibleInCache(aNodeOrId) {
* @param aNodeOrId [in] the DOM node identifier for the defunct accessible
*/
function testDefunctAccessible(aAcc, aNodeOrId) {
if (aNodeOrId)
ok(!isAccessible(aNodeOrId),
"Accessible for " + aNodeOrId + " wasn't properly shut down!");
if (aNodeOrId) {
ok(
!isAccessible(aNodeOrId),
"Accessible for " + aNodeOrId + " wasn't properly shut down!"
);
}
var msg = " doesn't fail for shut down accessible " +
prettyName(aNodeOrId) + "!";
var msg =
" doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
// firstChild
var success = false;
try {
aAcc.firstChild;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "firstChild" + msg);
@ -610,7 +726,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.lastChild;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "lastChild" + msg);
@ -619,7 +735,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.childCount;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "childCount" + msg);
@ -628,7 +744,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.children;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "children" + msg);
@ -637,7 +753,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.nextSibling;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "nextSibling" + msg);
@ -646,7 +762,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.previousSibling;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "previousSibling" + msg);
@ -655,7 +771,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
try {
aAcc.parent;
} catch (e) {
success = (e.result == Cr.NS_ERROR_FAILURE);
success = e.result == Cr.NS_ERROR_FAILURE;
}
ok(success, "parent" + msg);
}
@ -674,11 +790,13 @@ function statesToString(aStates, aExtraStates) {
var list = gAccService.getStringStates(aStates, aExtraStates);
var str = "";
for (var index = 0; index < list.length - 1; index++)
for (var index = 0; index < list.length - 1; index++) {
str += list.item(index) + ", ";
}
if (list.length != 0)
if (list.length != 0) {
str += list.item(index);
}
return str;
}
@ -705,11 +823,13 @@ function getLoadContext() {
* Return text from clipboard.
*/
function getTextFromClipboard() {
var trans = Cc["@mozilla.org/widget/transferable;1"].
createInstance(Ci.nsITransferable);
var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
Ci.nsITransferable
);
trans.init(getLoadContext());
if (!trans)
if (!trans) {
return "";
}
trans.addDataFlavor("text/unicode");
Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard);
@ -717,10 +837,12 @@ function getTextFromClipboard() {
var str = {};
trans.getTransferData("text/unicode", str);
if (str)
if (str) {
str = str.value.QueryInterface(Ci.nsISupportsString);
if (str)
}
if (str) {
return str.data;
}
return "";
}
@ -737,17 +859,23 @@ function getAccessibleDOMNodeID(accessible) {
// If accessible is a document, trying to find its document body id.
try {
return accessible.DOMNode.body.id;
} catch (e) { /* This only works if accessible is not a proxy. */ }
} catch (e) {
/* This only works if accessible is not a proxy. */
}
}
try {
return accessible.DOMNode.id;
} catch (e) { /* This will fail if DOMNode is in different process. */ }
} catch (e) {
/* This will fail if DOMNode is in different process. */
}
try {
// When e10s is enabled, accessible will have an "id" property if its
// corresponding DOMNode has an id. If accessible is a document, its "id"
// property corresponds to the "id" of its body element.
return accessible.id;
} catch (e) { /* This will fail if accessible is not a proxy. */ }
} catch (e) {
/* This will fail if accessible is not a proxy. */
}
return null;
}
@ -758,8 +886,9 @@ function prettyName(aIdentifier) {
if (aIdentifier instanceof Array) {
let msg = "";
for (var idx = 0; idx < aIdentifier.length; idx++) {
if (msg != "")
if (msg != "") {
msg += ", ";
}
msg += prettyName(aIdentifier[idx]);
}
@ -779,23 +908,26 @@ function prettyName(aIdentifier) {
msg += `${getNodePrettyName(acc.DOMNode)}, `;
}
msg += "role: " + roleToString(acc.role);
if (acc.name)
if (acc.name) {
msg += ", name: '" + shortenString(acc.name) + "'";
}
} catch (e) {
msg += "defunct";
}
if (acc)
if (acc) {
msg += ", address: " + getObjAddress(acc);
}
msg += "]";
return msg;
}
if (Node.isInstance(aIdentifier))
if (Node.isInstance(aIdentifier)) {
return "[ " + getNodePrettyName(aIdentifier) + " ]";
}
if (aIdentifier && typeof aIdentifier === "object" ) {
if (aIdentifier && typeof aIdentifier === "object") {
var treeObj = normalizeAccTreeObj(aIdentifier);
if ("role" in treeObj) {
function stringifyTree(aObj) {
@ -825,13 +957,17 @@ function prettyName(aIdentifier) {
* @returns the shortened string.
*/
function shortenString(aString, aMaxLength) {
if (aString.length <= MAX_TRIM_LENGTH)
if (aString.length <= MAX_TRIM_LENGTH) {
return aString;
}
// Trim the string if its length is > MAX_TRIM_LENGTH characters.
var trimOffset = MAX_TRIM_LENGTH / 2;
return aString.substring(0, trimOffset - 1) + "..." +
aString.substring(aString.length - trimOffset, aString.length);
return (
aString.substring(0, trimOffset - 1) +
"..." +
aString.substring(aString.length - trimOffset, aString.length)
);
}
// //////////////////////////////////////////////////////////////////////////////
@ -873,8 +1009,9 @@ function getNodePrettyName(aNode) {
tag = "document";
} else {
tag = aNode.localName;
if (aNode.nodeType == Node.ELEMENT_NODE && aNode.hasAttribute("id"))
tag += "@id=\"" + aNode.getAttribute("id") + "\"";
if (aNode.nodeType == Node.ELEMENT_NODE && aNode.hasAttribute("id")) {
tag += '@id="' + aNode.getAttribute("id") + '"';
}
}
return "'" + tag + " node', address: " + getObjAddress(aNode);
@ -886,15 +1023,17 @@ function getNodePrettyName(aNode) {
function getObjAddress(aObj) {
var exp = /native\s*@\s*(0x[a-f0-9]+)/g;
var match = exp.exec(aObj.toString());
if (match)
if (match) {
return match[1];
}
return aObj.toString();
}
function getTestPluginTag(aPluginName) {
var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
.getService(SpecialPowers.Ci.nsIPluginHost);
var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"].getService(
SpecialPowers.Ci.nsIPluginHost
);
var tags = ph.getPluginTags();
var name = aPluginName || "Test Plug-in";
for (var tag of tags) {

Просмотреть файл

@ -60,22 +60,29 @@ function editableTextTest(aID) {
}
aSkipStartOffset = aSkipStartOffset || 0;
var insertTripple = aValue ?
[ aSkipStartOffset, aSkipStartOffset + aValue.length, aValue ] : null;
var insertTripple = aValue
? [aSkipStartOffset, aSkipStartOffset + aValue.length, aValue]
: null;
var oldValue = getValue();
var removeTripple = oldValue ?
[ aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue ] : null;
var removeTripple = oldValue
? [aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue]
: null;
this.generateTest(removeTripple, insertTripple, setTextContentsInvoke,
getValueChecker(aValue), testID);
this.generateTest(
removeTripple,
insertTripple,
setTextContentsInvoke,
getValueChecker(aValue),
testID
);
};
/**
* insertText test.
*/
this.insertText = function insertText(aStr, aPos, aResStr, aResPos) {
var testID = "insertText '" + aStr + "' at " + aPos + " for " +
prettyName(aID);
var testID =
"insertText '" + aStr + "' at " + aPos + " for " + prettyName(aID);
function insertTextInvoke() {
dump(`\ninsertText '${aStr}' at ${aPos} pos\n`);
@ -83,16 +90,26 @@ function editableTextTest(aID) {
acc.insertText(aStr, aPos);
}
var resPos = (aResPos != undefined) ? aResPos : aPos;
this.generateTest(null, [resPos, resPos + aStr.length, aStr],
insertTextInvoke, getValueChecker(aResStr), testID);
var resPos = aResPos != undefined ? aResPos : aPos;
this.generateTest(
null,
[resPos, resPos + aStr.length, aStr],
insertTextInvoke,
getValueChecker(aResStr),
testID
);
};
/**
* copyText test.
*/
this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) {
var testID = "copyText from " + aStartPos + " to " + aEndPos + " for " +
var testID =
"copyText from " +
aStartPos +
" to " +
aEndPos +
" for " +
prettyName(aID);
function copyTextInvoke() {
@ -100,17 +117,33 @@ function editableTextTest(aID) {
acc.copyText(aStartPos, aEndPos);
}
this.generateTest(null, null, copyTextInvoke,
getClipboardChecker(aClipboardStr), testID);
this.generateTest(
null,
null,
copyTextInvoke,
getClipboardChecker(aClipboardStr),
testID
);
};
/**
* copyText and pasteText test.
*/
this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos,
aPos, aResStr) {
var testID = "copyText from " + aStartPos + " to " + aEndPos +
"and pasteText at " + aPos + " for " + prettyName(aID);
this.copyNPasteText = function copyNPasteText(
aStartPos,
aEndPos,
aPos,
aResStr
) {
var testID =
"copyText from " +
aStartPos +
" to " +
aEndPos +
"and pasteText at " +
aPos +
" for " +
prettyName(aID);
function copyNPasteTextInvoke() {
var acc = getAccessible(aID, nsIAccessibleEditableText);
@ -118,16 +151,31 @@ function editableTextTest(aID) {
acc.pasteText(aPos);
}
this.generateTest(null, [aStartPos, aEndPos, getTextFromClipboard],
copyNPasteTextInvoke, getValueChecker(aResStr), testID);
this.generateTest(
null,
[aStartPos, aEndPos, getTextFromClipboard],
copyNPasteTextInvoke,
getValueChecker(aResStr),
testID
);
};
/**
* cutText test.
*/
this.cutText = function cutText(aStartPos, aEndPos, aResStr,
aResStartPos, aResEndPos) {
var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " +
this.cutText = function cutText(
aStartPos,
aEndPos,
aResStr,
aResStartPos,
aResEndPos
) {
var testID =
"cutText from " +
aStartPos +
" to " +
aEndPos +
" for " +
prettyName(aID);
function cutTextInvoke() {
@ -135,19 +183,35 @@ function editableTextTest(aID) {
acc.cutText(aStartPos, aEndPos);
}
var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos;
var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos;
this.generateTest([resStartPos, resEndPos, getTextFromClipboard], null,
cutTextInvoke, getValueChecker(aResStr), testID);
var resStartPos = aResStartPos != undefined ? aResStartPos : aStartPos;
var resEndPos = aResEndPos != undefined ? aResEndPos : aEndPos;
this.generateTest(
[resStartPos, resEndPos, getTextFromClipboard],
null,
cutTextInvoke,
getValueChecker(aResStr),
testID
);
};
/**
* cutText and pasteText test.
*/
this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos,
aPos, aResStr) {
var testID = "cutText from " + aStartPos + " to " + aEndPos +
" and pasteText at " + aPos + " for " + prettyName(aID);
this.cutNPasteText = function copyNPasteText(
aStartPos,
aEndPos,
aPos,
aResStr
) {
var testID =
"cutText from " +
aStartPos +
" to " +
aEndPos +
" and pasteText at " +
aPos +
" for " +
prettyName(aID);
function cutNPasteTextInvoke() {
var acc = getAccessible(aID, nsIAccessibleEditableText);
@ -155,10 +219,13 @@ function editableTextTest(aID) {
acc.pasteText(aPos);
}
this.generateTest([aStartPos, aEndPos, getTextFromClipboard],
[aPos, -1, getTextFromClipboard],
cutNPasteTextInvoke, getValueChecker(aResStr),
testID);
this.generateTest(
[aStartPos, aEndPos, getTextFromClipboard],
[aPos, -1, getTextFromClipboard],
cutNPasteTextInvoke,
getValueChecker(aResStr),
testID
);
};
/**
@ -172,16 +239,26 @@ function editableTextTest(aID) {
acc.pasteText(aPos);
}
this.generateTest(null, [aPos, -1, getTextFromClipboard],
pasteTextInvoke, getValueChecker(aResStr), testID);
this.generateTest(
null,
[aPos, -1, getTextFromClipboard],
pasteTextInvoke,
getValueChecker(aResStr),
testID
);
};
/**
* deleteText test.
*/
this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) {
var testID = "deleteText from " + aStartPos + " to " + aEndPos +
" for " + prettyName(aID);
var testID =
"deleteText from " +
aStartPos +
" to " +
aEndPos +
" for " +
prettyName(aID);
var oldValue = getValue().substring(aStartPos, aEndPos);
var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null;
@ -191,8 +268,13 @@ function editableTextTest(aID) {
acc.deleteText(aStartPos, aEndPos);
}
this.generateTest(removeTripple, null, deleteTextInvoke,
getValueChecker(aResStr), testID);
this.generateTest(
removeTripple,
null,
deleteTextInvoke,
getValueChecker(aResStr),
testID
);
};
// ////////////////////////////////////////////////////////////////////////////
@ -201,11 +283,13 @@ function editableTextTest(aID) {
function getValue() {
var elm = getNode(aID);
var elmClass = ChromeUtils.getClassName(elm);
if (elmClass === "HTMLTextAreaElement" || elmClass === "HTMLInputElement")
if (elmClass === "HTMLTextAreaElement" || elmClass === "HTMLInputElement") {
return elm.value;
}
if (elmClass === "HTMLDocument")
if (elmClass === "HTMLDocument") {
return elm.body.textContent;
}
return elm.textContent;
}
@ -236,15 +320,21 @@ function editableTextTest(aID) {
*/
this.unwrapNextTest = function unwrapNextTest() {
var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1];
if (data)
if (data) {
data.func.apply(this, data.funcArgs);
}
};
/**
* Used to generate an invoker object for the sheduled test.
*/
this.generateTest = function generateTest(aRemoveTriple, aInsertTriple,
aInvokeFunc, aChecker, aInvokerID) {
this.generateTest = function generateTest(
aRemoveTriple,
aInsertTriple,
aInvokeFunc,
aChecker,
aInvokerID
) {
var et = this;
var invoker = {
eventSeq: [],
@ -256,26 +346,37 @@ function editableTextTest(aID) {
aChecker.check();
et.unwrapNextTest(); // replace dummy invoker on real invoker object.
},
getID: function getID() { return aInvokerID; },
getID: function getID() {
return aInvokerID;
},
};
if (aRemoveTriple) {
let checker = new textChangeChecker(aID, aRemoveTriple[0],
aRemoveTriple[1], aRemoveTriple[2],
false);
let checker = new textChangeChecker(
aID,
aRemoveTriple[0],
aRemoveTriple[1],
aRemoveTriple[2],
false
);
invoker.eventSeq.push(checker);
}
if (aInsertTriple) {
let checker = new textChangeChecker(aID, aInsertTriple[0],
aInsertTriple[1], aInsertTriple[2],
true);
let checker = new textChangeChecker(
aID,
aInsertTriple[0],
aInsertTriple[1],
aInsertTriple[2],
true
);
invoker.eventSeq.push(checker);
}
// Claim that we don't want to fail when no events are expected.
if (!aRemoveTriple && !aInsertTriple)
if (!aRemoveTriple && !aInsertTriple) {
invoker.noEventsOnAction = true;
}
this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker;
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -31,8 +31,9 @@ function grid(aTableIdentifier) {
var colIdx = aCell.cellIndex;
var rowIdx = aCell.parentNode.rowIndex;
if (this.table.tHead)
if (this.table.tHead) {
rowIdx -= 1;
}
var colsCount = this.getColsCount();
return rowIdx * colsCount + colIdx;
@ -44,8 +45,9 @@ function grid(aTableIdentifier) {
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
var cell = this.table.rows[rowIdx].cells[colIdx];
if (cell.hasAttribute("tabindex"))
if (cell.hasAttribute("tabindex")) {
return cell;
}
}
}
return null;
@ -57,15 +59,17 @@ function grid(aTableIdentifier) {
};
this.handleEvent = function handleEvent(aEvent) {
if (aEvent instanceof KeyboardEvent)
if (aEvent instanceof KeyboardEvent) {
this.handleKeyEvent(aEvent);
else
} else {
this.handleClickEvent(aEvent);
}
};
this.handleKeyEvent = function handleKeyEvent(aEvent) {
if (aEvent.target.localName != "td")
if (aEvent.target.localName != "td") {
return;
}
var cell = aEvent.target;
switch (aEvent.keyCode) {
@ -117,8 +121,9 @@ function grid(aTableIdentifier) {
};
this.handleClickEvent = function handleClickEvent(aEvent) {
if (aEvent.target.localName != "td")
if (aEvent.target.localName != "td") {
return;
}
var curCell = this.getCurrentCell();
var cell = aEvent.target;

Просмотреть файл

@ -13,22 +13,26 @@ function focusLink(aID, aSelectedAfter) {
this.unexpectedEventSeq = [];
var checker = new invokerChecker(EVENT_FOCUS, this.accessible);
if (aSelectedAfter)
if (aSelectedAfter) {
this.eventSeq.push(checker);
else
} else {
this.unexpectedEventSeq.push(checker);
}
this.invoke = function focusLink_invoke() {
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE : 0);
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
var expectedStates = aSelectedAfter ? STATE_FOCUSABLE : 0;
var unexpectedStates =
(!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
testStates(aID, expectedStates, 0, unexpectedStates, 0);
this.node.focus();
};
this.finalCheck = function focusLink_finalCheck() {
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
var expectedStates = aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0;
var unexpectedStates = !aSelectedAfter
? STATE_FOCUSABLE | STATE_FOCUSED
: 0;
testStates(aID, expectedStates, 0, unexpectedStates, 0);
};

Просмотреть файл

@ -6,17 +6,19 @@
addMessageListener, currentTabDocument, currentBrowser*/
/**
* A global variable holding an array of test functions.
*/
* A global variable holding an array of test functions.
*/
var gTestFuncs = [];
/**
* A global Iterator for the array of test functions.
*/
* A global Iterator for the array of test functions.
*/
var gIterator;
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var AccessFu;
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
const { Logger, Utils } = ChromeUtils.import(
"resource://gre/modules/accessibility/Utils.jsm"
);
const MovementGranularity = {
CHARACTER: 1,
@ -26,14 +28,16 @@ const MovementGranularity = {
};
var AccessFuTest = {
addFunc: function AccessFuTest_addFunc(aFunc) {
if (aFunc) {
gTestFuncs.push(aFunc);
}
},
_registerListener: function AccessFuTest__registerListener(aWaitForMessage, aListenerFunc) {
_registerListener: function AccessFuTest__registerListener(
aWaitForMessage,
aListenerFunc
) {
var listener = {
observe: function observe(aMessage) {
// Ignore unexpected messages.
@ -59,11 +63,13 @@ var AccessFuTest = {
},
once_log: function AccessFuTest_once_log(aWaitForMessage, aListenerFunc) {
return this._registerListener(aWaitForMessage,
return this._registerListener(
aWaitForMessage,
function listenAndUnregister() {
Services.console.unregisterListener(this);
aListenerFunc();
});
}
);
},
_addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) {
@ -134,7 +140,7 @@ var AccessFuTest = {
}
// Create an Iterator for gTestFuncs array.
gIterator = (function* () {
gIterator = (function*() {
for (var testFunc of gTestFuncs) {
yield testFunc;
}
@ -144,12 +150,14 @@ var AccessFuTest = {
Logger.logLevel = Logger.DEBUG;
// Start AccessFu and put it in stand-by.
({AccessFu} = ChromeUtils.import("resource://gre/modules/accessibility/AccessFu.jsm"));
({ AccessFu } = ChromeUtils.import(
"resource://gre/modules/accessibility/AccessFu.jsm"
));
var prefs = [["accessibility.accessfu.notify_output", 1]];
prefs.push.apply(prefs, aAdditionalPrefs);
SpecialPowers.pushPrefEnv({ "set": prefs }, function() {
SpecialPowers.pushPrefEnv({ set: prefs }, function() {
if (AccessFuTest._waitForExplicitFinish) {
// Run all test functions asynchronously.
AccessFuTest.nextTest();
@ -166,8 +174,10 @@ class AccessFuContentTestRunner {
constructor() {
this.listenersMap = new Map();
let frames = Array.from(currentTabDocument().querySelectorAll("iframe"));
this.mms = [Utils.getMessageManager(currentBrowser()),
...frames.map(f => Utils.getMessageManager(f)).filter(mm => !!mm)];
this.mms = [
Utils.getMessageManager(currentBrowser()),
...frames.map(f => Utils.getMessageManager(f)).filter(mm => !!mm),
];
}
start(aFinishedCallback) {
@ -208,14 +218,19 @@ class AccessFuContentTestRunner {
isFocused(aExpected) {
var doc = currentTabDocument();
SimpleTest.is(doc.activeElement, doc.querySelector(aExpected),
"Correct element is focused: " + aExpected);
SimpleTest.is(
doc.activeElement,
doc.querySelector(aExpected),
"Correct element is focused: " + aExpected
);
}
async setupMessageManager(aMessageManager) {
function contentScript() {
// eslint-disable-next-line no-shadow
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
const { Logger, Utils } = ChromeUtils.import(
"resource://gre/modules/accessibility/Utils.jsm"
);
Logger.logLevel = "DEBUG";
Utils.inTest = true;
@ -232,13 +247,18 @@ class AccessFuContentTestRunner {
}
aMessageManager.loadFrameScript(
"data:,(" + contentScript.toString() + ")();", false);
"data:,(" + contentScript.toString() + ")();",
false
);
aMessageManager.loadFrameScript(
"chrome://global/content/accessibility/content-script.js", false);
"chrome://global/content/accessibility/content-script.js",
false
);
let startedPromise = new Promise(resolve =>
aMessageManager.addMessageListener("AccessFu:ContentStarted", resolve));
aMessageManager.addMessageListener("AccessFu:ContentStarted", resolve)
);
await startedPromise;
@ -254,7 +274,9 @@ class AccessFuContentTestRunner {
if (this.debug) {
info("Android event: " + JSON.stringify(evt));
}
let listener = (this.listenersMap.get(evt.eventType || evt) || []).shift();
let listener = (
this.listenersMap.get(evt.eventType || evt) || []
).shift();
if (listener) {
listener(evt);
}
@ -282,34 +304,44 @@ class AccessFuContentTestRunner {
}
moveNext(aRule, ...aExpectedEvents) {
return this.moveCursor({ action: "moveNext", rule: aRule },
...aExpectedEvents);
return this.moveCursor(
{ action: "moveNext", rule: aRule },
...aExpectedEvents
);
}
movePrevious(aRule, ...aExpectedEvents) {
return this.moveCursor({ action: "movePrevious", rule: aRule },
...aExpectedEvents);
return this.moveCursor(
{ action: "movePrevious", rule: aRule },
...aExpectedEvents
);
}
moveFirst(aRule, ...aExpectedEvents) {
return this.moveCursor({ action: "moveFirst", rule: aRule },
...aExpectedEvents);
return this.moveCursor(
{ action: "moveFirst", rule: aRule },
...aExpectedEvents
);
}
moveLast(aRule, ...aExpectedEvents) {
return this.moveCursor({ action: "moveLast", rule: aRule },
...aExpectedEvents);
return this.moveCursor(
{ action: "moveLast", rule: aRule },
...aExpectedEvents
);
}
async clearCursor() {
return new Promise(resolve => {
let _listener = (msg) => {
this.mms.forEach(
mm => mm.removeMessageListener("AccessFu:CursorCleared", _listener));
let _listener = msg => {
this.mms.forEach(mm =>
mm.removeMessageListener("AccessFu:CursorCleared", _listener)
);
resolve();
};
this.mms.forEach(
mm => mm.addMessageListener("AccessFu:CursorCleared", _listener));
this.mms.forEach(mm =>
mm.addMessageListener("AccessFu:CursorCleared", _listener)
);
this.sendMessage({
name: "AccessFu:ClearCursor",
data: {
@ -355,15 +387,24 @@ class AccessFuContentTestRunner {
}
eventTextMatches(aEvent, aExpected) {
isDeeply(aEvent.text, aExpected,
isDeeply(
aEvent.text,
aExpected,
"Event text matches. " +
`Got ${JSON.stringify(aEvent.text)}, expected ${JSON.stringify(aExpected)}.`);
`Got ${JSON.stringify(aEvent.text)}, expected ${JSON.stringify(
aExpected
)}.`
);
}
eventInfoMatches(aEvent, aExpected) {
for (let key in aExpected) {
is(aEvent[key], aExpected[key], `Event info matches for ${key}. ` +
`Got ${aEvent[key]}, expected ${aExpected[key]}.`);
is(
aEvent[key],
aExpected[key],
`Event info matches for ${key}. ` +
`Got ${aEvent[key]}, expected ${aExpected[key]}.`
);
}
}

Просмотреть файл

@ -1,7 +1,12 @@
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
const {PivotContext} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this);
const { PivotContext } = ChromeUtils.import(
"resource://gre/modules/accessibility/Utils.jsm"
);
ChromeUtils.import(
"resource://gre/modules/accessibility/OutputGenerator.jsm",
this
);
/**
* Test context output generation.
@ -16,10 +21,17 @@ ChromeUtils.import("resource://gre/modules/accessibility/OutputGenerator.jsm", t
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
* scoped to the "root" element in markup.
*/
function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) {
function testContextOutput(
expected,
aAccOrElmOrID,
aOldAccOrElmOrID,
aGenerator
) {
var accessible = getAccessible(aAccOrElmOrID);
var oldAccessible = aOldAccOrElmOrID !== null ?
getAccessible(aOldAccOrElmOrID || "root") : null;
var oldAccessible =
aOldAccOrElmOrID !== null
? getAccessible(aOldAccOrElmOrID || "root")
: null;
var context = new PivotContext(accessible, oldAccessible);
var output = aGenerator.genForContext(context);
@ -32,15 +44,23 @@ function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator
if (expected[i] === null) {
masked_output.push(null);
} else {
masked_output[i] = typeof output[i] === "string" ? output[i].trim() :
output[i];
masked_output[i] =
typeof output[i] === "string" ? output[i].trim() : output[i];
}
}
isDeeply(masked_output, expected,
"Context output is correct for " + aAccOrElmOrID +
" (output: " + JSON.stringify(output) + ") ==" +
" (expected: " + JSON.stringify(expected) + ")");
isDeeply(
masked_output,
expected,
"Context output is correct for " +
aAccOrElmOrID +
" (output: " +
JSON.stringify(output) +
") ==" +
" (expected: " +
JSON.stringify(expected) +
")"
);
}
/**
@ -70,8 +90,10 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
var nameIndex = output.indexOf(accessible.name);
if (nameIndex > -1) {
ok(output.indexOf(accessible.name) === expectedNameIndex,
"Object output is correct for " + aAccOrElmOrID);
ok(
output.indexOf(accessible.name) === expectedNameIndex,
"Object output is correct for " + aAccOrElmOrID
);
}
}
@ -85,8 +107,12 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
* @param aOutputKind the type of output
*/
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID,
UtteranceGenerator);
testContextOutput(
expected,
aAccOrElmOrID,
aOldAccOrElmOrID,
UtteranceGenerator
);
// Just need to test object output for individual
// accOrElmOrID.
if (aOldAccOrElmOrID) {
@ -97,13 +123,23 @@ function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
var accessible = getAccessible(aAccOrElmOrID);
var oldAccessible = aOldAccOrElmOrID !== null ?
getAccessible(aOldAccOrElmOrID || "root") : null;
var oldAccessible =
aOldAccOrElmOrID !== null
? getAccessible(aOldAccOrElmOrID || "root")
: null;
var context = new PivotContext(accessible, oldAccessible);
var hints = context.interactionHints;
isDeeply(hints, expected,
"Context hitns are correct for " + aAccOrElmOrID +
" (hints: " + JSON.stringify(hints) + ") ==" +
" (expected: " + JSON.stringify(expected) + ")");
isDeeply(
hints,
expected,
"Context hitns are correct for " +
aAccOrElmOrID +
" (hints: " +
JSON.stringify(hints) +
") ==" +
" (expected: " +
JSON.stringify(expected) +
")"
);
}

Просмотреть файл

@ -12,15 +12,25 @@ function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) {
var child = getChildAtPoint(aID, aX, aY, false);
var expectedChild = getAccessible(aChildID);
var msg = "Wrong direct child accessible at the point (" + aX + ", " + aY +
") of " + prettyName(aID);
var msg =
"Wrong direct child accessible at the point (" +
aX +
", " +
aY +
") of " +
prettyName(aID);
isObject(child, expectedChild, msg);
var grandChild = getChildAtPoint(aID, aX, aY, true);
var expectedGrandChild = getAccessible(aGrandChildID);
msg = "Wrong deepest child accessible at the point (" + aX + ", " + aY +
") of " + prettyName(aID);
msg =
"Wrong deepest child accessible at the point (" +
aX +
", " +
aY +
") of " +
prettyName(aID);
isObject(grandChild, expectedGrandChild, msg);
}
@ -36,12 +46,18 @@ function hitTest(aContainerID, aChildID, aGrandChildID) {
var [x, y] = getBoundsForDOMElm(child);
var actualChild = container.getChildAtPoint(x + 1, y + 1);
isObject(actualChild, child,
"Wrong direct child of " + prettyName(aContainerID));
isObject(
actualChild,
child,
"Wrong direct child of " + prettyName(aContainerID)
);
var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1);
isObject(actualGrandChild, grandChild,
"Wrong deepest child of " + prettyName(aContainerID));
isObject(
actualGrandChild,
grandChild,
"Wrong deepest child of " + prettyName(aContainerID)
);
}
/**
@ -50,9 +66,16 @@ function hitTest(aContainerID, aChildID, aGrandChildID) {
function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) {
var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]);
var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType);
is(offset, aExpectedOffset,
"Wrong offset at given point (" + aX + ", " + aY + ") for " +
prettyName(aHyperTextID));
is(
offset,
aExpectedOffset,
"Wrong offset at given point (" +
aX +
", " +
aY +
") for " +
prettyName(aHyperTextID)
);
}
/**
@ -87,8 +110,9 @@ function setResolution(aDocument, aZoom) {
*/
function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
var acc = getAccessible(aIdentifier);
if (!acc)
if (!acc) {
return null;
}
var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode);
@ -96,10 +120,11 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
var y = screenY + aY;
try {
if (aFindDeepestChild)
if (aFindDeepestChild) {
return acc.getDeepestChildAtPoint(x, y);
}
return acc.getChildAtPoint(x, y);
} catch (e) { }
} catch (e) {}
return null;
}
@ -109,7 +134,7 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
*/
function testPos(aID, aPoint) {
var [expectedX, expectedY] =
(aPoint != undefined) ? aPoint : getBoundsForDOMElm(aID);
aPoint != undefined ? aPoint : getBoundsForDOMElm(aID);
var [x, y] = getBounds(aID);
is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
@ -121,7 +146,7 @@ function testPos(aID, aPoint) {
*/
function testBounds(aID, aRect) {
var [expectedX, expectedY, expectedWidth, expectedHeight] =
(aRect != undefined) ? aRect : getBoundsForDOMElm(aID);
aRect != undefined ? aRect : getBoundsForDOMElm(aID);
var [x, y, width, height] = getBounds(aID);
is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
@ -136,15 +161,27 @@ function testBounds(aID, aRect) {
function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
var [expectedX, expectedY] = aPoint;
var xObj = {}, yObj = {};
var xObj = {},
yObj = {};
var hyperText = getAccessible(aID, [nsIAccessibleText]);
hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin);
is(xObj.value, expectedX,
"Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID));
ok(yObj.value - expectedY < 2 && expectedY - yObj.value < 2,
"Wrong y coordinate at offset " + aOffset + " for " + prettyName(aID) +
" - got " + yObj.value + ", expected " + expectedY +
"The difference doesn't exceed 1.");
is(
xObj.value,
expectedX,
"Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)
);
ok(
yObj.value - expectedY < 2 && expectedY - yObj.value < 2,
"Wrong y coordinate at offset " +
aOffset +
" for " +
prettyName(aID) +
" - got " +
yObj.value +
", expected " +
expectedY +
"The difference doesn't exceed 1."
);
}
/**
@ -153,33 +190,64 @@ function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) {
var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect;
var xObj = {}, yObj = {}, widthObj = {}, heightObj = {};
var xObj = {},
yObj = {},
widthObj = {},
heightObj = {};
var hyperText = getAccessible(aID, [nsIAccessibleText]);
hyperText.getRangeExtents(aStartOffset, aEndOffset,
xObj, yObj, widthObj, heightObj, aCoordOrigin);
hyperText.getRangeExtents(
aStartOffset,
aEndOffset,
xObj,
yObj,
widthObj,
heightObj,
aCoordOrigin
);
// x
is(xObj.value, expectedX,
"Wrong x coordinate of text between offsets (" + aStartOffset + ", " +
aEndOffset + ") for " + prettyName(aID));
is(
xObj.value,
expectedX,
"Wrong x coordinate of text between offsets (" +
aStartOffset +
", " +
aEndOffset +
") for " +
prettyName(aID)
);
// y
isWithin(yObj.value, expectedY, 1,
`y coord of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
`for ${prettyName(aID)}`);
isWithin(
yObj.value,
expectedY,
1,
`y coord of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
`for ${prettyName(aID)}`
);
// Width
var msg = "Wrong width of text between offsets (" + aStartOffset + ", " +
aEndOffset + ") for " + prettyName(aID);
if (widthObj.value == expectedWidth)
var msg =
"Wrong width of text between offsets (" +
aStartOffset +
", " +
aEndOffset +
") for " +
prettyName(aID);
if (widthObj.value == expectedWidth) {
ok(true, msg);
else
todo(false, msg); // fails on some windows machines
} else {
todo(false, msg);
} // fails on some windows machines
// Height
isWithin(heightObj.value, expectedHeight, 1,
`height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
`for ${prettyName(aID)}`);
isWithin(
heightObj.value,
expectedHeight,
1,
`height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
`for ${prettyName(aID)}`
);
}
/**
@ -187,7 +255,8 @@ function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) {
*/
function getPos(aID) {
var accessible = getAccessible(aID);
var x = {}, y = {};
var x = {},
y = {};
accessible.getBounds(x, y, {}, {});
return [x.value, y.value];
}
@ -199,28 +268,60 @@ function getPos(aID) {
*/
function getBounds(aID, aDPR = window.devicePixelRatio) {
const accessible = getAccessible(aID);
let x = {}, y = {}, width = {}, height = {};
let xInCSS = {}, yInCSS = {}, widthInCSS = {}, heightInCSS = {};
let x = {},
y = {},
width = {},
height = {};
let xInCSS = {},
yInCSS = {},
widthInCSS = {},
heightInCSS = {};
accessible.getBounds(x, y, width, height);
accessible.getBoundsInCSSPixels(xInCSS, yInCSS, widthInCSS, heightInCSS);
isWithin(x.value / aDPR, xInCSS.value, 1,
"Heights in CSS pixels is calculated correctly");
isWithin(y.value / aDPR, yInCSS.value, 1,
"Heights in CSS pixels is calculated correctly");
isWithin(width.value / aDPR, widthInCSS.value, 1,
"Heights in CSS pixels is calculated correctly");
isWithin(height.value / aDPR, heightInCSS.value, 1,
"Heights in CSS pixels is calculated correctly");
isWithin(
x.value / aDPR,
xInCSS.value,
1,
"Heights in CSS pixels is calculated correctly"
);
isWithin(
y.value / aDPR,
yInCSS.value,
1,
"Heights in CSS pixels is calculated correctly"
);
isWithin(
width.value / aDPR,
widthInCSS.value,
1,
"Heights in CSS pixels is calculated correctly"
);
isWithin(
height.value / aDPR,
heightInCSS.value,
1,
"Heights in CSS pixels is calculated correctly"
);
return [x.value, y.value, width.value, height.value];
}
function getRangeExtents(aID, aStartOffset, aEndOffset, aCoordOrigin) {
var hyperText = getAccessible(aID, [nsIAccessibleText]);
var x = {}, y = {}, width = {}, height = {};
hyperText.getRangeExtents(aStartOffset, aEndOffset,
x, y, width, height, aCoordOrigin);
var x = {},
y = {},
width = {},
height = {};
hyperText.getRangeExtents(
aStartOffset,
aEndOffset,
x,
y,
width,
height,
aCoordOrigin
);
return [x.value, y.value, width.value, height.value];
}
@ -229,7 +330,10 @@ function getRangeExtents(aID, aStartOffset, aEndOffset, aCoordOrigin) {
* pixels.
*/
function getBoundsForDOMElm(aID) {
var x = 0, y = 0, width = 0, height = 0;
var x = 0,
y = 0,
width = 0,
height = 0;
var elm = getNode(aID);
if (elm.localName == "area") {
@ -257,11 +361,13 @@ function getBoundsForDOMElm(aID) {
}
var elmWindow = elm.ownerGlobal;
return CSSToDevicePixels(elmWindow,
x + elmWindow.mozInnerScreenX,
y + elmWindow.mozInnerScreenY,
width,
height);
return CSSToDevicePixels(
elmWindow,
x + elmWindow.mozInnerScreenX,
y + elmWindow.mozInnerScreenY,
width,
height
);
}
function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
@ -271,6 +377,10 @@ function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
// CSS pixels and ratio can be not integer. Device pixels are always integer.
// Do our best and hope it works.
return [ Math.round(aX * ratio), Math.round(aY * ratio),
Math.round(aWidth * ratio), Math.round(aHeight * ratio) ];
return [
Math.round(aX * ratio),
Math.round(aY * ratio),
Math.round(aWidth * ratio),
Math.round(aHeight * ratio),
];
}

Просмотреть файл

@ -5,8 +5,9 @@ function testName(aAccOrElmOrID, aName, aMsg, aTodo) {
var msg = aMsg ? aMsg : "";
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
if (!acc) {
return "";
}
var func = aTodo ? todo_is : is;
var txtID = prettyName(aAccOrElmOrID);
@ -23,9 +24,13 @@ function testName(aAccOrElmOrID, aName, aMsg, aTodo) {
*/
function testDescr(aAccOrElmOrID, aDescr) {
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
return;
if (!acc) {
return;
}
is(acc.description, aDescr,
"Wrong description for " + prettyName(aAccOrElmOrID));
is(
acc.description,
aDescr,
"Wrong description for " + prettyName(aAccOrElmOrID)
);
}

Просмотреть файл

@ -31,17 +31,20 @@ function testNames() {
/**
* Helper class to interate through name tests.
*/
var gTestIterator =
{
var gTestIterator = {
iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms) {
this.markupElms = aMarkupElms;
this.iterateNext();
},
iterateRules: function gTestIterator_iterateRules(aElm, aContainer,
aRuleSetElm, aRuleElms,
aTestID) {
iterateRules: function gTestIterator_iterateRules(
aElm,
aContainer,
aRuleSetElm,
aRuleElms,
aTestID
) {
this.ruleSetElm = aRuleSetElm;
this.ruleElms = aRuleElms;
this.elm = aElm;
@ -61,11 +64,15 @@ var gTestIterator =
this.ruleIdx++;
if (this.ruleIdx == this.ruleElms.length) {
// When test is finished then name is empty and no explict-name.
var defaultName = this.ruleSetElm.hasAttribute("defaultName") ?
this.ruleSetElm.getAttribute("defaultName") : null;
testName(this.elm, defaultName,
"Default name test (" + gTestIterator.testID + "). ");
testAbsentAttrs(this.elm, {"explicit-name": "true"});
var defaultName = this.ruleSetElm.hasAttribute("defaultName")
? this.ruleSetElm.getAttribute("defaultName")
: null;
testName(
this.elm,
defaultName,
"Default name test (" + gTestIterator.testID + "). "
);
testAbsentAttrs(this.elm, { "explicit-name": "true" });
this.markupIdx++;
if (this.markupIdx == this.markupElms.length) {
@ -77,11 +84,19 @@ var gTestIterator =
this.ruleIdx = -1;
if (gDumpToConsole) {
dump("\nPend next markup processing. Wait for reorder event on " +
prettyName(document) + "'\n");
dump(
"\nPend next markup processing. Wait for reorder event on " +
prettyName(document) +
"'\n"
);
}
waitForEvent(EVENT_REORDER, document, testNamesForMarkup,
null, this.markupElms[this.markupIdx]);
waitForEvent(
EVENT_REORDER,
document,
testNamesForMarkup,
null,
this.markupElms[this.markupIdx]
);
document.body.removeChild(this.container);
return;
@ -105,8 +120,9 @@ var gTestIterator =
* function.
*/
function testNamesForMarkup(aMarkupElm) {
if (gDumpToConsole)
if (gDumpToConsole) {
dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n");
}
var div = document.createElement("div");
div.setAttribute("id", "test");
@ -119,19 +135,29 @@ function testNamesForMarkup(aMarkupElm) {
}
if (gDumpToConsole) {
dump("\nProcessing markup. Wait for reorder event on " +
prettyName(document) + "'\n");
dump(
"\nProcessing markup. Wait for reorder event on " +
prettyName(document) +
"'\n"
);
}
waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
null, aMarkupElm, div);
waitForEvent(
EVENT_REORDER,
document,
testNamesForMarkupRules,
null,
aMarkupElm,
div
);
document.body.appendChild(div);
}
function testNamesForMarkupRules(aMarkupElm, aContainer) {
var testID = aMarkupElm.getAttribute("id");
if (gDumpToConsole)
if (gDumpToConsole) {
dump("\nProcessing markup rules '" + testID + "'\n");
}
var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
var elm = evaluateXPath(document, expr, htmlDocResolver)[0];
@ -140,18 +166,24 @@ function testNamesForMarkupRules(aMarkupElm, aContainer) {
var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']");
var ruleElms = getRuleElmsByRulesetId(ruleId);
var processMarkupRules =
gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer,
ruleElm, ruleElms, testID);
var processMarkupRules = gTestIterator.iterateRules.bind(
gTestIterator,
elm,
aContainer,
ruleElm,
ruleElms,
testID
);
// Images may be recreated after we append them into subtree. We need to wait
// in this case. If we are on profiling enabled build then stack tracing
// works and thus let's log instead. Note, that works if you enabled logging
// (refer to testNames() function).
if (isAccessible(elm) || isLogged("stack"))
if (isAccessible(elm) || isLogged("stack")) {
processMarkupRules();
else
} else {
waitForEvent(EVENT_SHOW, elm, processMarkupRules);
}
}
/**
@ -161,21 +193,31 @@ function testNamesForMarkupRules(aMarkupElm, aContainer) {
function testNameForRule(aElm, aRuleElm) {
if (aRuleElm.hasAttribute("attr")) {
if (gDumpToConsole) {
dump("\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") + " }\n");
dump(
"\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") + " }\n"
);
}
testNameForAttrRule(aElm, aRuleElm);
} else if (aRuleElm.hasAttribute("elm")) {
if (gDumpToConsole) {
dump("\nProcessing rule { elm: " + aRuleElm.getAttribute("elm") +
", elmattr: " + aRuleElm.getAttribute("elmattr") + " }\n");
dump(
"\nProcessing rule { elm: " +
aRuleElm.getAttribute("elm") +
", elmattr: " +
aRuleElm.getAttribute("elmattr") +
" }\n"
);
}
testNameForElmRule(aElm, aRuleElm);
} else if (aRuleElm.getAttribute("fromsubtree") == "true") {
if (gDumpToConsole) {
dump("\nProcessing rule { fromsubtree: " +
aRuleElm.getAttribute("fromsubtree") + " }\n");
dump(
"\nProcessing rule { fromsubtree: " +
aRuleElm.getAttribute("fromsubtree") +
" }\n"
);
}
testNameForSubtreeRule(aElm, aRuleElm);
@ -195,8 +237,9 @@ function testNameForAttrRule(aElm, aRule) {
var ids = attrValue.split(/\s+/);
for (var idx = 0; idx < ids.length; idx++) {
var labelElm = getNode(ids[idx]);
if (name != "")
if (name != "") {
name += " ";
}
name += labelElm.getAttribute("textequiv");
}
@ -205,25 +248,33 @@ function testNameForAttrRule(aElm, aRule) {
var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). ";
testName(aElm, name, msg);
if (aRule.getAttribute("explict-name") != "false")
testAttrs(aElm, {"explicit-name": "true"}, true);
else
testAbsentAttrs(aElm, {"explicit-name": "true"});
if (aRule.getAttribute("explict-name") != "false") {
testAttrs(aElm, { "explicit-name": "true" }, true);
} else {
testAbsentAttrs(aElm, { "explicit-name": "true" });
}
// If @recreated attribute is used then this attribute change recreates an
// accessible. Wait for reorder event in this case or otherwise proceed next
// test immediately.
if (aRule.hasAttribute("recreated")) {
waitForEvent(EVENT_REORDER, aElm.parentNode,
gTestIterator.iterateNext, gTestIterator);
waitForEvent(
EVENT_REORDER,
aElm.parentNode,
gTestIterator.iterateNext,
gTestIterator
);
aElm.removeAttribute(attr);
} else if (aRule.hasAttribute("textchanged")) {
waitForEvent(EVENT_TEXT_INSERTED, aElm,
gTestIterator.iterateNext, gTestIterator);
waitForEvent(
EVENT_TEXT_INSERTED,
aElm,
gTestIterator.iterateNext,
gTestIterator
);
aElm.removeAttribute(attr);
} else if (aRule.hasAttribute("contentchanged")) {
waitForEvent(EVENT_REORDER, aElm,
gTestIterator.iterateNext, gTestIterator);
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
aElm.removeAttribute(attr);
} else {
aElm.removeAttribute(attr);
@ -239,9 +290,12 @@ function testNameForElmRule(aElm, aRule) {
if (attrname) {
var filter = {
acceptNode: function filter_acceptNode(aNode) {
if (aNode.localName == this.mLocalName &&
aNode.getAttribute(this.mAttrName) == this.mAttrValue)
if (
aNode.localName == this.mLocalName &&
aNode.getAttribute(this.mAttrName) == this.mAttrValue
) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
},
@ -251,15 +305,18 @@ function testNameForElmRule(aElm, aRule) {
mAttrValue: aElm.getAttribute("id"),
};
var treeWalker = document.createTreeWalker(document.body,
NodeFilter.SHOW_ELEMENT,
filter);
var treeWalker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
filter
);
labelElm = treeWalker.nextNode();
} else {
// if attrname is empty then look for the element in subtree.
labelElm = aElm.getElementsByTagName(tagname)[0];
if (!labelElm)
if (!labelElm) {
labelElm = aElm.getElementsByTagName("html:" + tagname)[0];
}
}
if (!labelElm) {
@ -270,16 +327,23 @@ function testNameForElmRule(aElm, aRule) {
var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ").";
testName(aElm, labelElm.getAttribute("textequiv"), msg);
testAttrs(aElm, {"explicit-name": "true"}, true);
testAttrs(aElm, { "explicit-name": "true" }, true);
var parentNode = labelElm.parentNode;
if (gDumpToConsole) {
dump("\nProcessed elm rule. Wait for reorder event on " +
prettyName(parentNode) + "\n");
dump(
"\nProcessed elm rule. Wait for reorder event on " +
prettyName(parentNode) +
"\n"
);
}
waitForEvent(EVENT_REORDER, parentNode,
gTestIterator.iterateNext, gTestIterator);
waitForEvent(
EVENT_REORDER,
parentNode,
gTestIterator.iterateNext,
gTestIterator
);
parentNode.removeChild(labelElm);
}
@ -287,16 +351,20 @@ function testNameForElmRule(aElm, aRule) {
function testNameForSubtreeRule(aElm, aRule) {
var msg = "From subtree test (" + gTestIterator.testID + ").";
testName(aElm, aElm.getAttribute("textequiv"), msg);
testAbsentAttrs(aElm, {"explicit-name": "true"});
testAbsentAttrs(aElm, { "explicit-name": "true" });
if (gDumpToConsole) {
dump("\nProcessed from subtree rule. Wait for reorder event on " +
prettyName(aElm) + "\n");
dump(
"\nProcessed from subtree rule. Wait for reorder event on " +
prettyName(aElm) +
"\n"
);
}
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
while (aElm.firstChild)
while (aElm.firstChild) {
aElm.firstChild.remove();
}
}
/**
@ -311,17 +379,20 @@ function getRuleElmsByRulesetId(aRulesetId) {
function getRuleElmsFromRulesetElm(aRulesetElm) {
var rulesetId = aRulesetElm.getAttribute("ref");
if (rulesetId)
if (rulesetId) {
return getRuleElmsByRulesetId(rulesetId);
}
var ruleElms = [];
var child = aRulesetElm.firstChild;
while (child) {
if (child.localName == "ruleset")
if (child.localName == "ruleset") {
ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
if (child.localName == "rule")
}
if (child.localName == "rule") {
ruleElms.push(child);
}
child = child.nextSibling;
}
@ -337,23 +408,26 @@ function evaluateXPath(aNode, aExpr, aResolver) {
var resolver = aResolver;
if (!resolver) {
var node = aNode.ownerDocument == null ?
aNode.documentElement : aNode.ownerDocument.documentElement;
var node =
aNode.ownerDocument == null
? aNode.documentElement
: aNode.ownerDocument.documentElement;
resolver = xpe.createNSResolver(node);
}
var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
var found = [];
var res;
while ((res = result.iterateNext()))
while ((res = result.iterateNext())) {
found.push(res);
}
return found;
}
function htmlDocResolver(aPrefix) {
var ns = {
"html": "http://www.w3.org/1999/xhtml",
html: "http://www.w3.org/1999/xhtml",
};
return ns[aPrefix] || null;
}

Просмотреть файл

@ -21,8 +21,7 @@ const NS_ERROR_INVALID_ARG = 0x80070057;
/**
* Rule object to traverse all focusable nodes and text nodes.
*/
var HeadersTraversalRule =
{
var HeadersTraversalRule = {
getMatchRoles() {
return [ROLE_HEADING];
},
@ -39,8 +38,7 @@ var HeadersTraversalRule =
/**
* Traversal rule for all focusable nodes or leafs.
*/
var ObjectTraversalRule =
{
var ObjectTraversalRule = {
getMatchRoles() {
return [];
},
@ -50,12 +48,18 @@ var ObjectTraversalRule =
match(aAccessible) {
var rv = FILTER_IGNORE;
var role = aAccessible.role;
if (hasState(aAccessible, STATE_FOCUSABLE) &&
(role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME))
if (
hasState(aAccessible, STATE_FOCUSABLE) &&
(role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME)
) {
rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH;
else if (aAccessible.childCount == 0 &&
role != ROLE_STATICTEXT && aAccessible.name.trim())
} else if (
aAccessible.childCount == 0 &&
role != ROLE_STATICTEXT &&
aAccessible.name.trim()
) {
rv = FILTER_MATCH;
}
return rv;
},
@ -69,8 +73,14 @@ var ObjectTraversalRule =
/**
* A checker for virtual cursor changed events.
*/
function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod,
aIsFromUserInput, aBoundaryType = NO_BOUNDARY) {
function VCChangedChecker(
aDocAcc,
aIdOrNameOrAcc,
aTextOffsets,
aPivotMoveMethod,
aIsFromUserInput,
aBoundaryType = NO_BOUNDARY
) {
this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc);
this.match = function VCChangedChecker_match(aEvent) {
@ -81,11 +91,13 @@ function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMetho
return false;
}
var expectedReason = VCChangedChecker.methodReasonMap[aPivotMoveMethod] ||
var expectedReason =
VCChangedChecker.methodReasonMap[aPivotMoveMethod] ||
nsIAccessiblePivot.REASON_NONE;
return event.reason == expectedReason &&
event.boundaryType == aBoundaryType;
return (
event.reason == expectedReason && event.boundaryType == aBoundaryType
);
};
this.check = function VCChangedChecker_check(aEvent) {
@ -103,65 +115,100 @@ function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMetho
var nameMatches = position && position.name == aIdOrNameOrAcc;
var accMatches = position == aIdOrNameOrAcc;
SimpleTest.ok(idMatches || nameMatches || accMatches,
"id or name matches - expecting " +
prettyName(aIdOrNameOrAcc) + ", got '" + prettyName(position));
SimpleTest.ok(
idMatches || nameMatches || accMatches,
"id or name matches - expecting " +
prettyName(aIdOrNameOrAcc) +
", got '" +
prettyName(position)
);
SimpleTest.is(aEvent.isFromUserInput, aIsFromUserInput,
"Expected user input is " + aIsFromUserInput + "\n");
SimpleTest.is(
aEvent.isFromUserInput,
aIsFromUserInput,
"Expected user input is " + aIsFromUserInput + "\n"
);
SimpleTest.is(event.newAccessible, position,
"new position in event is incorrect");
SimpleTest.is(
event.newAccessible,
position,
"new position in event is incorrect"
);
if (aTextOffsets) {
SimpleTest.is(aDocAcc.virtualCursor.startOffset, aTextOffsets[0],
"wrong start offset");
SimpleTest.is(aDocAcc.virtualCursor.endOffset, aTextOffsets[1],
"wrong end offset");
SimpleTest.is(event.newStartOffset, aTextOffsets[0],
"wrong start offset in event");
SimpleTest.is(event.newEndOffset, aTextOffsets[1],
"wrong end offset in event");
SimpleTest.is(
aDocAcc.virtualCursor.startOffset,
aTextOffsets[0],
"wrong start offset"
);
SimpleTest.is(
aDocAcc.virtualCursor.endOffset,
aTextOffsets[1],
"wrong end offset"
);
SimpleTest.is(
event.newStartOffset,
aTextOffsets[0],
"wrong start offset in event"
);
SimpleTest.is(
event.newEndOffset,
aTextOffsets[1],
"wrong end offset in event"
);
}
var prevPosAndOffset = VCChangedChecker.
getPreviousPosAndOffset(aDocAcc.virtualCursor);
var prevPosAndOffset = VCChangedChecker.getPreviousPosAndOffset(
aDocAcc.virtualCursor
);
if (prevPosAndOffset) {
SimpleTest.is(event.oldAccessible, prevPosAndOffset.position,
"previous position does not match");
SimpleTest.is(event.oldStartOffset, prevPosAndOffset.startOffset,
"previous start offset does not match");
SimpleTest.is(event.oldEndOffset, prevPosAndOffset.endOffset,
"previous end offset does not match");
SimpleTest.is(
event.oldAccessible,
prevPosAndOffset.position,
"previous position does not match"
);
SimpleTest.is(
event.oldStartOffset,
prevPosAndOffset.startOffset,
"previous start offset does not match"
);
SimpleTest.is(
event.oldEndOffset,
prevPosAndOffset.endOffset,
"previous end offset does not match"
);
}
};
}
VCChangedChecker.prevPosAndOffset = {};
VCChangedChecker.storePreviousPosAndOffset =
function storePreviousPosAndOffset(aPivot) {
VCChangedChecker.prevPosAndOffset[aPivot] =
{position: aPivot.position,
startOffset: aPivot.startOffset,
endOffset: aPivot.endOffset};
VCChangedChecker.storePreviousPosAndOffset = function storePreviousPosAndOffset(
aPivot
) {
VCChangedChecker.prevPosAndOffset[aPivot] = {
position: aPivot.position,
startOffset: aPivot.startOffset,
endOffset: aPivot.endOffset,
};
};
VCChangedChecker.getPreviousPosAndOffset =
function getPreviousPosAndOffset(aPivot) {
VCChangedChecker.getPreviousPosAndOffset = function getPreviousPosAndOffset(
aPivot
) {
return VCChangedChecker.prevPosAndOffset[aPivot];
};
VCChangedChecker.methodReasonMap = {
"moveNext": nsIAccessiblePivot.REASON_NEXT,
"movePrevious": nsIAccessiblePivot.REASON_PREV,
"moveFirst": nsIAccessiblePivot.REASON_FIRST,
"moveLast": nsIAccessiblePivot.REASON_LAST,
"setTextRange": nsIAccessiblePivot.REASON_NONE,
"moveNextByText": nsIAccessiblePivot.REASON_NEXT,
"movePreviousByText": nsIAccessiblePivot.REASON_PREV,
"moveToPoint": nsIAccessiblePivot.REASON_POINT,
moveNext: nsIAccessiblePivot.REASON_NEXT,
movePrevious: nsIAccessiblePivot.REASON_PREV,
moveFirst: nsIAccessiblePivot.REASON_FIRST,
moveLast: nsIAccessiblePivot.REASON_LAST,
setTextRange: nsIAccessiblePivot.REASON_NONE,
moveNextByText: nsIAccessiblePivot.REASON_NEXT,
movePreviousByText: nsIAccessiblePivot.REASON_PREV,
moveToPoint: nsIAccessiblePivot.REASON_POINT,
};
/**
@ -174,21 +221,35 @@ VCChangedChecker.methodReasonMap = {
*/
function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) {
this.invoke = function virtualCursorChangedInvoker_invoke() {
VCChangedChecker.
storePreviousPosAndOffset(aDocAcc.virtualCursor);
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets);
aDocAcc.virtualCursor.setTextRange(aTextAccessible,
aTextOffsets[0],
aTextOffsets[1]);
aDocAcc.virtualCursor.setTextRange(
aTextAccessible,
aTextOffsets[0],
aTextOffsets[1]
);
};
this.getID = function setVCRangeInvoker_getID() {
return "Set offset in " + prettyName(aTextAccessible) +
" to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")";
return (
"Set offset in " +
prettyName(aTextAccessible) +
" to (" +
aTextOffsets[0] +
", " +
aTextOffsets[1] +
")"
);
};
this.eventSeq = [
new VCChangedChecker(aDocAcc, aTextAccessible, aTextOffsets, "setTextRange", true),
new VCChangedChecker(
aDocAcc,
aTextAccessible,
aTextOffsets,
"setTextRange",
true
),
];
}
@ -204,31 +265,42 @@ function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) {
* @param aIsFromUserInput [in] set user input flag when invoking method, and
* expect it in the event.
*/
function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
aIsFromUserInput) {
function setVCPosInvoker(
aDocAcc,
aPivotMoveMethod,
aRule,
aIdOrNameOrAcc,
aIsFromUserInput
) {
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
var expectMove = aIdOrNameOrAcc != false;
this.invoke = function virtualCursorChangedInvoker_invoke() {
VCChangedChecker.
storePreviousPosAndOffset(aDocAcc.virtualCursor);
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
if (aPivotMoveMethod && aRule) {
var moved = false;
switch (aPivotMoveMethod) {
case "moveFirst":
case "moveLast":
moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule,
aIsFromUserInput === undefined ? true : aIsFromUserInput);
moved = aDocAcc.virtualCursor[aPivotMoveMethod](
aRule,
aIsFromUserInput === undefined ? true : aIsFromUserInput
);
break;
case "moveNext":
case "movePrevious":
moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule,
aDocAcc.virtualCursor.position, false,
aIsFromUserInput === undefined ? true : aIsFromUserInput);
moved = aDocAcc.virtualCursor[aPivotMoveMethod](
aRule,
aDocAcc.virtualCursor.position,
false,
aIsFromUserInput === undefined ? true : aIsFromUserInput
);
break;
}
SimpleTest.is(!!moved, !!expectMove,
"moved pivot with " + aPivotMoveMethod +
" to " + aIdOrNameOrAcc);
SimpleTest.is(
!!moved,
!!expectMove,
"moved pivot with " + aPivotMoveMethod + " to " + aIdOrNameOrAcc
);
} else {
aDocAcc.virtualCursor.position = getAccessible(aIdOrNameOrAcc);
}
@ -240,8 +312,13 @@ function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
if (expectMove) {
this.eventSeq = [
new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, null, aPivotMoveMethod,
aIsFromUserInput === undefined ? !!aPivotMoveMethod : aIsFromUserInput),
new VCChangedChecker(
aDocAcc,
aIdOrNameOrAcc,
null,
aPivotMoveMethod,
aIsFromUserInput === undefined ? !!aPivotMoveMethod : aIsFromUserInput
),
];
} else {
this.eventSeq = [];
@ -265,30 +342,55 @@ function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
* @param aIsFromUserInput [in] set user input flag when invoking method, and
* expect it in the event.
*/
function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
aIdOrNameOrAcc, aIsFromUserInput) {
function setVCTextInvoker(
aDocAcc,
aPivotMoveMethod,
aBoundary,
aTextOffsets,
aIdOrNameOrAcc,
aIsFromUserInput
) {
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
var expectMove = aIdOrNameOrAcc != false;
this.invoke = function virtualCursorChangedInvoker_invoke() {
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
SimpleTest.info(aDocAcc.virtualCursor.position);
var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aBoundary,
aIsFromUserInput === undefined);
SimpleTest.is(!!moved, !!expectMove,
"moved pivot by text with " + aPivotMoveMethod +
" to " + aIdOrNameOrAcc);
var moved = aDocAcc.virtualCursor[aPivotMoveMethod](
aBoundary,
aIsFromUserInput === undefined
);
SimpleTest.is(
!!moved,
!!expectMove,
"moved pivot by text with " + aPivotMoveMethod + " to " + aIdOrNameOrAcc
);
};
this.getID = function setVCPosInvoker_getID() {
return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod + " in " +
prettyName(aIdOrNameOrAcc) + ", " + boundaryToString(aBoundary) +
", [" + aTextOffsets + "]";
return (
"Do " +
(expectMove ? "" : "no-op ") +
aPivotMoveMethod +
" in " +
prettyName(aIdOrNameOrAcc) +
", " +
boundaryToString(aBoundary) +
", [" +
aTextOffsets +
"]"
);
};
if (expectMove) {
this.eventSeq = [
new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod,
aIsFromUserInput === undefined ? true : aIsFromUserInput, aBoundary),
new VCChangedChecker(
aDocAcc,
aIdOrNameOrAcc,
aTextOffsets,
aPivotMoveMethod,
aIsFromUserInput === undefined ? true : aIsFromUserInput,
aBoundary
),
];
} else {
this.eventSeq = [];
@ -298,7 +400,6 @@ function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
}
}
/**
* Move the pivot to the position under the point.
*
@ -312,21 +413,34 @@ function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
* virtual cursor to land on after performing move method.
* false if no move is expected.
*/
function moveVCCoordInvoker(aDocAcc, aX, aY, aIgnoreNoMatch,
aRule, aIdOrNameOrAcc) {
function moveVCCoordInvoker(
aDocAcc,
aX,
aY,
aIgnoreNoMatch,
aRule,
aIdOrNameOrAcc
) {
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
var expectMove = aIdOrNameOrAcc != false;
this.invoke = function virtualCursorChangedInvoker_invoke() {
VCChangedChecker.
storePreviousPosAndOffset(aDocAcc.virtualCursor);
var moved = aDocAcc.virtualCursor.moveToPoint(aRule, aX, aY,
aIgnoreNoMatch);
SimpleTest.ok((expectMove && moved) || (!expectMove && !moved),
"moved pivot");
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
var moved = aDocAcc.virtualCursor.moveToPoint(
aRule,
aX,
aY,
aIgnoreNoMatch
);
SimpleTest.ok(
(expectMove && moved) || (!expectMove && !moved),
"moved pivot"
);
};
this.getID = function setVCPosInvoker_getID() {
return "Do " + (expectMove ? "" : "no-op ") + "moveToPoint " + aIdOrNameOrAcc;
return (
"Do " + (expectMove ? "" : "no-op ") + "moveToPoint " + aIdOrNameOrAcc
);
};
if (expectMove) {
@ -355,12 +469,17 @@ function setModalRootInvoker(aDocAcc, aModalRootAcc, aExpectedResult) {
aDocAcc.virtualCursor.modalRoot = aModalRootAcc;
} catch (x) {
SimpleTest.ok(
x.result, "Unexpected exception when changing modal root: " + x);
x.result,
"Unexpected exception when changing modal root: " + x
);
errorResult = x.result;
}
SimpleTest.is(errorResult, aExpectedResult,
"Did not get expected result when changing modalRoot");
SimpleTest.is(
errorResult,
aExpectedResult,
"Did not get expected result when changing modalRoot"
);
};
this.getID = function setModalRootInvoker_getID() {
@ -394,8 +513,7 @@ function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) {
aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
for (let i = 1; i < aSequence.length; i++) {
let invoker =
new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
let invoker = new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
aQueue.push(invoker);
}
@ -403,22 +521,34 @@ function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) {
aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
for (let i = aSequence.length - 2; i >= 0; i--) {
let invoker =
new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]);
let invoker = new setVCPosInvoker(
aDocAcc,
"movePrevious",
aRule,
aSequence[i]
);
aQueue.push(invoker);
}
// No previous more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule,
aSequence[aSequence.length - 1]));
aQueue.push(
new setVCPosInvoker(
aDocAcc,
"moveLast",
aRule,
aSequence[aSequence.length - 1]
)
);
// No further more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
// set isFromUserInput to false, just to test..
aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0], false));
aQueue.push(
new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0], false)
);
// No previous more matches for given rule, expect no virtual cursor changes.
aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
@ -441,8 +571,10 @@ function removeVCPositionChecker(aDocAcc, aHiddenParentAcc) {
errorResult = x.result;
}
SimpleTest.is(
errorResult, NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
errorResult,
NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position."
);
};
}
@ -484,8 +616,10 @@ function removeVCRootChecker(aPivot) {
errorResult = x.result;
}
SimpleTest.is(
errorResult, NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
errorResult,
NS_ERROR_NOT_IN_TREE,
"Expecting NOT_IN_TREE error when moving pivot from invalid position."
);
};
}
@ -507,9 +641,7 @@ function removeVCRootInvoker(aRootNode) {
return "Remove root of pivot from tree.";
};
this.eventSeq = [
new removeVCRootChecker(this.pivot),
];
this.eventSeq = [new removeVCRootChecker(this.pivot)];
}
/**

Просмотреть файл

@ -18,9 +18,12 @@ var RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF;
var RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF;
var RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR;
var RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF;
var RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
var RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
var RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
var RELATION_CONTAINING_DOCUMENT =
nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
var RELATION_CONTAINING_TAB_PANE =
nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
var RELATION_CONTAINING_APPLICATION =
nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
const RELATION_DETAILS = nsIAccessibleRelation.RELATION_DETAILS;
const RELATION_DETAILS_FOR = nsIAccessibleRelation.RELATION_DETAILS_FOR;
const RELATION_ERRORMSG = nsIAccessibleRelation.RELATION_ERRORMSG;
@ -50,8 +53,11 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
return;
}
var msg = relDescrStart + "has no expected targets: '" +
prettyName(aRelatedIdentifiers) + "'";
var msg =
relDescrStart +
"has no expected targets: '" +
prettyName(aRelatedIdentifiers) +
"'";
ok(false, msg);
return;
@ -60,15 +66,19 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
return;
}
var relatedIds = (aRelatedIdentifiers instanceof Array) ?
aRelatedIdentifiers : [aRelatedIdentifiers];
var relatedIds =
aRelatedIdentifiers instanceof Array
? aRelatedIdentifiers
: [aRelatedIdentifiers];
var targets = [];
for (let idx = 0; idx < relatedIds.length; idx++)
targets.push(getAccessible(relatedIds[idx]));
for (let idx = 0; idx < relatedIds.length; idx++) {
targets.push(getAccessible(relatedIds[idx]));
}
if (targets.length != relatedIds.length)
if (targets.length != relatedIds.length) {
return;
}
var actualTargets = relation.getTargets();
@ -88,10 +98,14 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
// Check if all obtained targets are given related accessibles.
for (let relatedAcc of actualTargets.enumerate(Ci.nsIAccessible)) {
let idx;
for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++);
for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++) {}
if (idx == targets.length)
ok(false, "There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr);
if (idx == targets.length) {
ok(
false,
"There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr
);
}
}
}
@ -120,15 +134,19 @@ function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers) {
return;
}
var relatedIds = (aUnrelatedIdentifiers instanceof Array) ?
aUnrelatedIdentifiers : [aUnrelatedIdentifiers];
var relatedIds =
aUnrelatedIdentifiers instanceof Array
? aUnrelatedIdentifiers
: [aUnrelatedIdentifiers];
var targets = [];
for (let idx = 0; idx < relatedIds.length; idx++)
for (let idx = 0; idx < relatedIds.length; idx++) {
targets.push(getAccessible(relatedIds[idx]));
}
if (targets.length != relatedIds.length)
if (targets.length != relatedIds.length) {
return;
}
var actualTargets = relation.getTargets();
@ -155,8 +173,9 @@ function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers) {
*/
function getRelationByType(aIdentifier, aRelType) {
var acc = getAccessible(aIdentifier);
if (!acc)
if (!acc) {
return null;
}
var relation = null;
try {

Просмотреть файл

@ -154,8 +154,9 @@ function testRole(aAccOrElmOrID, aRole) {
*/
function getRole(aAccOrElmOrID) {
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
if (!acc) {
return -1;
}
var role = -1;
try {
@ -172,8 +173,9 @@ function getRole(aAccOrElmOrID) {
*/
function isRole(aIdentifier, aRole, aMsg) {
var role = getRole(aIdentifier);
if (role == -1)
if (role == -1) {
return;
}
if (role == aRole) {
ok(true, aMsg);

Просмотреть файл

@ -6,37 +6,62 @@
*/
function testSelectableSelection(aIdentifier, aSelectedChildren, aMsg) {
var acc = getAccessible(aIdentifier, [nsIAccessibleSelectable]);
if (!acc)
if (!acc) {
return;
}
var msg = aMsg ? aMsg : "";
var len = aSelectedChildren.length;
// getSelectedChildren
var selectedChildren = acc.selectedItems;
is(selectedChildren ? selectedChildren.length : 0, len,
msg + "getSelectedChildren: wrong selected children count for " +
prettyName(aIdentifier));
is(
selectedChildren ? selectedChildren.length : 0,
len,
msg +
"getSelectedChildren: wrong selected children count for " +
prettyName(aIdentifier)
);
for (let idx = 0; idx < len; idx++) {
let expectedAcc = getAccessible(aSelectedChildren[idx]);
var actualAcc = selectedChildren.queryElementAt(idx, nsIAccessible);
is(actualAcc, expectedAcc,
msg + "getSelectedChildren: wrong selected child at index " + idx +
" for " + prettyName(aIdentifier) + " { actual : " +
prettyName(actualAcc) + ", expected: " + prettyName(expectedAcc) + "}");
is(
actualAcc,
expectedAcc,
msg +
"getSelectedChildren: wrong selected child at index " +
idx +
" for " +
prettyName(aIdentifier) +
" { actual : " +
prettyName(actualAcc) +
", expected: " +
prettyName(expectedAcc) +
"}"
);
}
// selectedItemCount
is(acc.selectedItemCount, aSelectedChildren.length,
"selectedItemCount: wrong selected children count for " + prettyName(aIdentifier));
is(
acc.selectedItemCount,
aSelectedChildren.length,
"selectedItemCount: wrong selected children count for " +
prettyName(aIdentifier)
);
// getSelectedItemAt
for (let idx = 0; idx < len; idx++) {
let expectedAcc = getAccessible(aSelectedChildren[idx]);
is(acc.getSelectedItemAt(idx), expectedAcc,
msg + "getSelectedItemAt: wrong selected child at index " + idx + " for " +
prettyName(aIdentifier));
is(
acc.getSelectedItemAt(idx),
expectedAcc,
msg +
"getSelectedItemAt: wrong selected child at index " +
idx +
" for " +
prettyName(aIdentifier)
);
}
// isItemSelected
@ -46,7 +71,13 @@ function testSelectableSelection(aIdentifier, aSelectedChildren, aMsg) {
/**
* Test isItemSelected method, helper for testSelectableSelection
*/
function testIsItemSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChildren, aMsg) {
function testIsItemSelected(
aSelectAcc,
aTraversedAcc,
aIndexObj,
aSelectedChildren,
aMsg
) {
var childCount = aTraversedAcc.childCount;
for (var idx = 0; idx < childCount; idx++) {
var child = aTraversedAcc.getChildAt(idx);
@ -62,13 +93,24 @@ function testIsItemSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChild
}
// isItemSelected
is(aSelectAcc.isItemSelected(aIndexObj.value++), isSelected,
aMsg + "isItemSelected: wrong selected child " + prettyName(child) +
" for " + prettyName(aSelectAcc));
is(
aSelectAcc.isItemSelected(aIndexObj.value++),
isSelected,
aMsg +
"isItemSelected: wrong selected child " +
prettyName(child) +
" for " +
prettyName(aSelectAcc)
);
// selected state
testStates(child, isSelected ? STATE_SELECTED : 0, 0,
!isSelected ? STATE_SELECTED : 0, 0);
testStates(
child,
isSelected ? STATE_SELECTED : 0,
0,
!isSelected ? STATE_SELECTED : 0,
0
);
continue;
}

Просмотреть файл

@ -72,92 +72,178 @@ const kExtraState = 1;
* @param aAbsentExtraState Extra state bits that are not wanted.
* @param aTestName The test name.
*/
function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
aAbsentExtraState, aTestName) {
function testStates(
aAccOrElmOrID,
aState,
aExtraState,
aAbsentState,
aAbsentExtraState,
aTestName
) {
var [state, extraState] = getStates(aAccOrElmOrID);
var role = getRole(aAccOrElmOrID);
var id = prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]" : "");
var id =
prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]" : "");
// Primary test.
if (aState) {
isState(state & aState, aState, false,
"wrong state bits for " + id + "!");
isState(state & aState, aState, false, "wrong state bits for " + id + "!");
}
if (aExtraState)
isState(extraState & aExtraState, aExtraState, true,
"wrong extra state bits for " + id + "!");
if (aExtraState) {
isState(
extraState & aExtraState,
aExtraState,
true,
"wrong extra state bits for " + id + "!"
);
}
if (aAbsentState)
isState(state & aAbsentState, 0, false,
"state bits should not be present in ID " + id + "!");
if (aAbsentState) {
isState(
state & aAbsentState,
0,
false,
"state bits should not be present in ID " + id + "!"
);
}
if (aAbsentExtraState)
isState(extraState & aAbsentExtraState, 0, true,
"extraState bits should not be present in ID " + id + "!");
if (aAbsentExtraState) {
isState(
extraState & aAbsentExtraState,
0,
true,
"extraState bits should not be present in ID " + id + "!"
);
}
// Additional test.
// focused/focusable
if (state & STATE_FOCUSED)
isState(state & STATE_FOCUSABLE, STATE_FOCUSABLE, false,
"Focussed " + id + " must be focusable!");
if (state & STATE_FOCUSED) {
isState(
state & STATE_FOCUSABLE,
STATE_FOCUSABLE,
false,
"Focussed " + id + " must be focusable!"
);
}
if (aAbsentState && (aAbsentState & STATE_FOCUSABLE)) {
isState(state & STATE_FOCUSED, 0, false,
"Not focusable " + id + " must be not focused!");
if (aAbsentState && aAbsentState & STATE_FOCUSABLE) {
isState(
state & STATE_FOCUSED,
0,
false,
"Not focusable " + id + " must be not focused!"
);
}
// multiline/singleline
if (extraState & EXT_STATE_MULTI_LINE)
isState(extraState & EXT_STATE_SINGLE_LINE, 0, true,
"Multiline " + id + " cannot be singleline!");
if (extraState & EXT_STATE_MULTI_LINE) {
isState(
extraState & EXT_STATE_SINGLE_LINE,
0,
true,
"Multiline " + id + " cannot be singleline!"
);
}
if (extraState & EXT_STATE_SINGLE_LINE)
isState(extraState & EXT_STATE_MULTI_LINE, 0, true,
"Singleline " + id + " cannot be multiline!");
if (extraState & EXT_STATE_SINGLE_LINE) {
isState(
extraState & EXT_STATE_MULTI_LINE,
0,
true,
"Singleline " + id + " cannot be multiline!"
);
}
// expanded/collapsed/expandable
if (state & STATE_COLLAPSED || state & STATE_EXPANDED)
isState(extraState & EXT_STATE_EXPANDABLE, EXT_STATE_EXPANDABLE, true,
"Collapsed or expanded " + id + " must be expandable!");
if (state & STATE_COLLAPSED || state & STATE_EXPANDED) {
isState(
extraState & EXT_STATE_EXPANDABLE,
EXT_STATE_EXPANDABLE,
true,
"Collapsed or expanded " + id + " must be expandable!"
);
}
if (state & STATE_COLLAPSED)
isState(state & STATE_EXPANDED, 0, false,
"Collapsed " + id + " cannot be expanded!");
if (state & STATE_COLLAPSED) {
isState(
state & STATE_EXPANDED,
0,
false,
"Collapsed " + id + " cannot be expanded!"
);
}
if (state & STATE_EXPANDED)
isState(state & STATE_COLLAPSED, 0, false,
"Expanded " + id + " cannot be collapsed!");
if (state & STATE_EXPANDED) {
isState(
state & STATE_COLLAPSED,
0,
false,
"Expanded " + id + " cannot be collapsed!"
);
}
if (aAbsentState && (extraState & EXT_STATE_EXPANDABLE)) {
if (aAbsentState && extraState & EXT_STATE_EXPANDABLE) {
if (aAbsentState & STATE_EXPANDED) {
isState(state & STATE_COLLAPSED, STATE_COLLAPSED, false,
"Not expanded " + id + " must be collapsed!");
isState(
state & STATE_COLLAPSED,
STATE_COLLAPSED,
false,
"Not expanded " + id + " must be collapsed!"
);
} else if (aAbsentState & STATE_COLLAPSED) {
isState(state & STATE_EXPANDED, STATE_EXPANDED, false,
"Not collapsed " + id + " must be expanded!");
isState(
state & STATE_EXPANDED,
STATE_EXPANDED,
false,
"Not collapsed " + id + " must be expanded!"
);
}
}
// checked/mixed/checkable
if (state & STATE_CHECKED || state & STATE_MIXED &&
role != ROLE_TOGGLE_BUTTON && role != ROLE_PROGRESSBAR)
isState(state & STATE_CHECKABLE, STATE_CHECKABLE, false,
"Checked or mixed element must be checkable!");
if (
state & STATE_CHECKED ||
(state & STATE_MIXED &&
role != ROLE_TOGGLE_BUTTON &&
role != ROLE_PROGRESSBAR)
) {
isState(
state & STATE_CHECKABLE,
STATE_CHECKABLE,
false,
"Checked or mixed element must be checkable!"
);
}
if (state & STATE_CHECKED)
isState(state & STATE_MIXED, 0, false,
"Checked element cannot be state mixed!");
if (state & STATE_CHECKED) {
isState(
state & STATE_MIXED,
0,
false,
"Checked element cannot be state mixed!"
);
}
if (state & STATE_MIXED)
isState(state & STATE_CHECKED, 0, false,
"Mixed element cannot be state checked!");
if (state & STATE_MIXED) {
isState(
state & STATE_CHECKED,
0,
false,
"Mixed element cannot be state checked!"
);
}
// selected/selectable
if ((state & STATE_SELECTED) && !(aAbsentState & STATE_SELECTABLE)) {
isState(state & STATE_SELECTABLE, STATE_SELECTABLE, false,
"Selected element must be selectable!");
if (state & STATE_SELECTED && !(aAbsentState & STATE_SELECTABLE)) {
isState(
state & STATE_SELECTABLE,
STATE_SELECTABLE,
false,
"Selected element must be selectable!"
);
}
}
@ -174,13 +260,15 @@ function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState) {
// test accessible and its subtree for propagated states.
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
if (!acc) {
return;
}
if (getRole(acc) != ROLE_TEXT_LEAF)
if (getRole(acc) != ROLE_TEXT_LEAF) {
// Right now, text leafs don't get tested because the states are not being
// propagated.
testStates(acc, aState, aExtraState, aAbsentState);
}
// Iterate over its children to see if the state got propagated.
var children = null;
@ -202,9 +290,13 @@ function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState) {
*/
function testIsDefunct(aAccessible, aTestName) {
var id = prettyName(aAccessible) + (aTestName ? " [" + aTestName + "]" : "");
var [/* state*/, extraState] = getStates(aAccessible);
isState(extraState & EXT_STATE_DEFUNCT, EXT_STATE_DEFUNCT, true,
"no defuct state for " + id + "!");
var [, /* state*/ extraState] = getStates(aAccessible);
isState(
extraState & EXT_STATE_DEFUNCT,
EXT_STATE_DEFUNCT,
true,
"no defuct state for " + id + "!"
);
}
function getStringStates(aAccOrElmOrID) {
@ -214,10 +306,12 @@ function getStringStates(aAccOrElmOrID) {
function getStates(aAccOrElmOrID) {
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
if (!acc) {
return [0, 0];
}
var state = {}, extraState = {};
var state = {},
extraState = {};
acc.getState(state, extraState);
return [state.value, extraState.value];
@ -228,8 +322,10 @@ function getStates(aAccOrElmOrID) {
*/
function hasState(aAccOrElmOrID, aState, aExtraState) {
var [state, exstate] = getStates(aAccOrElmOrID);
return (aState ? state & aState : true) &&
(aExtraState ? exstate & aExtraState : true);
return (
(aState ? state & aState : true) &&
(aExtraState ? exstate & aExtraState : true)
);
}
// //////////////////////////////////////////////////////////////////////////////
@ -246,14 +342,18 @@ function isState(aState1, aState2, aIsExtraStates, aMsg) {
var got = "0";
if (aState1) {
got = statesToString(aIsExtraStates ? 0 : aState1,
aIsExtraStates ? aState1 : 0);
got = statesToString(
aIsExtraStates ? 0 : aState1,
aIsExtraStates ? aState1 : 0
);
}
var expected = "0";
if (aState2) {
expected = statesToString(aIsExtraStates ? 0 : aState2,
aIsExtraStates ? aState2 : 0);
expected = statesToString(
aIsExtraStates ? 0 : aState2,
aIsExtraStates ? aState2 : 0
);
}
ok(false, aMsg + "got '" + got + "', expected '" + expected + "'");

Просмотреть файл

@ -47,10 +47,18 @@ const kMathTable = 2;
* @param aTableType [in] specifies the table type.
* @param aRowRoles [in] array of row roles.
*/
function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
aCaption, aSummary, aTableType, aRowRoles) {
function testTableStruct(
aIdentifier,
aCellsArray,
aColHeaderType,
aCaption,
aSummary,
aTableType,
aRowRoles
) {
var tableNode = getNode(aIdentifier);
var isGrid = tableNode.getAttribute("role") == "grid" ||
var isGrid =
tableNode.getAttribute("role") == "grid" ||
tableNode.getAttribute("role") == "treegrid" ||
tableNode.localName == "tree";
@ -126,8 +134,12 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
var role = ROLE_NOTHING;
switch (celltype) {
case kDataCell:
role = (aTableType == kMathTable ? ROLE_MATHML_CELL :
(isGrid ? ROLE_GRID_CELL : ROLE_CELL));
role =
aTableType == kMathTable
? ROLE_MATHML_CELL
: isGrid
? ROLE_GRID_CELL
: ROLE_CELL;
break;
case kRowHeaderCell:
role = ROLE_ROWHEADER;
@ -152,15 +164,25 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
var table = getAccessible(aIdentifier, [nsIAccessibleTable]);
// summary
if (aSummary)
is(table.summary, aSummary,
"Wrong summary of the table " + prettyName(aIdentifier));
if (aSummary) {
is(
table.summary,
aSummary,
"Wrong summary of the table " + prettyName(aIdentifier)
);
}
// rowCount and columnCount
is(table.rowCount, rowCount,
"Wrong rows count of " + prettyName(aIdentifier));
is(table.columnCount, colsCount,
"Wrong columns count of " + prettyName(aIdentifier));
is(
table.rowCount,
rowCount,
"Wrong rows count of " + prettyName(aIdentifier)
);
is(
table.columnCount,
colsCount,
"Wrong columns count of " + prettyName(aIdentifier)
);
// rows and columns extents
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
@ -170,37 +192,70 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
// table getRowExtentAt
var rowExtent = table.getRowExtentAt(rowIdx, colIdx);
let idx;
for (idx = rowIdx + 1;
idx < rowCount && (aCellsArray[idx][colIdx] & kRowSpanned);
idx++);
for (
idx = rowIdx + 1;
idx < rowCount && aCellsArray[idx][colIdx] & kRowSpanned;
idx++
) {}
var expectedRowExtent = idx - rowIdx;
is(rowExtent, expectedRowExtent,
"getRowExtentAt: Wrong number of spanned rows at (" + rowIdx + ", " +
colIdx + ") for " + prettyName(aIdentifier));
is(
rowExtent,
expectedRowExtent,
"getRowExtentAt: Wrong number of spanned rows at (" +
rowIdx +
", " +
colIdx +
") for " +
prettyName(aIdentifier)
);
// table getColumnExtentAt
var colExtent = table.getColumnExtentAt(rowIdx, colIdx);
for (idx = colIdx + 1;
idx < colsCount && (aCellsArray[rowIdx][idx] & kColSpanned);
idx++);
for (
idx = colIdx + 1;
idx < colsCount && aCellsArray[rowIdx][idx] & kColSpanned;
idx++
) {}
var expectedColExtent = idx - colIdx;
is(colExtent, expectedColExtent,
"getColumnExtentAt: Wrong number of spanned columns at (" + rowIdx +
", " + colIdx + ") for " + prettyName(aIdentifier));
is(
colExtent,
expectedColExtent,
"getColumnExtentAt: Wrong number of spanned columns at (" +
rowIdx +
", " +
colIdx +
") for " +
prettyName(aIdentifier)
);
// cell rowExtent and columnExtent
var cell = getAccessible(table.getCellAt(rowIdx, colIdx),
[nsIAccessibleTableCell]);
var cell = getAccessible(table.getCellAt(rowIdx, colIdx), [
nsIAccessibleTableCell,
]);
is(cell.rowExtent, expectedRowExtent,
"rowExtent: Wrong number of spanned rows at (" + rowIdx + ", " +
colIdx + ") for " + prettyName(aIdentifier));
is(
cell.rowExtent,
expectedRowExtent,
"rowExtent: Wrong number of spanned rows at (" +
rowIdx +
", " +
colIdx +
") for " +
prettyName(aIdentifier)
);
is(cell.columnExtent, expectedColExtent,
"columnExtent: Wrong number of spanned column at (" + rowIdx + ", " +
colIdx + ") for " + prettyName(aIdentifier));
is(
cell.columnExtent,
expectedColExtent,
"columnExtent: Wrong number of spanned column at (" +
rowIdx +
", " +
colIdx +
") for " +
prettyName(aIdentifier)
);
}
}
}
@ -214,8 +269,9 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
*/
function testTableIndexes(aIdentifier, aIdxes) {
var tableAcc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!tableAcc)
if (!tableAcc) {
return;
}
var obtainedRowIdx, obtainedColIdx, obtainedIdx;
var cellAcc;
@ -232,55 +288,105 @@ function testTableIndexes(aIdentifier, aIdxes) {
try {
cellAcc = null;
cellAcc = tableAcc.getCellAt(rowIdx, colIdx);
} catch (e) { }
} catch (e) {}
ok(idx != -1 && cellAcc || idx == -1 && !cellAcc,
id + ": Can't get cell accessible at row = " + rowIdx + ", column = " + colIdx);
ok(
(idx != -1 && cellAcc) || (idx == -1 && !cellAcc),
id +
": Can't get cell accessible at row = " +
rowIdx +
", column = " +
colIdx
);
if (idx != -1) {
// getRowIndexAt
var origRowIdx = rowIdx;
while (origRowIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
while (
origRowIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx]
) {
origRowIdx--;
}
try {
obtainedRowIdx = tableAcc.getRowIndexAt(idx);
} catch (e) {
ok(false, id + ": can't get row index for cell index " + idx + "," + e);
ok(
false,
id + ": can't get row index for cell index " + idx + "," + e
);
}
is(obtainedRowIdx, origRowIdx,
id + ": row for index " + idx + " is not correct (getRowIndexAt)");
is(
obtainedRowIdx,
origRowIdx,
id + ": row for index " + idx + " is not correct (getRowIndexAt)"
);
// getColumnIndexAt
var origColIdx = colIdx;
while (origColIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1])
while (
origColIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1]
) {
origColIdx--;
}
try {
obtainedColIdx = tableAcc.getColumnIndexAt(idx);
} catch (e) {
ok(false, id + ": can't get column index for cell index " + idx + "," + e);
ok(
false,
id + ": can't get column index for cell index " + idx + "," + e
);
}
is(obtainedColIdx, origColIdx,
id + ": column for index " + idx + " is not correct (getColumnIndexAt)");
is(
obtainedColIdx,
origColIdx,
id +
": column for index " +
idx +
" is not correct (getColumnIndexAt)"
);
// getRowAndColumnIndicesAt
var obtainedRowIdxObj = { }, obtainedColIdxObj = { };
var obtainedRowIdxObj = {},
obtainedColIdxObj = {};
try {
tableAcc.getRowAndColumnIndicesAt(idx, obtainedRowIdxObj,
obtainedColIdxObj);
tableAcc.getRowAndColumnIndicesAt(
idx,
obtainedRowIdxObj,
obtainedColIdxObj
);
} catch (e) {
ok(false, id + ": can't get row and column indices for cell index " + idx + "," + e);
ok(
false,
id +
": can't get row and column indices for cell index " +
idx +
"," +
e
);
}
is(obtainedRowIdxObj.value, origRowIdx,
id + ": row for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
is(obtainedColIdxObj.value, origColIdx,
id + ": column for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
is(
obtainedRowIdxObj.value,
origRowIdx,
id +
": row for index " +
idx +
" is not correct (getRowAndColumnIndicesAt)"
);
is(
obtainedColIdxObj.value,
origColIdx,
id +
": column for index " +
idx +
" is not correct (getRowAndColumnIndicesAt)"
);
if (cellAcc) {
var cellId = prettyName(cellAcc);
@ -292,45 +398,74 @@ function testTableIndexes(aIdentifier, aIdxes) {
try {
strIdx = attrs.getStringProperty("table-cell-index");
} catch (e) {
ok(false,
cellId + ": no cell index from object attributes on the cell accessible at index " + idx + ".");
ok(
false,
cellId +
": no cell index from object attributes on the cell accessible at index " +
idx +
"."
);
}
if (strIdx) {
is(parseInt(strIdx), idx,
cellId + ": cell index from object attributes of cell accessible isn't corrent.");
is(
parseInt(strIdx),
idx,
cellId +
": cell index from object attributes of cell accessible isn't corrent."
);
}
// cell: table
try {
is(cellAcc.table, tableAcc,
cellId + ": wrong table accessible for the cell.");
is(
cellAcc.table,
tableAcc,
cellId + ": wrong table accessible for the cell."
);
} catch (e) {
ok(false,
cellId + ": can't get table accessible from the cell.");
ok(false, cellId + ": can't get table accessible from the cell.");
}
// cell: getRowIndex
try {
obtainedRowIdx = cellAcc.rowIndex;
} catch (e) {
ok(false,
cellId + ": can't get row index of the cell at index " + idx + "," + e);
ok(
false,
cellId +
": can't get row index of the cell at index " +
idx +
"," +
e
);
}
is(obtainedRowIdx, origRowIdx,
cellId + ": row for the cell at index " + idx + " is not correct");
is(
obtainedRowIdx,
origRowIdx,
cellId + ": row for the cell at index " + idx + " is not correct"
);
// cell: getColumnIndex
try {
obtainedColIdx = cellAcc.columnIndex;
} catch (e) {
ok(false,
cellId + ": can't get column index of the cell at index " + idx + "," + e);
ok(
false,
cellId +
": can't get column index of the cell at index " +
idx +
"," +
e
);
}
is(obtainedColIdx, origColIdx,
id + ": column for the cell at index " + idx + " is not correct");
is(
obtainedColIdx,
origColIdx,
id + ": column for the cell at index " + idx + " is not correct"
);
}
}
@ -341,8 +476,18 @@ function testTableIndexes(aIdentifier, aIdxes) {
obtainedIdx = -1;
}
is(obtainedIdx, idx,
id + ": row " + rowIdx + " /column " + colIdx + " and index " + obtainedIdx + " aren't inconsistent.");
is(
obtainedIdx,
idx,
id +
": row " +
rowIdx +
" /column " +
colIdx +
" and index " +
obtainedIdx +
" aren't inconsistent."
);
}
}
}
@ -359,8 +504,9 @@ function testTableIndexes(aIdentifier, aIdxes) {
function testTableSelection(aIdentifier, aCellsArray, aMsg) {
var msg = aMsg ? aMsg : "";
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!acc)
if (!acc) {
return;
}
var rowCount = aCellsArray.length;
var colsCount = aCellsArray[0].length;
@ -372,36 +518,56 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
var isColSelected = true;
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
if (!aCellsArray[rowIdx][colIdx] ||
aCellsArray[rowIdx][colIdx] == undefined) {
if (
!aCellsArray[rowIdx][colIdx] ||
aCellsArray[rowIdx][colIdx] == undefined
) {
isColSelected = false;
break;
}
}
is(acc.isColumnSelected(colIdx), isColSelected,
msg + "Wrong selection state of " + colIdx + " column for " +
prettyName(aIdentifier));
is(
acc.isColumnSelected(colIdx),
isColSelected,
msg +
"Wrong selection state of " +
colIdx +
" column for " +
prettyName(aIdentifier)
);
if (isColSelected)
if (isColSelected) {
selCols.push(colIdx);
}
}
// selectedColsCount test
is(acc.selectedColumnCount, selCols.length,
msg + "Wrong count of selected columns for " + prettyName(aIdentifier));
is(
acc.selectedColumnCount,
selCols.length,
msg + "Wrong count of selected columns for " + prettyName(aIdentifier)
);
// getSelectedColumns test
var actualSelCols = acc.getSelectedColumnIndices();
var actualSelColsCount = actualSelCols.length;
is(actualSelColsCount, selCols.length,
msg + "Wrong count of selected columns for " + prettyName(aIdentifier) +
"from getSelectedColumns.");
is(
actualSelColsCount,
selCols.length,
msg +
"Wrong count of selected columns for " +
prettyName(aIdentifier) +
"from getSelectedColumns."
);
for (let i = 0; i < actualSelColsCount; i++) {
is(actualSelCols[i], selCols[i],
msg + "Column at index " + selCols[i] + " should be selected.");
is(
actualSelCols[i],
selCols[i],
msg + "Column at index " + selCols[i] + " should be selected."
);
}
// Rows selection tests.
@ -411,36 +577,56 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
var isRowSelected = true;
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
if (!aCellsArray[rowIdx][colIdx] ||
aCellsArray[rowIdx][colIdx] == undefined) {
if (
!aCellsArray[rowIdx][colIdx] ||
aCellsArray[rowIdx][colIdx] == undefined
) {
isRowSelected = false;
break;
}
}
is(acc.isRowSelected(rowIdx), isRowSelected,
msg + "Wrong selection state of " + rowIdx + " row for " +
prettyName(aIdentifier));
is(
acc.isRowSelected(rowIdx),
isRowSelected,
msg +
"Wrong selection state of " +
rowIdx +
" row for " +
prettyName(aIdentifier)
);
if (isRowSelected)
if (isRowSelected) {
selRows.push(rowIdx);
}
}
// selectedRowCount test
is(acc.selectedRowCount, selRows.length,
msg + "Wrong count of selected rows for " + prettyName(aIdentifier));
is(
acc.selectedRowCount,
selRows.length,
msg + "Wrong count of selected rows for " + prettyName(aIdentifier)
);
// getSelectedRows test
var actualSelRows = acc.getSelectedRowIndices();
var actualSelrowCount = actualSelRows.length;
is(actualSelrowCount, selRows.length,
msg + "Wrong count of selected rows for " + prettyName(aIdentifier) +
"from getSelectedRows.");
is(
actualSelrowCount,
selRows.length,
msg +
"Wrong count of selected rows for " +
prettyName(aIdentifier) +
"from getSelectedRows."
);
for (let i = 0; i < actualSelrowCount; i++) {
is(actualSelRows[i], selRows[i],
msg + "Row at index " + selRows[i] + " should be selected.");
is(
actualSelRows[i],
selRows[i],
msg + "Row at index " + selRows[i] + " should be selected."
);
}
// Cells selection tests.
@ -449,69 +635,103 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
// isCellSelected test
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
if (aCellsArray[rowIdx][colIdx] & kSpanned)
if (aCellsArray[rowIdx][colIdx] & kSpanned) {
continue;
}
var isSelected = !!aCellsArray[rowIdx][colIdx];
is(acc.isCellSelected(rowIdx, colIdx), isSelected,
msg + "Wrong selection state of cell at " + rowIdx + " row and " +
colIdx + " column for " + prettyName(aIdentifier));
is(
acc.isCellSelected(rowIdx, colIdx),
isSelected,
msg +
"Wrong selection state of cell at " +
rowIdx +
" row and " +
colIdx +
" column for " +
prettyName(aIdentifier)
);
if (aCellsArray[rowIdx][colIdx])
if (aCellsArray[rowIdx][colIdx]) {
selCells.push(acc.getCellIndexAt(rowIdx, colIdx));
}
}
}
// selectedCellCount tests
is(acc.selectedCellCount, selCells.length,
msg + "Wrong count of selected cells for " + prettyName(aIdentifier));
is(
acc.selectedCellCount,
selCells.length,
msg + "Wrong count of selected cells for " + prettyName(aIdentifier)
);
// getSelectedCellIndices test
var actualSelCells = acc.getSelectedCellIndices();
var actualSelCellsCount = actualSelCells.length;
is(actualSelCellsCount, selCells.length,
msg + "Wrong count of selected cells for " + prettyName(aIdentifier) +
"from getSelectedCells.");
is(
actualSelCellsCount,
selCells.length,
msg +
"Wrong count of selected cells for " +
prettyName(aIdentifier) +
"from getSelectedCells."
);
for (let i = 0; i < actualSelCellsCount; i++) {
is(actualSelCells[i], selCells[i],
msg + "getSelectedCellIndices: Cell at index " + selCells[i] +
" should be selected.");
is(
actualSelCells[i],
selCells[i],
msg +
"getSelectedCellIndices: Cell at index " +
selCells[i] +
" should be selected."
);
}
// selectedCells and isSelected tests
var actualSelCellsArray = acc.selectedCells;
for (let i = 0; i < actualSelCellsCount; i++) {
var actualSelCellAccessible =
actualSelCellsArray.queryElementAt(i, nsIAccessibleTableCell);
var actualSelCellAccessible = actualSelCellsArray.queryElementAt(
i,
nsIAccessibleTableCell
);
let colIdx = acc.getColumnIndexAt(selCells[i]);
let rowIdx = acc.getRowIndexAt(selCells[i]);
var expectedSelCellAccessible = acc.getCellAt(rowIdx, colIdx);
is(actualSelCellAccessible, expectedSelCellAccessible,
msg + "getSelectedCells: Cell at index " + selCells[i] +
" should be selected.");
is(
actualSelCellAccessible,
expectedSelCellAccessible,
msg +
"getSelectedCells: Cell at index " +
selCells[i] +
" should be selected."
);
ok(actualSelCellAccessible.isSelected(),
"isSelected: Cell at index " + selCells[i] + " should be selected.");
ok(
actualSelCellAccessible.isSelected(),
"isSelected: Cell at index " + selCells[i] + " should be selected."
);
}
// selected states tests
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
if (aCellsArray[rowIdx][colIdx] & kSpanned)
if (aCellsArray[rowIdx][colIdx] & kSpanned) {
continue;
}
var cell = acc.getCellAt(rowIdx, colIdx);
var isSel = aCellsArray[rowIdx][colIdx];
if (isSel == undefined)
if (isSel == undefined) {
testStates(cell, 0, 0, STATE_SELECTABLE | STATE_SELECTED);
else if (isSel)
} else if (isSel) {
testStates(cell, STATE_SELECTED);
else
} else {
testStates(cell, STATE_SELECTABLE, 0, STATE_SELECTED);
}
}
}
}
@ -521,20 +741,27 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
*/
function testUnselectTableColumn(aIdentifier, aColIdx, aCellsArray) {
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!acc)
if (!acc) {
return;
}
var rowCount = aCellsArray.length;
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
// Unselect origin cell.
var [origRowIdx, origColIdx] =
getOrigRowAndColumn(aCellsArray, rowIdx, aColIdx);
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
aCellsArray,
rowIdx,
aColIdx
);
aCellsArray[origRowIdx][origColIdx] = false;
}
acc.unselectColumn(aColIdx);
testTableSelection(aIdentifier, aCellsArray,
"Unselect " + aColIdx + " column: ");
testTableSelection(
aIdentifier,
aCellsArray,
"Unselect " + aColIdx + " column: "
);
}
/**
@ -542,8 +769,9 @@ function testUnselectTableColumn(aIdentifier, aColIdx, aCellsArray) {
*/
function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!acc)
if (!acc) {
return;
}
var rowCount = aCellsArray.length;
var colsCount = aCellsArray[0].length;
@ -552,17 +780,22 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
var cellState = aCellsArray[rowIdx][colIdx];
if (colIdx == aColIdx) { // select target column
if (colIdx == aColIdx) {
// select target column
if (!(cellState & kSpanned)) {
// Select the cell if it is origin.
aCellsArray[rowIdx][colIdx] = true;
} else {
// If the cell is spanned then search origin cell and select it.
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
rowIdx, colIdx);
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
aCellsArray,
rowIdx,
colIdx
);
aCellsArray[origRowIdx][origColIdx] = true;
}
} else if (!(cellState & kSpanned)) { // unselect other columns
} else if (!(cellState & kSpanned)) {
// unselect other columns
if (colIdx > aColIdx) {
// Unselect the cell if traversed column index is greater than column
// index of target cell.
@ -572,8 +805,11 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
aCellsArray[rowIdx][colIdx] = false;
} else {
// Unselect the cell if it is not spanned to the target cell.
for (var spannedColIdx = colIdx + 1; spannedColIdx < aColIdx;
spannedColIdx++) {
for (
var spannedColIdx = colIdx + 1;
spannedColIdx < aColIdx;
spannedColIdx++
) {
var spannedCellState = aCellsArray[rowIdx][spannedColIdx];
if (!(spannedCellState & kRowSpanned)) {
aCellsArray[rowIdx][colIdx] = false;
@ -586,8 +822,11 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
}
acc.selectColumn(aColIdx);
testTableSelection(aIdentifier, aCellsArray,
"Select " + aColIdx + " column: ");
testTableSelection(
aIdentifier,
aCellsArray,
"Select " + aColIdx + " column: "
);
}
/**
@ -595,20 +834,27 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
*/
function testUnselectTableRow(aIdentifier, aRowIdx, aCellsArray) {
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!acc)
if (!acc) {
return;
}
var colsCount = aCellsArray[0].length;
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
// Unselect origin cell.
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
aRowIdx, colIdx);
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
aCellsArray,
aRowIdx,
colIdx
);
aCellsArray[origRowIdx][origColIdx] = false;
}
acc.unselectRow(aRowIdx);
testTableSelection(aIdentifier, aCellsArray,
"Unselect " + aRowIdx + " row: ");
testTableSelection(
aIdentifier,
aCellsArray,
"Unselect " + aRowIdx + " row: "
);
}
/**
@ -616,8 +862,9 @@ function testUnselectTableRow(aIdentifier, aRowIdx, aCellsArray) {
*/
function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
if (!acc)
if (!acc) {
return;
}
var rowCount = aCellsArray.length;
var colsCount = aCellsArray[0].length;
@ -626,18 +873,23 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
var cellState = aCellsArray[rowIdx][colIdx];
if (rowIdx == aRowIdx) { // select the given row
if (rowIdx == aRowIdx) {
// select the given row
if (!(cellState & kSpanned)) {
// Select the cell if it is origin.
aCellsArray[rowIdx][colIdx] = true;
} else {
// If the cell is spanned then search origin cell and select it.
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
rowIdx, colIdx);
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
aCellsArray,
rowIdx,
colIdx
);
aCellsArray[origRowIdx][origColIdx] = true;
}
} else if (!(cellState & kSpanned)) { // unselect other rows
} else if (!(cellState & kSpanned)) {
// unselect other rows
if (rowIdx > aRowIdx) {
// Unselect the cell if traversed row index is greater than row
// index of target cell.
@ -647,8 +899,11 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
aCellsArray[rowIdx][colIdx] = false;
} else {
// Unselect the cell if it is not spanned to the target cell.
for (var spannedRowIdx = rowIdx + 1; spannedRowIdx < aRowIdx;
spannedRowIdx++) {
for (
var spannedRowIdx = rowIdx + 1;
spannedRowIdx < aRowIdx;
spannedRowIdx++
) {
var spannedCellState = aCellsArray[spannedRowIdx][colIdx];
if (!(spannedCellState & kRowSpanned)) {
aCellsArray[rowIdx][colIdx] = false;
@ -661,8 +916,7 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
}
acc.selectRow(aRowIdx);
testTableSelection(aIdentifier, aCellsArray,
"Select " + aRowIdx + " row: ");
testTableSelection(aIdentifier, aCellsArray, "Select " + aRowIdx + " row: ");
}
/**
@ -679,18 +933,28 @@ function testHeaderCells(aHeaderInfoMap) {
var actualRowHeaderCells = dataCell.rowHeaderCells;
var actualRowHeaderCellsCount = actualRowHeaderCells.length;
is(actualRowHeaderCellsCount, rowHeaderCellsCount,
"Wrong number of row header cells for the cell " +
prettyName(dataCellIdentifier));
is(
actualRowHeaderCellsCount,
rowHeaderCellsCount,
"Wrong number of row header cells for the cell " +
prettyName(dataCellIdentifier)
);
if (actualRowHeaderCellsCount == rowHeaderCellsCount) {
for (let idx = 0; idx < rowHeaderCellsCount; idx++) {
var rowHeaderCell = getAccessible(rowHeaderCells[idx]);
var actualRowHeaderCell =
actualRowHeaderCells.queryElementAt(idx, nsIAccessible);
isObject(actualRowHeaderCell, rowHeaderCell,
"Wrong row header cell at index " + idx + " for the cell " +
dataCellIdentifier);
var actualRowHeaderCell = actualRowHeaderCells.queryElementAt(
idx,
nsIAccessible
);
isObject(
actualRowHeaderCell,
rowHeaderCell,
"Wrong row header cell at index " +
idx +
" for the cell " +
dataCellIdentifier
);
}
}
@ -700,18 +964,28 @@ function testHeaderCells(aHeaderInfoMap) {
var actualColHeaderCells = dataCell.columnHeaderCells;
var actualColHeaderCellsCount = actualColHeaderCells.length;
is(actualColHeaderCellsCount, colHeaderCellsCount,
"Wrong number of column header cells for the cell " +
prettyName(dataCellIdentifier));
is(
actualColHeaderCellsCount,
colHeaderCellsCount,
"Wrong number of column header cells for the cell " +
prettyName(dataCellIdentifier)
);
if (actualColHeaderCellsCount == colHeaderCellsCount) {
for (let idx = 0; idx < colHeaderCellsCount; idx++) {
var colHeaderCell = getAccessible(colHeaderCells[idx]);
var actualColHeaderCell =
actualColHeaderCells.queryElementAt(idx, nsIAccessible);
isObject(actualColHeaderCell, colHeaderCell,
"Wrong column header cell at index " + idx + " for the cell " +
dataCellIdentifier);
var actualColHeaderCell = actualColHeaderCells.queryElementAt(
idx,
nsIAccessible
);
isObject(
actualColHeaderCell,
colHeaderCell,
"Wrong column header cell at index " +
idx +
" for the cell " +
dataCellIdentifier
);
}
}
}
@ -726,7 +1000,8 @@ function testHeaderCells(aHeaderInfoMap) {
function getOrigRowAndColumn(aCellsArray, aRowIdx, aColIdx) {
var cellState = aCellsArray[aRowIdx][aColIdx];
var origRowIdx = aRowIdx, origColIdx = aColIdx;
var origRowIdx = aRowIdx,
origColIdx = aColIdx;
if (cellState & kRowSpanned) {
for (var prevRowIdx = aRowIdx - 1; prevRowIdx >= 0; prevRowIdx--) {
let prevCellState = aCellsArray[prevRowIdx][aColIdx];

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше