Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(aria-required-children): avoid confusing aria-busy message in failures #4347

Merged
merged 4 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/checks/aria/aria-busy.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"id": "aria-busy",
"evaluate": "aria-busy-evaluate",
"deprecated": true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecation should probably go into its own PR so it's a separate line in the changelog.

"metadata": {
"impact": "serious",
"messages": {
Expand Down
5 changes: 5 additions & 0 deletions lib/checks/aria/aria-required-children-evaluate.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export default function ariaRequiredChildrenEvaluate(
return true;
}

if (virtualNode.attr('aria-busy') === 'true') {
this.data({ messageKey: 'aria-busy' });
return true;
}

this.data(required);

// Only review empty nodes when a node is both empty and does not have an aria-owns relationship
Expand Down
5 changes: 4 additions & 1 deletion lib/checks/aria/aria-required-children.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
"metadata": {
"impact": "critical",
"messages": {
"pass": "Required ARIA children are present",
"pass": {
"default": "Required ARIA children are present",
"aria-busy": "Element has an aria-busy attribute, so it is allowed to omit required children"
},
"fail": {
"singular": "Required ARIA child role not present: ${data.values}",
"plural": "Required ARIA children role not present: ${data.values}",
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/aria-required-children.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"help": "Certain ARIA roles must contain particular children"
},
"all": [],
"any": ["aria-required-children", "aria-busy"],
"any": ["aria-required-children"],
"none": []
}
5 changes: 4 additions & 1 deletion locales/_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,10 @@
}
},
"aria-required-children": {
"pass": "Required ARIA children are present",
"pass": {
"default": "Required ARIA children are present",
"aria-busy": "Element has an aria-busy attribute, so it is allowed to omit required children"
},
"fail": {
"singular": "Required ARIA child role not present: ${data.values}",
"plural": "Required ARIA children role not present: ${data.values}",
Expand Down
4 changes: 3 additions & 1 deletion locales/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,9 @@
}
},
"aria-required-children": {
"pass": "Krævet ARIA-under-elementer er til stede",
"pass": {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we normally don't update translations with this sort of change, but I thought it made sense to fix the structure here - with these updates, npx grunt translate will preserve the old translations, and without these updates, it'll eat the existing translations and replace them with english.

"default": "Krævet ARIA-under-elementer er til stede"
},
"fail": {
"singular": "Krævet ARIA-under-elementers rolle er ikke til stede: ${data.values}",
"plural": "Krævet ARIA-under-elements rolle er ikke til stede: ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,9 @@
}
},
"aria-required-children": {
"pass": "Alle benötigten ARIA Kinder sind vorhanden.",
"pass": {
"default": "Alle benötigten ARIA Kinder sind vorhanden."
},
"fail": {
"singular": "Benötigte ARIA Kindrolle nicht vorhanden: ${data.values}",
"plural": "Benötigte ARIA Kindrollen nicht vorhanden: ${data.values}",
Expand Down
4 changes: 3 additions & 1 deletion locales/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,9 @@
}
},
"aria-required-children": {
"pass": "Οι απαιτούμενοι γόνοι ARIA είναι παρόντες",
"pass": {
"default": "Οι απαιτούμενοι γόνοι ARIA είναι παρόντες"
},
"fail": {
"singular": "Ο απαιτούμενος θυγατρικός ρόλος ARIA δεν υπάρχει: ${data.values}",
"plural": "Οι απαιτούμενοι θυγατρικόι ρόλοι ARIA δεν υπάρχουν: ${data.values}",
Expand Down
4 changes: 3 additions & 1 deletion locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@
}
},
"aria-required-children": {
"pass": "Los hijos ARIA requeridos están presentes",
"pass": {
"default": "Los hijos ARIA requeridos están presentes"
},
"fail": {
"singular": "Rol de hijos requerido en ARIA no presente: ${data.values}",
"plural": "Rol de hijo requerido en ARIA no presente: ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/eu.json
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@
}
},
"aria-required-children": {
"pass": "Eskatutako ARIA semeak bertan daude",
"pass": {
"default": "Eskatutako ARIA semeak bertan daude"
},
"fail": {
"singular": "Esktatutako ARIARren semeak ez daude : ${data.values}",
"plural": "Esktatutako ARIARren semeaez dago : ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,9 @@
}
},
"aria-required-children": {
"pass": "Les descendants ARIA requis sont présents",
"pass": {
"default": "Les descendants ARIA requis sont présents"
},
"fail": {
"singular": "Le descendant ARIA requis est manquant : ${data.values}",
"plural": "Les descendants ARIA requis sont manquants : ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,9 @@
}
},
"aria-required-children": {
"pass": "ילדי ARIA הדרושים נמצאים",
"pass": {
"default": "ילדי ARIA הדרושים נמצאים"
},
"fail": {
"singular": "תפקיד ילד ARIA הדרוש אינו נמצא: ${data.values}",
"plural": "תפקיד ילדי ARIA הדרושים אינם נמצאים: ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,9 @@
}
},
"aria-required-children": {
"pass": "必須のARIA子ロールが存在します",
"pass": {
"default": "必須のARIA子ロールが存在します"
},
"fail": {
"singular": "必須のARIA子ロールが提供されていません: ${data.values}",
"plural": "必須のARIA子ロールが提供されていません: ${data.values}",
Expand Down
4 changes: 3 additions & 1 deletion locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@
}
},
"aria-required-children": {
"pass": "필수 ARIA 하위 항목들이 존재합니다.",
"pass": {
"default": "필수 ARIA 하위 항목들이 존재합니다."
},
"fail": {
"singular": "필수 ARIA 하위 역할(role)이 없습니다: ${data.values}",
"plural": "필수 ARIA 하위 역할(role)들이 없습니다: ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/no_NB.json
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,9 @@
}
},
"aria-required-children": {
"pass": "Påkrevde ARIA-under-elementer er til stede",
"pass": {
"default": "Påkrevde ARIA-under-elementer er til stede"
},
"fail": {
"singular": "Påkrevd ARIA-under-element sin rolle er ikke til stede: ${data.values}",
"plural": "Påkrevde ARIA-under-elementer sine roller er ikke til stede: ${data.values}"
Expand Down
4 changes: 3 additions & 1 deletion locales/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,9 @@
}
},
"aria-required-children": {
"pass": "Wymagane dzieci ARIA istnieją.",
"pass": {
"default": "Wymagane dzieci ARIA istnieją."
},
"fail": {
"singular": "Wymagana rola dziecka ARIA nie istnieje: ${data.values}.",
"plural": "Wymagane role dzieci ARIA nie istnieją: ${data.values",
Expand Down
4 changes: 3 additions & 1 deletion locales/pt_BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@
}
},
"aria-required-children": {
"pass": "Os ARIA filhos necessários estão presentes",
"pass": {
"default": "Os ARIA filhos necessários estão presentes"
},
"fail": {
"singular": "Função ARIA filha necessária ausente: ${data.values}",
"plural": "Funções ARIA filhas necessárias ausentes: ${data.values}"
Expand Down
55 changes: 55 additions & 0 deletions test/checks/aria/required-children.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,53 @@ describe('aria-required-children', () => {
assert.deepEqual(checkContext._data, ['listitem']);
});

it('should pass when missing required children but aria-busy', () => {
const params = checkSetup(
'<div id="target" role="list" aria-busy="true"><span>Item 1</span></div>'
);
assert.isTrue(requiredChildrenCheck.apply(checkContext, params));

assert.deepEqual(checkContext._data, { messageKey: 'aria-busy' });
});

it('should treat aria-busy="false" as not aria-busy', () => {
const params = checkSetup(
'<div id="target" role="list" aria-busy="false"><span>Item 1</span></div>'
);
assert.isFalse(requiredChildrenCheck.apply(checkContext, params));
});

it('should treat valueless aria-busy as not aria-busy', () => {
const params = checkSetup(
'<div id="target" role="list" aria-busy><span>Item 1</span></div>'
);
assert.isFalse(requiredChildrenCheck.apply(checkContext, params));
});

it('should fail list with an unallowed child', () => {
const params = checkSetup(`
<div id="target" role="list"><div role="tabpanel"></div></div>
`);
assert.isFalse(requiredChildrenCheck.apply(checkContext, params));

assert.deepEqual(checkContext._data, {
messageKey: 'unallowed',
values: '[role=tabpanel]'
});
});

it('should fail list with an unallowed child, even if aria-busy="true"', () => {
const params = checkSetup(`
<div id="target" role="list" aria-busy="true"><div role="tabpanel"></div></div>
`);
assert.isFalse(requiredChildrenCheck.apply(checkContext, params));

assert.deepEqual(checkContext._data, {
messageKey: 'unallowed',
values: '[role=tabpanel]'
});
});

it('should fail when list has intermediate child with role that is not a required role', () => {
const params = checkSetup(
'<div id="target" role="list"><div role="tabpanel"><div role="listitem">List item 1</div></div></div>'
Expand Down Expand Up @@ -378,6 +425,14 @@ describe('aria-required-children', () => {
assert.isUndefined(requiredChildrenCheck.apply(checkContext, params));
});

it('should return true if aria-busy preempts a reviewEmpty case', () => {
const params = checkSetup(
'<div role="grid" id="target" aria-busy="true"></div>',
{ reviewEmpty: ['grid'] }
);
assert.isTrue(requiredChildrenCheck.apply(checkContext, params));
});

it('should return undefined when the element has empty children', () => {
const params = checkSetup(
'<div role="listbox" id="target"><div></div></div>',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@
<div aria-busy="true"></div>
</div>

<div role="list" id="fail13" aria-busy="true">
<div role="alert">unallowed role</div>
</div>

<div role="doc-bibliography" id="inapplicable1"></div>
<div role="doc-endnotes" id="inapplicable2"></div>
<div role="radiogroup" id="inapplicable3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
["#fail9"],
["#fail10"],
["#fail11"],
["#fail12"]
["#fail12"],
["#fail13"]
],
"passes": [
["#pass1"],
Expand Down
Loading