From 3897bde8f54fddbaad4a7abfbd8a1744761669d8 Mon Sep 17 00:00:00 2001 From: Wilco Fiers Date: Fri, 28 Jun 2024 15:26:39 +0200 Subject: [PATCH] Resolve feedback --- lib/rules/summary-interactive-matches.js | 34 ++------ .../rules/summary-name/summary-name.html | 22 ----- .../integration/virtual-rules/summary-name.js | 16 ---- .../summary-interactive-matches.js | 82 ++++--------------- test/testutils.js | 4 +- 5 files changed, 25 insertions(+), 133 deletions(-) diff --git a/lib/rules/summary-interactive-matches.js b/lib/rules/summary-interactive-matches.js index f8a4252238..883dd51e9c 100644 --- a/lib/rules/summary-interactive-matches.js +++ b/lib/rules/summary-interactive-matches.js @@ -1,15 +1,7 @@ -import { hasContentVirtual } from '../commons/dom'; - export default function summaryIsInteractiveMatches(_, virtualNode) { // Summary only interactive if its real DOM parent is a details element const parent = virtualNode.parent; - if ( - parent.props.nodeName !== 'details' || - virtualNode.shadowId !== parent.shadowId - ) { - return false; - } - if (!hasDetailsContent(parent)) { + if (parent.props.nodeName !== 'details' || isSlottedElm(virtualNode)) { return false; } // Only the first summary element is interactive @@ -22,23 +14,9 @@ export default function summaryIsInteractiveMatches(_, virtualNode) { return true; } -function hasDetailsContent(vDetails) { - let summary = false; - for (const vNode of vDetails.children) { - const { nodeType, nodeValue } = vNode.props; - // Skip the first summary elm - if (!summary && vNode.props.nodeName === 'summary') { - summary = true; - continue; - } - // True for elements with content - if (nodeType === 1 && hasContentVirtual(vNode)) { - return true; - } - // True for text nodes - if (nodeType === 3 && nodeValue.trim()) { - return true; - } - } - return false; +function isSlottedElm(vNode) { + // Normally this wouldn't be enough, but since we know parent is a details + // element, we can ignore edge cases like slot being the real parent + const domParent = vNode.actualNode?.parentElement; + return domParent && domParent !== vNode.parent.actualNode; } diff --git a/test/integration/rules/summary-name/summary-name.html b/test/integration/rules/summary-name/summary-name.html index ca5afbe131..1a236dd4a0 100644 --- a/test/integration/rules/summary-name/summary-name.html +++ b/test/integration/rules/summary-name/summary-name.html @@ -79,25 +79,3 @@ Not a valid method for giving a name - - - -
- -
- -
- -
- - - - - -
diff --git a/test/integration/virtual-rules/summary-name.js b/test/integration/virtual-rules/summary-name.js index 8fd74625ff..1c711bd77c 100644 --- a/test/integration/virtual-rules/summary-name.js +++ b/test/integration/virtual-rules/summary-name.js @@ -46,22 +46,6 @@ describe('summary-name virtual-rule', () => { assert.lengthOf(results.incomplete, 0); }); - it('is inapplicable without siblings to summary', () => { - const vSummary = new axe.SerialVirtualNode({ - nodeName: 'summary', - attributes: {} - }); - appendSerialChild(vSummary, { nodeName: '#text', nodeValue: 'text' }); - vSummary.parent = vDetails; - vDetails.children = [vSummary]; - - const results = axe.runVirtualRule('summary-name', vSummary); - assert.lengthOf(results.passes, 0); - assert.lengthOf(results.violations, 0); - assert.lengthOf(results.incomplete, 0); - assert.lengthOf(results.inapplicable, 1); - }); - it('passes with aria-label', () => { const vSummary = new axe.SerialVirtualNode({ nodeName: 'summary', diff --git a/test/rule-matches/summary-interactive-matches.js b/test/rule-matches/summary-interactive-matches.js index 5fbc2b4cd9..f23ce73845 100644 --- a/test/rule-matches/summary-interactive-matches.js +++ b/test/rule-matches/summary-interactive-matches.js @@ -43,15 +43,21 @@ describe('summary-interactive-matches', () => { assert.isFalse(rule.matches(null, vNode)); }); - it('is false for s details parent in a different DOM tree', () => { - const vNode = queryShadowFixture( + it('is false for details parent in a different DOM tree', () => { + const vFixture = queryShadowFixture( html`
-
+ Hello World
`, - html` Hello World ` + html` +
+ + text +
+ ` ); + const vNode = axe.utils.querySelectorAll(vFixture, 'summary')[0]; assert.isFalse(rule.matches(null, vNode)); }); @@ -95,66 +101,12 @@ describe('summary-interactive-matches', () => { assert.isTrue(rule.matches(null, vNode)); }); - describe('details has no content', () => { - it('is false if summary is the only child', () => { - const vNode = queryFixture(html` -
- Summary -
- `); - assert.isFalse(rule.matches(null, vNode)); - }); - - it('is false with a comment sibling', () => { - const vNode = queryFixture(html` -
- Summary - -
- `); - assert.isFalse(rule.matches(null, vNode)); - }); - - it('is false with an empty sibling elm', () => { - const vNode = queryFixture(html` -
- Summary -
-
- `); - assert.isFalse(rule.matches(null, vNode)); - }); - - it('is false with a hidden text element', () => { - const vNode = queryFixture(html` -
- Summary - -
- `); - assert.isFalse(rule.matches(null, vNode)); - }); - - it('is true if the content is a graphic', () => { - const vNode = queryFixture(html` -
- Summary -
-
- `); - assert.isTrue(rule.matches(null, vNode)); - }); - - it('is true if there are is a second summary with content', () => { - const vNode = queryFixture(html` -
- Summary - actual content -
- `); - assert.isTrue(rule.matches(null, vNode)); - }); + it('is true even if summary is the only child', () => { + const vNode = queryFixture(html` +
+ Summary +
+ `); + assert.isTrue(rule.matches(null, vNode)); }); }); diff --git a/test/testutils.js b/test/testutils.js index a9168b10fe..fe4d38fee0 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -236,8 +236,8 @@ var commons; } // query the composed tree AFTER shadowDOM has been attached - axe.setup(fixtureNode); - return axe.utils.getNodeFromTree(targetCandidate); + const vFixture = axe.setup(fixtureNode); + return axe.utils.getNodeFromTree(targetCandidate) || vFixture; }; /**