зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1723614 - P2: Robustify name change events and use events in name tests. r=Jamie
Changed the browser and mochitest name tests to rely exclusively on name change events. To make this happen, I fixed all the cases where we were event-deficient in the code: * Examine target in PushNameOrDescriptionChange if it has eNameFromSubtreeRule. Fixes cases where a text change event happens with the subtree name root as target. * Change in aria-labelledby should always result in a name change event because that attribute has highest prescedence. * Add eHasNameDependent/eHasDescriptionDependent context flags when dependee accessible is added after dependent accessible to tree. * Handle value attribute change in HTML buttons and determine if they should trigger a name changed event. * Use accessible tree instead of content tree when calculating HTMLSelectOptionAccessible name, this keeps the PushNameOrDescriptionChange sees in name flags consistent with the actual tree. * Handle label attribute change in select options and determine if they should trigger a name changed event. * Determine if s summary attribute change on a table triggers a name change event. * If a title attribute is changed, reliably fire a name change event if it is used in name calculation. Differential Revision: https://phabricator.services.mozilla.com/D121580
This commit is contained in:
Родитель
caafeaea2a
Коммит
7255c6bf8e
|
@ -63,12 +63,11 @@ bool EventQueue::PushNameOrDescriptionChange(LocalAccessible* aTarget) {
|
|||
// Only continue traversing up the tree if it's possible that the parent
|
||||
// LocalAccessible's name (or a LocalAccessible being labelled by this
|
||||
// LocalAccessible or an ancestor) can depend on this LocalAccessible's name.
|
||||
LocalAccessible* parent = aTarget->LocalParent();
|
||||
while (parent &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
|
||||
LocalAccessible* parent = aTarget;
|
||||
do {
|
||||
// Test possible name dependent parent.
|
||||
if (doName) {
|
||||
if (nameCheckAncestor &&
|
||||
if (nameCheckAncestor && parent != aTarget &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
|
||||
nsAutoString name;
|
||||
ENameValueFlag nameFlag = parent->Name(name);
|
||||
|
@ -99,7 +98,9 @@ bool EventQueue::PushNameOrDescriptionChange(LocalAccessible* aTarget) {
|
|||
}
|
||||
|
||||
parent = parent->LocalParent();
|
||||
}
|
||||
} while (parent &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule));
|
||||
|
||||
return pushed;
|
||||
}
|
||||
|
||||
|
|
|
@ -1239,11 +1239,14 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
|||
mDoc->Controller()->ScheduleRelocation(this);
|
||||
}
|
||||
|
||||
// Fire name change and description change events. XXX: it's not complete and
|
||||
// dupes the code logic of accessible name and description calculation, we do
|
||||
// that for performance reasons.
|
||||
// Fire name change and description change events.
|
||||
if (aAttribute == nsGkAtoms::aria_label) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
// A valid aria-labelledby would take precedence so an aria-label change
|
||||
// won't change the name.
|
||||
IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby);
|
||||
if (!iter.NextElem()) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1256,21 +1259,13 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
|||
// the eHasDescriptionDependent flag on all Accessibles in these subtrees.
|
||||
IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_describedby);
|
||||
while (LocalAccessible* target = iter.Next()) {
|
||||
Pivot pivot(target);
|
||||
LocalAccInSameDocRule rule;
|
||||
for (Accessible* anchor = target; anchor;
|
||||
anchor = pivot.Next(anchor, rule)) {
|
||||
LocalAccessible* acc = anchor->AsLocal();
|
||||
MOZ_ASSERT(acc);
|
||||
acc->mContextFlags |= eHasDescriptionDependent;
|
||||
}
|
||||
target->ModifySubtreeContextFlags(eHasDescriptionDependent, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_labelledby &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label)) {
|
||||
if (aAttribute == nsGkAtoms::aria_labelledby) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
if (aModType == dom::MutationEvent_Binding::MODIFICATION ||
|
||||
aModType == dom::MutationEvent_Binding::ADDITION) {
|
||||
|
@ -1279,14 +1274,7 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
|||
// the eHasNameDependent flag on all Accessibles in these subtrees.
|
||||
IDRefsIterator iter(mDoc, elm, nsGkAtoms::aria_labelledby);
|
||||
while (LocalAccessible* target = iter.Next()) {
|
||||
Pivot pivot(target);
|
||||
LocalAccInSameDocRule rule;
|
||||
for (Accessible* anchor = target; anchor;
|
||||
anchor = pivot.Next(anchor, rule)) {
|
||||
LocalAccessible* acc = anchor->AsLocal();
|
||||
MOZ_ASSERT(acc);
|
||||
acc->mContextFlags |= eHasNameDependent;
|
||||
}
|
||||
target->ModifySubtreeContextFlags(eHasNameDependent, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1300,11 +1288,14 @@ void LocalAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
|||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::title) {
|
||||
if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label) &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby) &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
return;
|
||||
nsAutoString name;
|
||||
ARIAName(name);
|
||||
if (name.IsEmpty()) {
|
||||
NativeName(name);
|
||||
if (name.IsEmpty()) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_describedby)) {
|
||||
|
@ -2381,6 +2372,23 @@ void LocalAccessible::BindToParent(LocalAccessible* aParent,
|
|||
mContextFlags &= ~eHasDescriptionDependent;
|
||||
}
|
||||
|
||||
// Add name/description dependent flags for dependent content once
|
||||
// a name/description provider is added to doc.
|
||||
Relation rel = RelationByType(RelationType::LABELLED_BY);
|
||||
LocalAccessible* relTarget = nullptr;
|
||||
while ((relTarget = rel.Next())) {
|
||||
if (!relTarget->HasNameDependent()) {
|
||||
relTarget->ModifySubtreeContextFlags(eHasNameDependent, true);
|
||||
}
|
||||
}
|
||||
|
||||
rel = RelationByType(RelationType::DESCRIBED_BY);
|
||||
while ((relTarget = rel.Next())) {
|
||||
if (!relTarget->HasDescriptionDependent()) {
|
||||
relTarget->ModifySubtreeContextFlags(eHasDescriptionDependent, true);
|
||||
}
|
||||
}
|
||||
|
||||
mContextFlags |=
|
||||
static_cast<uint32_t>((mParent->IsAlert() || mParent->IsInsideAlert())) &
|
||||
eInsideAlert;
|
||||
|
@ -2885,6 +2893,21 @@ LocalAccessible* LocalAccessible::GetSiblingAtOffset(int32_t aOffset,
|
|||
return child;
|
||||
}
|
||||
|
||||
void LocalAccessible::ModifySubtreeContextFlags(uint32_t aContextFlags,
|
||||
bool aAdd) {
|
||||
Pivot pivot(this);
|
||||
LocalAccInSameDocRule rule;
|
||||
for (Accessible* anchor = this; anchor; anchor = pivot.Next(anchor, rule)) {
|
||||
MOZ_ASSERT(anchor->IsLocal());
|
||||
LocalAccessible* acc = anchor->AsLocal();
|
||||
if (aAdd) {
|
||||
acc->mContextFlags |= aContextFlags;
|
||||
} else {
|
||||
acc->mContextFlags &= ~aContextFlags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double LocalAccessible::AttrNumericValue(nsAtom* aAttr) const {
|
||||
const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
|
||||
if (!roleMapEntry || roleMapEntry->valueRule == eNoValue) {
|
||||
|
|
|
@ -968,6 +968,8 @@ class LocalAccessible : public nsISupports, public Accessible {
|
|||
virtual LocalAccessible* GetSiblingAtOffset(int32_t aOffset,
|
||||
nsresult* aError = nullptr) const;
|
||||
|
||||
void ModifySubtreeContextFlags(uint32_t aContextFlags, bool aAdd);
|
||||
|
||||
/**
|
||||
* Flags used to describe the state of this accessible.
|
||||
*/
|
||||
|
|
|
@ -204,6 +204,28 @@ ENameValueFlag HTMLButtonAccessible::NativeName(nsString& aName) const {
|
|||
return eNameOK;
|
||||
}
|
||||
|
||||
void HTMLButtonAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue,
|
||||
uint64_t aOldState) {
|
||||
HyperTextAccessibleWrap::DOMAttributeChanged(aNameSpaceID, aAttribute,
|
||||
aModType, aOldValue, aOldState);
|
||||
|
||||
if (aAttribute == nsGkAtoms::value) {
|
||||
dom::Element* elm = Elm();
|
||||
if (elm->IsHTMLElement(nsGkAtoms::input) ||
|
||||
(elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::image,
|
||||
eCaseMatters) &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::alt))) {
|
||||
if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby) &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label)) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HTMLButtonAccessible: Widgets
|
||||
|
||||
|
|
|
@ -65,6 +65,11 @@ class HTMLButtonAccessible : public HyperTextAccessibleWrap {
|
|||
protected:
|
||||
// LocalAccessible
|
||||
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
||||
|
||||
virtual void DOMAttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue,
|
||||
uint64_t aOldState) override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -123,7 +123,8 @@ ENameValueFlag HTMLSelectOptionAccessible::NativeName(nsString& aName) const {
|
|||
|
||||
// CASE #2 -- no label parameter, get the first child,
|
||||
// use it if it is a text node
|
||||
nsIContent* text = mContent->GetFirstChild();
|
||||
LocalAccessible* firstChild = LocalFirstChild();
|
||||
nsIContent* text = firstChild ? firstChild->GetContent() : nullptr;
|
||||
if (text && text->IsText()) {
|
||||
nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName);
|
||||
aName.CompressWhitespace();
|
||||
|
@ -133,6 +134,21 @@ ENameValueFlag HTMLSelectOptionAccessible::NativeName(nsString& aName) const {
|
|||
return eNameOK;
|
||||
}
|
||||
|
||||
void HTMLSelectOptionAccessible::DOMAttributeChanged(
|
||||
int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue, uint64_t aOldState) {
|
||||
HyperTextAccessibleWrap::DOMAttributeChanged(aNameSpaceID, aAttribute,
|
||||
aModType, aOldValue, aOldState);
|
||||
|
||||
if (aAttribute == nsGkAtoms::label) {
|
||||
dom::Element* elm = Elm();
|
||||
if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby) &&
|
||||
!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label)) {
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t HTMLSelectOptionAccessible::NativeState() const {
|
||||
// As a HTMLSelectOptionAccessible we can have the following states:
|
||||
// SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN
|
||||
|
|
|
@ -81,6 +81,10 @@ class HTMLSelectOptionAccessible : public HyperTextAccessibleWrap {
|
|||
protected:
|
||||
// LocalAccessible
|
||||
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
||||
virtual void DOMAttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue,
|
||||
uint64_t aOldState) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -415,6 +415,15 @@ void HTMLTableAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
|
|||
aModType, aOldValue, aOldState);
|
||||
|
||||
if (aAttribute == nsGkAtoms::summary) {
|
||||
nsAutoString name;
|
||||
ARIAName(name);
|
||||
if (name.IsEmpty()) {
|
||||
if (!Caption()) {
|
||||
// XXX: Should really be checking if caption provides a name.
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
}
|
||||
}
|
||||
|
||||
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
|
||||
this);
|
||||
}
|
||||
|
|
|
@ -19,19 +19,11 @@ loadScripts({ name: "name.js", dir: MOCHITESTS_DIR });
|
|||
* { elm } - calculated from another element
|
||||
* { fromsubtree } - calculated from element's subtree
|
||||
*
|
||||
*
|
||||
* Options include:
|
||||
* * waitFor - changes in the subtree will result in an accessible event
|
||||
* being fired, the test must only continue after the event
|
||||
* is receieved.
|
||||
*/
|
||||
const ARIARule = [
|
||||
{ attr: "aria-labelledby" },
|
||||
{ attr: "aria-label", waitFor: EVENT_NAME_CHANGE },
|
||||
];
|
||||
const HTMLControlHeadRule = [...ARIARule, { elm: "label", isSibling: true }];
|
||||
const ARIARule = [{ attr: "aria-labelledby" }, { attr: "aria-label" }];
|
||||
const HTMLControlHeadRule = [...ARIARule, { elm: "label" }];
|
||||
const rules = {
|
||||
CSSContent: [{ elm: "style", isSibling: true }, { fromsubtree: true }],
|
||||
CSSContent: [{ elm: "style" }, { fromsubtree: true }],
|
||||
HTMLARIAGridCell: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
|
||||
HTMLControl: [
|
||||
...HTMLControlHeadRule,
|
||||
|
@ -39,11 +31,7 @@ const rules = {
|
|||
{ attr: "title" },
|
||||
],
|
||||
HTMLElm: [...ARIARule, { attr: "title" }],
|
||||
HTMLImg: [
|
||||
...ARIARule,
|
||||
{ attr: "alt", waitFor: EVENT_NAME_CHANGE },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLImg: [...ARIARule, { attr: "alt" }, { attr: "title" }],
|
||||
HTMLImgEmptyAlt: [...ARIARule, { attr: "title" }, { attr: "alt" }],
|
||||
HTMLInputButton: [
|
||||
...HTMLControlHeadRule,
|
||||
|
@ -52,25 +40,19 @@ const rules = {
|
|||
],
|
||||
HTMLInputImage: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", waitFor: EVENT_NAME_CHANGE },
|
||||
{ attr: "alt" },
|
||||
{ attr: "value" },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLInputImageNoValidSrc: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", waitFor: EVENT_NAME_CHANGE },
|
||||
{ attr: "alt" },
|
||||
{ attr: "value" },
|
||||
],
|
||||
HTMLInputReset: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "value", waitFor: EVENT_TEXT_INSERTED },
|
||||
],
|
||||
HTMLInputSubmit: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "value", waitFor: EVENT_TEXT_INSERTED },
|
||||
],
|
||||
HTMLInputReset: [...HTMLControlHeadRule, { attr: "value" }],
|
||||
HTMLInputSubmit: [...HTMLControlHeadRule, { attr: "value" }],
|
||||
HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
|
||||
HTMLLinkImage: [...ARIARule, { elm: "img" }, { attr: "title" }],
|
||||
HTMLLinkImage: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
|
||||
HTMLOption: [
|
||||
...ARIARule,
|
||||
{ attr: "label" },
|
||||
|
@ -396,34 +378,26 @@ const markupTests = [
|
|||
* becomes defunct, update its reference using the one that is attached to one
|
||||
* of the above events.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* @param {Object} target { acc, id } structure that contains an
|
||||
* accessible and its content element
|
||||
* id.
|
||||
* @param {Object} rule current attr rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
async function testAttrRule(browser, target, rule, expected) {
|
||||
let { id, parent, acc } = target;
|
||||
let { waitFor, attr } = rule;
|
||||
let { id, acc } = target;
|
||||
let { attr } = rule;
|
||||
|
||||
testName(acc, expected);
|
||||
|
||||
if (waitFor) {
|
||||
let [event] = await contentSpawnMutation(
|
||||
browser,
|
||||
{
|
||||
expected: [[waitFor, waitFor === EVENT_REORDER ? parent : id]],
|
||||
},
|
||||
(contentId, contentAttr) =>
|
||||
content.document.getElementById(contentId).removeAttribute(contentAttr),
|
||||
[id, attr]
|
||||
);
|
||||
let nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
|
||||
await invokeContentTask(browser, [id, attr], (contentId, contentAttr) => {
|
||||
content.document.getElementById(contentId).removeAttribute(contentAttr);
|
||||
});
|
||||
let event = await nameChange;
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
} else {
|
||||
await invokeSetAttribute(browser, id, attr);
|
||||
}
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -432,25 +406,23 @@ async function testAttrRule(browser, target, rule, expected) {
|
|||
* in a reorder event - wait for it. If accessible becomes defunct, update its
|
||||
* reference using the one that is attached to a possible reorder event.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* @param {Object} target { acc, id } structure that contains an
|
||||
* accessible and its content element
|
||||
* id.
|
||||
* @param {Object} rule current elm rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
async function testElmRule(browser, target, rule, expected) {
|
||||
let { id, parent, acc } = target;
|
||||
let { isSibling, elm } = rule;
|
||||
let { id, acc } = target;
|
||||
let { elm } = rule;
|
||||
|
||||
testName(acc, expected);
|
||||
let [event] = await contentSpawnMutation(
|
||||
browser,
|
||||
{
|
||||
expected: [[EVENT_REORDER, isSibling ? parent : id]],
|
||||
},
|
||||
contentElm => content.document.querySelector(`${contentElm}`).remove(),
|
||||
[elm]
|
||||
);
|
||||
let nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
|
||||
|
||||
await invokeContentTask(browser, [elm], contentElm => {
|
||||
content.document.querySelector(`${contentElm}`).remove();
|
||||
});
|
||||
let event = await nameChange;
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
|
@ -462,8 +434,8 @@ async function testElmRule(browser, target, rule, expected) {
|
|||
* accessible becomes defunct, update its reference using the one that is
|
||||
* attached to a reorder event.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* @param {Object} target { acc, id } structure that contains an
|
||||
* accessible and its content element
|
||||
* id.
|
||||
* @param {Object} rule current subtree rule for name calculation
|
||||
* @param {[type]} expected expected name value
|
||||
|
@ -472,19 +444,15 @@ async function testSubtreeRule(browser, target, rule, expected) {
|
|||
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 nameChange = waitForEvent(EVENT_NAME_CHANGE, id);
|
||||
|
||||
await invokeContentTask(browser, [id], contentId => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
while (elm.firstChild) {
|
||||
elm.firstChild.remove();
|
||||
}
|
||||
});
|
||||
let event = await nameChange;
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
|
@ -494,8 +462,8 @@ async function testSubtreeRule(browser, target, rule, expected) {
|
|||
* Iterate over a list of rules and test accessible names for each one of the
|
||||
* rules.
|
||||
* @param {Object} browser current "tabbrowser" element
|
||||
* @param {Object} target { acc, parent, id } structure that contains an
|
||||
* accessible, its parent and its content element
|
||||
* @param {Object} target { acc, id } structure that contains an
|
||||
* accessible and its content element
|
||||
* id.
|
||||
* @param {Array} ruleset A list of rules to test a target with
|
||||
* @param {Array} expected A list of expected name value for each rule
|
||||
|
@ -528,9 +496,7 @@ markupTests.forEach(({ id, ruleset, markup, expected }) =>
|
|||
Services.obs.addObserver(observer, "accessible-event");
|
||||
// Find a target accessible from an accessible subtree.
|
||||
let acc = findAccessibleChildByID(accDoc, id);
|
||||
// Find target's parent accessible from an accessible subtree.
|
||||
let parent = getAccessibleDOMNodeID(acc.parent);
|
||||
let target = { id, parent, acc };
|
||||
let target = { id, acc };
|
||||
await testNameRule(browser, target, rules[ruleset], expected);
|
||||
Services.obs.removeObserver(observer, "accessible-event");
|
||||
},
|
||||
|
|
|
@ -59,8 +59,9 @@
|
|||
gQueue.push(new setAttr("tst1", "title", "title",
|
||||
new unexpectedInvokerChecker(EVENT_DESCRIPTION_CHANGE, "tst1")));
|
||||
|
||||
// A title has lower priority over text content. There should be no name change event.
|
||||
gQueue.push(new setAttr("tst2", "title", "title",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
|
||||
gQueue.invoke();
|
||||
await queueFinished;
|
||||
|
|
|
@ -74,12 +74,12 @@
|
|||
|
||||
gQueue.push(new setAttr("tst1", "aria-label", "hi",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
gQueue.push(new setAttr("tst1", "aria-labelledby", "display",
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
gQueue.push(new setAttr("tst1", "alt", "alt",
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
gQueue.push(new setAttr("tst1", "title", "title",
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
gQueue.push(new setAttr("tst1", "aria-labelledby", "display",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst1")));
|
||||
|
||||
gQueue.push(new setAttr("tst2", "aria-labelledby", "display",
|
||||
new invokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
|
@ -87,6 +87,8 @@
|
|||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
gQueue.push(new setAttr("tst2", "title", "title",
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
gQueue.push(new setAttr("tst2", "aria-label", "hi",
|
||||
new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
|
||||
|
||||
// When `alt` attribute is added or removed from a broken img,
|
||||
// the accessible is recreated.
|
||||
|
|
|
@ -259,32 +259,14 @@ function testNameForAttrRule(aElm, aRule) {
|
|||
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
|
||||
);
|
||||
aElm.removeAttribute(attr);
|
||||
} else if (aRule.hasAttribute("textchanged")) {
|
||||
waitForEvent(
|
||||
EVENT_TEXT_INSERTED,
|
||||
aElm,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
aElm.removeAttribute(attr);
|
||||
} else if (aRule.hasAttribute("contentchanged")) {
|
||||
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
|
||||
aElm.removeAttribute(attr);
|
||||
} else {
|
||||
aElm.removeAttribute(attr);
|
||||
gTestIterator.iterateNext();
|
||||
}
|
||||
waitForEvent(
|
||||
EVENT_NAME_CHANGE,
|
||||
aElm,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
|
||||
aElm.removeAttribute(attr);
|
||||
}
|
||||
|
||||
function testNameForElmRule(aElm, aRule) {
|
||||
|
@ -338,14 +320,14 @@ function testNameForElmRule(aElm, aRule) {
|
|||
|
||||
if (gDumpToConsole) {
|
||||
dump(
|
||||
"\nProcessed elm rule. Wait for reorder event on " +
|
||||
prettyName(parentNode) +
|
||||
"\nProcessed elm rule. Wait for name change event on " +
|
||||
prettyName(aElm) +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(
|
||||
EVENT_REORDER,
|
||||
parentNode,
|
||||
EVENT_NAME_CHANGE,
|
||||
aElm,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
|
@ -365,7 +347,12 @@ function testNameForSubtreeRule(aElm, aRule) {
|
|||
"\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
|
||||
waitForEvent(
|
||||
EVENT_NAME_CHANGE,
|
||||
aElm,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
|
||||
while (aElm.firstChild) {
|
||||
aElm.firstChild.remove();
|
||||
|
|
|
@ -124,25 +124,25 @@
|
|||
|
||||
<ruleset id="HTMLInputSubmit" defaultName="Submit Query">
|
||||
<ruleset ref="HTMLControl:Head"/>
|
||||
<rule attr="value" type="string" explict-name="false" textchanged="true"/>
|
||||
<rule attr="value" type="string" explict-name="false"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLInputReset" defaultName="Reset">
|
||||
<ruleset ref="HTMLControl:Head"/>
|
||||
<rule attr="value" type="string" explict-name="false" textchanged="true"/>
|
||||
<rule attr="value" type="string" explict-name="false"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLInputImage">
|
||||
<ruleset ref="HTMLControl:Head"/>
|
||||
<rule attr="alt" type="string" textchanged="true"/>
|
||||
<rule attr="value" type="string" textchanged="true"/>
|
||||
<rule attr="alt" type="string"/>
|
||||
<rule attr="value" type="string"/>
|
||||
<rule attr="title" type="string"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLInputImageNoValidSrc" defaultName="Submit Query">
|
||||
<ruleset ref="HTMLControl:Head"/>
|
||||
<rule attr="alt" type="string" explict-name="false" textchanged="true"/>
|
||||
<rule attr="value" type="string" explict-name="false" textchanged="true"/>
|
||||
<rule attr="alt" type="string" explict-name="false"/>
|
||||
<rule attr="value" type="string" explict-name="false"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLOption">
|
||||
|
@ -154,14 +154,14 @@
|
|||
|
||||
<ruleset id="HTMLImg">
|
||||
<ruleset ref="ARIA"/>
|
||||
<rule attr="alt" type="string" recreated="true"/>
|
||||
<rule attr="alt" type="string"/>
|
||||
<rule attr="title" type="string"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLImgEmptyAlt">
|
||||
<ruleset ref="ARIA"/>
|
||||
<rule attr="title" type="string"/>
|
||||
<rule attr="alt" type="string" recreated="true"/>
|
||||
<rule attr="alt" type="string"/>
|
||||
</ruleset>
|
||||
|
||||
<ruleset id="HTMLTable">
|
||||
|
|
Загрузка…
Ссылка в новой задаче