From 77daf9e73cb21ad9a834657f16310bcd6d7df1b3 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:36:14 -0600 Subject: [PATCH 1/9] fix(target-size): do not crash for nodes with many overlapping widgets --- lib/checks/mobile/target-offset-evaluate.js | 5 ++ lib/checks/mobile/target-size-evaluate.js | 57 +++++++++++++-------- lib/checks/mobile/target-size.json | 3 +- lib/commons/math/split-rects.js | 7 +++ test/checks/mobile/target-size.js | 30 +++++++++++ test/commons/math/split-rects.js | 9 ++++ 6 files changed, 89 insertions(+), 22 deletions(-) diff --git a/lib/checks/mobile/target-offset-evaluate.js b/lib/checks/mobile/target-offset-evaluate.js index e799cb68f1..de361b1131 100644 --- a/lib/checks/mobile/target-offset-evaluate.js +++ b/lib/checks/mobile/target-offset-evaluate.js @@ -13,6 +13,11 @@ export default function targetOffsetEvaluate(node, options, vNode) { continue; } // the offset code works off radius but we want our messaging to reflect diameter + + // getOffeset can return null now + // pass early if size is 10x (just like target-size) + // handle null as well + const offset = roundToSingleDecimal(getOffset(vNode, vNeighbor, minOffset / 2)) * 2; if (offset + roundingMargin >= minOffset) { diff --git a/lib/checks/mobile/target-size-evaluate.js b/lib/checks/mobile/target-size-evaluate.js index a0224c8ad2..c88f4fed14 100644 --- a/lib/checks/mobile/target-size-evaluate.js +++ b/lib/checks/mobile/target-size-evaluate.js @@ -10,7 +10,7 @@ import { * Determine if an element has a minimum size, taking into account * any elements that may obscure it. */ -export default function targetSize(node, options, vNode) { +export default function targetSizeEvaluate(node, options, vNode) { const minSize = options?.minSize || 24; const nodeRect = vNode.boundingClientRect; const hasMinimumSize = rectHasMinimumSize.bind(null, minSize); @@ -20,9 +20,22 @@ export default function targetSize(node, options, vNode) { vNode, nearbyElms ); + const hasOverflowingContent = () => { + this.data({ minSize, messageKey: 'contentOverflow' }); + this.relatedNodes(mapActualNodes(overflowingContent)); + return undefined; + }; + + // If the target has sufficient space it should pass instead of incomplete + if ( + overflowingContent.length && + (fullyObscuringElms.length || !hasMinimumSize(nodeRect)) + ) { + return hasOverflowingContent(); + } // Target is fully obscured and no overflowing content (which may not be obscured) - if (fullyObscuringElms.length && !overflowingContent.length) { + if (fullyObscuringElms.length) { this.relatedNodes(mapActualNodes(fullyObscuringElms)); this.data({ messageKey: 'obscured' }); return true; @@ -32,31 +45,32 @@ export default function targetSize(node, options, vNode) { const negativeOutcome = isInTabOrder(vNode) ? false : undefined; // Target is too small, and has no overflowing content that increases the size - if (!hasMinimumSize(nodeRect) && !overflowingContent.length) { + if (!hasMinimumSize(nodeRect)) { this.data({ minSize, ...toDecimalSize(nodeRect) }); return negativeOutcome; } // Figure out the largest space on the target, not obscured by other widgets const obscuredWidgets = filterFocusableWidgets(partialObscuringElms); - const largestInnerRect = getLargestUnobscuredArea(vNode, obscuredWidgets); - // Target has overflowing content; - // and is either not fully obscured (so may not pass), - // or has insufficient space (and so may not fail) - if (overflowingContent.length) { - if ( - fullyObscuringElms.length || - !hasMinimumSize(largestInnerRect || nodeRect) - ) { - this.data({ minSize, messageKey: 'contentOverflow' }); - this.relatedNodes(mapActualNodes(overflowingContent)); - return undefined; - } + // Target not obscured and has sufficient space + if (!obscuredWidgets.length) { + this.data({ minSize, ...toDecimalSize(nodeRect) }); + return true; + } + + const largestInnerRect = getLargestUnobscuredArea(vNode, obscuredWidgets); + if (!largestInnerRect) { + this.data({ minSize, messageKey: 'tooManyRects' }); + return undefined; } // Target is obscured, and insufficient space is left - if (obscuredWidgets.length !== 0 && !hasMinimumSize(largestInnerRect)) { + if (!hasMinimumSize(largestInnerRect)) { + if (overflowingContent.length) { + return hasOverflowingContent(); + } + const allTabbable = obscuredWidgets.every(isInTabOrder); const messageKey = `partiallyObscured${allTabbable ? '' : 'NonTabbable'}`; @@ -65,7 +79,7 @@ export default function targetSize(node, options, vNode) { return allTabbable ? negativeOutcome : undefined; } - // Target not obscured, or has sufficient space + // Target has sufficient space this.data({ minSize, ...toDecimalSize(largestInnerRect || nodeRect) }); this.relatedNodes(mapActualNodes(obscuredWidgets)); return true; @@ -106,13 +120,14 @@ function filterByElmsOverlap(vNode, nearbyElms) { // Find areas of the target that are not obscured function getLargestUnobscuredArea(vNode, obscuredNodes) { const nodeRect = vNode.boundingClientRect; - if (obscuredNodes.length === 0) { - return null; - } const obscuringRects = obscuredNodes.map( ({ boundingClientRect: rect }) => rect ); const unobscuredRects = splitRects(nodeRect, obscuringRects); + if (!unobscuredRects.length) { + return null; + } + // Of the unobscured inner rects, work out the largest return getLargestRect(unobscuredRects); } diff --git a/lib/checks/mobile/target-size.json b/lib/checks/mobile/target-size.json index 0fff548a65..5490d54479 100644 --- a/lib/checks/mobile/target-size.json +++ b/lib/checks/mobile/target-size.json @@ -19,7 +19,8 @@ "default": "Element with negative tabindex has insufficient size (${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", "contentOverflow": "Element size could not be accurately determined due to overflow content", "partiallyObscured": "Element with negative tabindex has insufficient size because it is partially obscured (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", - "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?" + "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?", + "tooManyRects": "Could not calculate calculate largest obscured rectangle as there are too many overlapping widgets" } } } diff --git a/lib/commons/math/split-rects.js b/lib/commons/math/split-rects.js index c7d45bafda..ca4ef232a6 100644 --- a/lib/commons/math/split-rects.js +++ b/lib/commons/math/split-rects.js @@ -13,6 +13,13 @@ export default function splitRects(outerRect, overlapRects) { uniqueRects = uniqueRects.reduce((rects, inputRect) => { return rects.concat(splitRect(inputRect, overlapRect)); }, []); + + // exit early if we get too many rects that it starts causing + // a performance bottleneck + // @see https://github.com/dequelabs/axe-core/issues/4359 + if (uniqueRects.length > 4000) { + return []; + } } return uniqueRects; } diff --git a/test/checks/mobile/target-size.js b/test/checks/mobile/target-size.js index f01a05841b..6d34482246 100644 --- a/test/checks/mobile/target-size.js +++ b/test/checks/mobile/target-size.js @@ -167,6 +167,36 @@ describe('target-size tests', function () { assert.deepEqual(elmIds(checkContext._relatedNodes), ['#obscurer']); }); + it('returns undefined if there are too many focusable widgets', () => { + let html = ''; + for (let i = 0; i < 100; i++) { + html += ` + + Hello + Hello + Hello + Hello + Hello + Hello + Hello + + + + + `; + } + const checkArgs = checkSetup(` +
+ ${html}
+
+ `); + assert.isUndefined(check.evaluate.apply(checkContext, checkArgs)); + assert.deepEqual(checkContext._data, { + messageKey: 'tooManyRects', + minSize: 24 + }); + }); + describe('for obscured targets with insufficient space', () => { it('returns false if all elements are tabbable', function () { var checkArgs = checkSetup( diff --git a/test/commons/math/split-rects.js b/test/commons/math/split-rects.js index 0680b44822..9463a7fbde 100644 --- a/test/commons/math/split-rects.js +++ b/test/commons/math/split-rects.js @@ -16,6 +16,15 @@ describe('splitRects', () => { assert.deepEqual(rects[0], rectA); }); + it('returns empty array if there are too many overlapping rects', () => { + const rects = []; + for (let i = 0; i < 100; i++) { + rects.push(new DOMRect(i, i, 50, 50)); + } + const rectA = new DOMRect(0, 0, 1000, 1000); + assert.lengthOf(splitRects(rectA, rects), 0); + }); + describe('with one overlapping rect', () => { it('returns one rect if overlaps covers two corners', () => { const rectA = new DOMRect(0, 0, 100, 50); From 4f98389bd3163d9eeec8aec373a3e144c59d4439 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:45:24 -0600 Subject: [PATCH 2/9] remove comments, add test, add _template --- lib/checks/mobile/target-offset-evaluate.js | 5 ---- locales/_template.json | 3 ++- test/checks/mobile/target-offset.js | 30 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/checks/mobile/target-offset-evaluate.js b/lib/checks/mobile/target-offset-evaluate.js index de361b1131..af7767fff1 100644 --- a/lib/checks/mobile/target-offset-evaluate.js +++ b/lib/checks/mobile/target-offset-evaluate.js @@ -12,11 +12,6 @@ export default function targetOffsetEvaluate(node, options, vNode) { if (getRoleType(vNeighbor) !== 'widget' || !isFocusable(vNeighbor)) { continue; } - // the offset code works off radius but we want our messaging to reflect diameter - - // getOffeset can return null now - // pass early if size is 10x (just like target-size) - // handle null as well const offset = roundToSingleDecimal(getOffset(vNode, vNeighbor, minOffset / 2)) * 2; diff --git a/locales/_template.json b/locales/_template.json index 1ce6e1c658..3a3e498f55 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -885,7 +885,8 @@ "default": "Element with negative tabindex has insufficient size (${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", "contentOverflow": "Element size could not be accurately determined due to overflow content", "partiallyObscured": "Element with negative tabindex has insufficient size because it is partially obscured (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", - "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?" + "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?", + "tooManyRects": "Could not calculate calculate largest obscured rectangle as there are too many overlapping widgets" } }, "header-present": { diff --git a/test/checks/mobile/target-offset.js b/test/checks/mobile/target-offset.js index f160baa10f..47ff219834 100644 --- a/test/checks/mobile/target-offset.js +++ b/test/checks/mobile/target-offset.js @@ -120,6 +120,36 @@ describe('target-offset tests', () => { assert.deepEqual(relatedIds, ['#left', '#right']); }); + it('returns false if there are too many focusable widgets', () => { + let html = ''; + for (let i = 0; i < 100; i++) { + html += ` + + Hello + Hello + Hello + Hello + Hello + Hello + Hello + + + + + `; + } + const checkArgs = checkSetup(` +
+ ${html}
+
+ `); + assert.isFalse(checkEvaluate.apply(checkContext, checkArgs)); + assert.deepEqual(checkContext._data, { + closestOffset: 0, + minOffset: 24 + }); + }); + describe('when neighbors are focusable but not tabbable', () => { it('returns undefined if all neighbors are not tabbable', () => { const checkArgs = checkSetup( From c9377ab15815ae9e974ebbf392f6e46f6b9ffb77 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:02:12 -0600 Subject: [PATCH 3/9] put back comment --- lib/checks/mobile/target-offset-evaluate.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/checks/mobile/target-offset-evaluate.js b/lib/checks/mobile/target-offset-evaluate.js index af7767fff1..6b17670c67 100644 --- a/lib/checks/mobile/target-offset-evaluate.js +++ b/lib/checks/mobile/target-offset-evaluate.js @@ -13,6 +13,7 @@ export default function targetOffsetEvaluate(node, options, vNode) { continue; } + // the offset code works off radius but we want our messaging to reflect diameter const offset = roundToSingleDecimal(getOffset(vNode, vNeighbor, minOffset / 2)) * 2; if (offset + roundingMargin >= minOffset) { From 1d4f5190455576f0e112be7a6f4593fa14ed7471 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:02:48 -0600 Subject: [PATCH 4/9] reset --- lib/checks/mobile/target-offset-evaluate.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/checks/mobile/target-offset-evaluate.js b/lib/checks/mobile/target-offset-evaluate.js index 6b17670c67..e799cb68f1 100644 --- a/lib/checks/mobile/target-offset-evaluate.js +++ b/lib/checks/mobile/target-offset-evaluate.js @@ -12,7 +12,6 @@ export default function targetOffsetEvaluate(node, options, vNode) { if (getRoleType(vNeighbor) !== 'widget' || !isFocusable(vNeighbor)) { continue; } - // the offset code works off radius but we want our messaging to reflect diameter const offset = roundToSingleDecimal(getOffset(vNode, vNeighbor, minOffset / 2)) * 2; From fbb6acd16cfd204f835a644fdf60608a42036d8c Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:03:58 -0600 Subject: [PATCH 5/9] comment --- lib/checks/mobile/target-size-evaluate.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/checks/mobile/target-size-evaluate.js b/lib/checks/mobile/target-size-evaluate.js index c88f4fed14..3b69a77369 100644 --- a/lib/checks/mobile/target-size-evaluate.js +++ b/lib/checks/mobile/target-size-evaluate.js @@ -26,7 +26,9 @@ export default function targetSizeEvaluate(node, options, vNode) { return undefined; }; - // If the target has sufficient space it should pass instead of incomplete + // Target has overflowing content; + // and is either not fully obscured (so may not pass), + // or has insufficient space (and so may not fail) if ( overflowingContent.length && (fullyObscuringElms.length || !hasMinimumSize(nodeRect)) From 9c770776aaf7f1bf89791274b70fc3b573d1cfcc Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 18 Mar 2024 08:40:45 -0600 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Wilco Fiers --- lib/checks/mobile/target-size-evaluate.js | 2 +- lib/checks/mobile/target-size.json | 2 +- locales/_template.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/checks/mobile/target-size-evaluate.js b/lib/checks/mobile/target-size-evaluate.js index 3b69a77369..79f7082f95 100644 --- a/lib/checks/mobile/target-size-evaluate.js +++ b/lib/checks/mobile/target-size-evaluate.js @@ -126,7 +126,7 @@ function getLargestUnobscuredArea(vNode, obscuredNodes) { ({ boundingClientRect: rect }) => rect ); const unobscuredRects = splitRects(nodeRect, obscuringRects); - if (!unobscuredRects.length) { + if (unobscuredRects.length === 0) { return null; } diff --git a/lib/checks/mobile/target-size.json b/lib/checks/mobile/target-size.json index 5490d54479..649d075ae8 100644 --- a/lib/checks/mobile/target-size.json +++ b/lib/checks/mobile/target-size.json @@ -20,7 +20,7 @@ "contentOverflow": "Element size could not be accurately determined due to overflow content", "partiallyObscured": "Element with negative tabindex has insufficient size because it is partially obscured (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?", - "tooManyRects": "Could not calculate calculate largest obscured rectangle as there are too many overlapping widgets" + "tooManyRects": "Could not get the target size because there are too many overlapping elements" } } } diff --git a/locales/_template.json b/locales/_template.json index 3a3e498f55..3a55869ed4 100644 --- a/locales/_template.json +++ b/locales/_template.json @@ -886,7 +886,7 @@ "contentOverflow": "Element size could not be accurately determined due to overflow content", "partiallyObscured": "Element with negative tabindex has insufficient size because it is partially obscured (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is this a target?", "partiallyObscuredNonTabbable": "Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is ${data.width}px by ${data.height}px, should be at least ${data.minSize}px by ${data.minSize}px). Is the neighbor a target?", - "tooManyRects": "Could not calculate calculate largest obscured rectangle as there are too many overlapping widgets" + "tooManyRects": "Could not get the target size because there are too many overlapping elements" } }, "header-present": { From a6eab332ea07e7a2d1e91ec6aa45aa0d22660b4c Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 18 Mar 2024 09:07:13 -0600 Subject: [PATCH 7/9] intergration test --- .../full/target-size/target-size.html | 26 +++++++++ .../full/target-size/target-size.js | 54 ++++++++++++------- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/test/integration/full/target-size/target-size.html b/test/integration/full/target-size/target-size.html index a393199c05..e59c707e4f 100644 --- a/test/integration/full/target-size/target-size.html +++ b/test/integration/full/target-size/target-size.html @@ -651,6 +651,32 @@ +
+
+
+
+ +
+ diff --git a/test/integration/full/target-size/target-size.js b/test/integration/full/target-size/target-size.js index 68287e6a8b..2364afc93e 100644 --- a/test/integration/full/target-size/target-size.js +++ b/test/integration/full/target-size/target-size.js @@ -1,20 +1,25 @@ -describe('target-size test', function () { +describe('target-size test', () => { 'use strict'; - var results; + let results; - before(function (done) { - axe.testUtils.awaitNestedLoad(function () { + before(done => { + axe.testUtils.awaitNestedLoad(() => { // Add necessary markup for axe to recognize these as components: - document.querySelectorAll('section span').forEach(function (link) { + document.querySelectorAll('section span').forEach(link => { link.setAttribute('role', 'link'); link.setAttribute('tabindex', '0'); }); - var options = { + const options = { runOnly: ['target-size'], elementRef: true }; - axe.run('section', options, function (err, r) { + const context = { + include: 'section', + // ignore the incomplete table results + exclude: 'table tr' + }; + axe.run(context, options, (err, r) => { if (err) { done(err); } @@ -22,11 +27,11 @@ describe('target-size test', function () { // Add some highlighting for visually identifying issues. // There are too many test cases to just do this by selector. results.violations[0] && - results.violations[0].nodes.forEach(function (node) { + results.violations[0].nodes.forEach(node => { node.element.className += ' violations'; }); results.passes[0] && - results.passes[0].nodes.forEach(function (node) { + results.passes[0].nodes.forEach(node => { node.element.className += ' passes'; }); console.log(results); @@ -35,25 +40,38 @@ describe('target-size test', function () { }); }); - it('finds all passing nodes', function () { - var passResults = results.passes[0] ? results.passes[0].nodes : []; - var passedElms = document.querySelectorAll( + it('finds all passing nodes', () => { + const passResults = results.passes[0] ? results.passes[0].nodes : []; + const passedElms = document.querySelectorAll( 'section:not([hidden]) div:not([hidden]) .passed' ); - passResults.forEach(function (result) { + passResults.forEach(result => { assert.include(passedElms, result.element); }); assert.lengthOf(passResults, passedElms.length); }); - it('finds all failed nodes', function () { - var failResults = results.violations[0] ? results.violations[0].nodes : []; - var failedElms = document.querySelectorAll( - 'section:not([hidden]) div:not([hidden]) .failed' + it('finds all failed nodes', () => { + const failResults = results.violations[0] + ? results.violations[0].nodes + : []; + const failedElms = document.querySelectorAll( + 'section:not([hidden]) div:not([hidden]) .failed' ); - failResults.forEach(function (result) { + failResults.forEach(result => { assert.include(failedElms, result.element); }); assert.lengthOf(failResults, failedElms.length); }); + + it('incompletes with too many rects', () => { + const incompleteNodes = results.incomplete[0] + ? results.incomplete[0].nodes + : []; + assert.lengthOf(incompleteNodes, 1); + assert.include( + incompleteNodes[0].element, + document.querySelector('#incomplete-many-rects') + ); + }); }); From c0039dda0f9c3ef9b9c8270681f61bcf0c00a973 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 18 Mar 2024 09:09:50 -0600 Subject: [PATCH 8/9] no inner function --- lib/checks/mobile/target-size-evaluate.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/checks/mobile/target-size-evaluate.js b/lib/checks/mobile/target-size-evaluate.js index 79f7082f95..3d692606e3 100644 --- a/lib/checks/mobile/target-size-evaluate.js +++ b/lib/checks/mobile/target-size-evaluate.js @@ -20,11 +20,6 @@ export default function targetSizeEvaluate(node, options, vNode) { vNode, nearbyElms ); - const hasOverflowingContent = () => { - this.data({ minSize, messageKey: 'contentOverflow' }); - this.relatedNodes(mapActualNodes(overflowingContent)); - return undefined; - }; // Target has overflowing content; // and is either not fully obscured (so may not pass), @@ -33,7 +28,9 @@ export default function targetSizeEvaluate(node, options, vNode) { overflowingContent.length && (fullyObscuringElms.length || !hasMinimumSize(nodeRect)) ) { - return hasOverflowingContent(); + this.data({ minSize, messageKey: 'contentOverflow' }); + this.relatedNodes(mapActualNodes(overflowingContent)); + return undefined; } // Target is fully obscured and no overflowing content (which may not be obscured) @@ -70,7 +67,9 @@ export default function targetSizeEvaluate(node, options, vNode) { // Target is obscured, and insufficient space is left if (!hasMinimumSize(largestInnerRect)) { if (overflowingContent.length) { - return hasOverflowingContent(); + this.data({ minSize, messageKey: 'contentOverflow' }); + this.relatedNodes(mapActualNodes(overflowingContent)); + return undefined; } const allTabbable = obscuredWidgets.every(isInTabOrder); From ad43fc5cb432816a68bddd1c9a82141c063afa22 Mon Sep 17 00:00:00 2001 From: Steven Lambert <2433219+straker@users.noreply.github.com> Date: Mon, 18 Mar 2024 12:20:14 -0600 Subject: [PATCH 9/9] move to own file --- .../full/target-size/target-size.html | 26 --------- .../full/target-size/target-size.js | 54 +++++++------------ .../full/target-size/too-many-rects.html | 53 ++++++++++++++++++ .../full/target-size/too-many-rects.js | 36 +++++++++++++ 4 files changed, 107 insertions(+), 62 deletions(-) create mode 100644 test/integration/full/target-size/too-many-rects.html create mode 100644 test/integration/full/target-size/too-many-rects.js diff --git a/test/integration/full/target-size/target-size.html b/test/integration/full/target-size/target-size.html index e59c707e4f..a393199c05 100644 --- a/test/integration/full/target-size/target-size.html +++ b/test/integration/full/target-size/target-size.html @@ -651,32 +651,6 @@ -
-
-
-
- -
- diff --git a/test/integration/full/target-size/target-size.js b/test/integration/full/target-size/target-size.js index 2364afc93e..68287e6a8b 100644 --- a/test/integration/full/target-size/target-size.js +++ b/test/integration/full/target-size/target-size.js @@ -1,25 +1,20 @@ -describe('target-size test', () => { +describe('target-size test', function () { 'use strict'; - let results; + var results; - before(done => { - axe.testUtils.awaitNestedLoad(() => { + before(function (done) { + axe.testUtils.awaitNestedLoad(function () { // Add necessary markup for axe to recognize these as components: - document.querySelectorAll('section span').forEach(link => { + document.querySelectorAll('section span').forEach(function (link) { link.setAttribute('role', 'link'); link.setAttribute('tabindex', '0'); }); - const options = { + var options = { runOnly: ['target-size'], elementRef: true }; - const context = { - include: 'section', - // ignore the incomplete table results - exclude: 'table tr' - }; - axe.run(context, options, (err, r) => { + axe.run('section', options, function (err, r) { if (err) { done(err); } @@ -27,11 +22,11 @@ describe('target-size test', () => { // Add some highlighting for visually identifying issues. // There are too many test cases to just do this by selector. results.violations[0] && - results.violations[0].nodes.forEach(node => { + results.violations[0].nodes.forEach(function (node) { node.element.className += ' violations'; }); results.passes[0] && - results.passes[0].nodes.forEach(node => { + results.passes[0].nodes.forEach(function (node) { node.element.className += ' passes'; }); console.log(results); @@ -40,38 +35,25 @@ describe('target-size test', () => { }); }); - it('finds all passing nodes', () => { - const passResults = results.passes[0] ? results.passes[0].nodes : []; - const passedElms = document.querySelectorAll( + it('finds all passing nodes', function () { + var passResults = results.passes[0] ? results.passes[0].nodes : []; + var passedElms = document.querySelectorAll( 'section:not([hidden]) div:not([hidden]) .passed' ); - passResults.forEach(result => { + passResults.forEach(function (result) { assert.include(passedElms, result.element); }); assert.lengthOf(passResults, passedElms.length); }); - it('finds all failed nodes', () => { - const failResults = results.violations[0] - ? results.violations[0].nodes - : []; - const failedElms = document.querySelectorAll( - 'section:not([hidden]) div:not([hidden]) .failed' + it('finds all failed nodes', function () { + var failResults = results.violations[0] ? results.violations[0].nodes : []; + var failedElms = document.querySelectorAll( + 'section:not([hidden]) div:not([hidden]) .failed' ); - failResults.forEach(result => { + failResults.forEach(function (result) { assert.include(failedElms, result.element); }); assert.lengthOf(failResults, failedElms.length); }); - - it('incompletes with too many rects', () => { - const incompleteNodes = results.incomplete[0] - ? results.incomplete[0].nodes - : []; - assert.lengthOf(incompleteNodes, 1); - assert.include( - incompleteNodes[0].element, - document.querySelector('#incomplete-many-rects') - ); - }); }); diff --git a/test/integration/full/target-size/too-many-rects.html b/test/integration/full/target-size/too-many-rects.html new file mode 100644 index 0000000000..4ce85fd174 --- /dev/null +++ b/test/integration/full/target-size/too-many-rects.html @@ -0,0 +1,53 @@ + + + + Target-size too many rects Test + + + + + + + +
+ +
+
+
+
+
+ + + + + + + diff --git a/test/integration/full/target-size/too-many-rects.js b/test/integration/full/target-size/too-many-rects.js new file mode 100644 index 0000000000..d1364b0d32 --- /dev/null +++ b/test/integration/full/target-size/too-many-rects.js @@ -0,0 +1,36 @@ +describe('target-size too many rects test', () => { + 'use strict'; + let results; + + before(done => { + axe.testUtils.awaitNestedLoad(() => { + const options = { + runOnly: ['target-size'], + elementRef: true + }; + const context = { + // ignore the incomplete table results + exclude: 'table tr' + }; + axe.run(context, options, (err, r) => { + if (err) { + done(err); + } + results = r; + console.log(results); + done(); + }); + }); + }); + + it('incompletes with too many rects', () => { + const incompleteNodes = results.incomplete[0] + ? results.incomplete[0].nodes + : []; + assert.lengthOf(incompleteNodes, 1); + assert.include( + incompleteNodes[0].element, + document.querySelector('#incomplete-many-rects') + ); + }); +});