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 += `
+
+ `);
+ 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 += `
+
+ `);
+ 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
+
+
+
+
+
+
+
+
+
+
+