diff --git a/lib/checks/aria/aria-required-children-evaluate.js b/lib/checks/aria/aria-required-children-evaluate.js index 226bd54703..1e7512d960 100644 --- a/lib/checks/aria/aria-required-children-evaluate.js +++ b/lib/checks/aria/aria-required-children-evaluate.js @@ -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 diff --git a/lib/checks/aria/aria-required-children.json b/lib/checks/aria/aria-required-children.json index db1e2bf630..16c67dbd51 100644 --- a/lib/checks/aria/aria-required-children.json +++ b/lib/checks/aria/aria-required-children.json @@ -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}", diff --git a/lib/rules/aria-required-children.json b/lib/rules/aria-required-children.json index f81242a613..e1b22fb129 100644 --- a/lib/rules/aria-required-children.json +++ b/lib/rules/aria-required-children.json @@ -10,6 +10,6 @@ "help": "Certain ARIA roles must contain particular children" }, "all": [], - "any": ["aria-required-children", "aria-busy"], + "any": ["aria-required-children"], "none": [] } diff --git a/locales/_template.json b/locales/_template.json index 33a69a793b..1ce6e1c658 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -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}", diff --git a/locales/da.json b/locales/da.json index 1b2e74e441..56c9a5ccd7 100644 --- a/locales/da.json +++ b/locales/da.json @@ -385,7 +385,9 @@ } }, "aria-required-children": { - "pass": "Krævet ARIA-under-elementer er til stede", + "pass": { + "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}" diff --git a/locales/de.json b/locales/de.json index 60575103c6..cab4da906e 100644 --- a/locales/de.json +++ b/locales/de.json @@ -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}", diff --git a/locales/el.json b/locales/el.json index b963ccede8..f8f805c424 100644 --- a/locales/el.json +++ b/locales/el.json @@ -473,7 +473,9 @@ } }, "aria-required-children": { - "pass": "Οι απαιτούμενοι γόνοι ARIA είναι παρόντες", + "pass": { + "default": "Οι απαιτούμενοι γόνοι ARIA είναι παρόντες" + }, "fail": { "singular": "Ο απαιτούμενος θυγατρικός ρόλος ARIA δεν υπάρχει: ${data.values}", "plural": "Οι απαιτούμενοι θυγατρικόι ρόλοι ARIA δεν υπάρχουν: ${data.values}", diff --git a/locales/es.json b/locales/es.json index 5605020f93..7a0b5c0b3f 100644 --- a/locales/es.json +++ b/locales/es.json @@ -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}" diff --git a/locales/eu.json b/locales/eu.json index 4767e9e93c..03b534cfc7 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -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}" diff --git a/locales/fr.json b/locales/fr.json index 2cd83e97c4..9bd71725e4 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -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}" diff --git a/locales/he.json b/locales/he.json index d3c5803ec2..fd0d2eaa50 100644 --- a/locales/he.json +++ b/locales/he.json @@ -465,7 +465,9 @@ } }, "aria-required-children": { - "pass": "ילדי ARIA הדרושים נמצאים", + "pass": { + "default": "ילדי ARIA הדרושים נמצאים" + }, "fail": { "singular": "תפקיד ילד ARIA הדרוש אינו נמצא: ${data.values}", "plural": "תפקיד ילדי ARIA הדרושים אינם נמצאים: ${data.values}" diff --git a/locales/ja.json b/locales/ja.json index e84bff43d9..161fdba32e 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -497,7 +497,9 @@ } }, "aria-required-children": { - "pass": "必須のARIA子ロールが存在します", + "pass": { + "default": "必須のARIA子ロールが存在します" + }, "fail": { "singular": "必須のARIA子ロールが提供されていません: ${data.values}", "plural": "必須のARIA子ロールが提供されていません: ${data.values}", diff --git a/locales/ko.json b/locales/ko.json index 267f4766af..9c304d1d7f 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -461,7 +461,9 @@ } }, "aria-required-children": { - "pass": "필수 ARIA 하위 항목들이 존재합니다.", + "pass": { + "default": "필수 ARIA 하위 항목들이 존재합니다." + }, "fail": { "singular": "필수 ARIA 하위 역할(role)이 없습니다: ${data.values}", "plural": "필수 ARIA 하위 역할(role)들이 없습니다: ${data.values}" diff --git a/locales/no_NB.json b/locales/no_NB.json index a1223028aa..4dbf8dbe9d 100644 --- a/locales/no_NB.json +++ b/locales/no_NB.json @@ -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}" diff --git a/locales/pl.json b/locales/pl.json index 72f6dec42a..1caafcabda 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -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", diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 31b6f1dc3f..404d5ab293 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -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}" diff --git a/test/checks/aria/required-children.js b/test/checks/aria/required-children.js index fe5a15ff82..faf68eb714 100644 --- a/test/checks/aria/required-children.js +++ b/test/checks/aria/required-children.js @@ -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( + '
Item 1
' + ); + 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( + '
Item 1
' + ); + assert.isFalse(requiredChildrenCheck.apply(checkContext, params)); + }); + + it('should treat valueless aria-busy as not aria-busy', () => { + const params = checkSetup( + '
Item 1
' + ); + assert.isFalse(requiredChildrenCheck.apply(checkContext, params)); + }); + + it('should fail list with an unallowed child', () => { + const params = checkSetup(` +
+ `); + 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(` +
+ `); + 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( '
List item 1
' @@ -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( + '
', + { reviewEmpty: ['grid'] } + ); + assert.isTrue(requiredChildrenCheck.apply(checkContext, params)); + }); + it('should return undefined when the element has empty children', () => { const params = checkSetup( '
', diff --git a/test/integration/rules/aria-required-children/aria-required-children.html b/test/integration/rules/aria-required-children/aria-required-children.html index def03ca181..af5b16d858 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.html +++ b/test/integration/rules/aria-required-children/aria-required-children.html @@ -114,6 +114,10 @@
+
+
unallowed role
+
+
diff --git a/test/integration/rules/aria-required-children/aria-required-children.json b/test/integration/rules/aria-required-children/aria-required-children.json index 21f2ed2f3a..4b32bb9c7b 100644 --- a/test/integration/rules/aria-required-children/aria-required-children.json +++ b/test/integration/rules/aria-required-children/aria-required-children.json @@ -13,7 +13,8 @@ ["#fail9"], ["#fail10"], ["#fail11"], - ["#fail12"] + ["#fail12"], + ["#fail13"] ], "passes": [ ["#pass1"],