Skip to content

Commit

Permalink
chore(target-size): consider fixed and non-fixed position nodes separ…
Browse files Browse the repository at this point in the history
…ately (#3715)

* chore(target-size): Avoid testing nested widgets

* Include descendants in the tab order

* Exclude nested widgets with tabindex="-1"

* improve tests

* chore(target-size): report non-tabbable widgets for review

* Handle integration test

* Update based on feedback

* chore(target-size): consider fixed and non-fixed position nodes separately
  • Loading branch information
WilcoFiers authored Oct 13, 2022
1 parent 13ac4c3 commit 73cbc0f
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 23 deletions.
20 changes: 19 additions & 1 deletion lib/commons/dom/find-nearby-elms.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import createGrid from './create-grid';
import { memoize } from '../../core/utils';

export default function findNearbyElms(vNode, margin = 0) {
/*eslint no-bitwise: 0*/
const gridSize = createGrid();
const selfIsFixed = hasFixedPosition(vNode);
if (!vNode._grid?.cells?.length) {
return []; // Elements not in the grid don't have ._grid
}
Expand All @@ -18,10 +20,16 @@ export default function findNearbyElms(vNode, margin = 0) {

const neighbors = [];
loopGridCells(gridCells, boundaries, vNeighbor => {
if (vNeighbor && vNeighbor !== vNode && !neighbors.includes(vNeighbor)) {
if (
vNeighbor &&
vNeighbor !== vNode &&
!neighbors.includes(vNeighbor) &&
selfIsFixed === hasFixedPosition(vNeighbor)
) {
neighbors.push(vNeighbor);
}
});

return neighbors;
}

Expand All @@ -37,3 +45,13 @@ function loopGridCells(gridCells, boundaries, cb) {
}
}
}

const hasFixedPosition = memoize(vNode => {
if (!vNode) {
return false;
}
if (vNode.getComputedStylePropertyValue('position') === 'fixed') {
return true;
}
return hasFixedPosition(vNode.parent);
});
64 changes: 44 additions & 20 deletions test/commons/dom/find-nearby-elms.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
describe('findNearbyElms', function () {
'use strict';
var fixtureSetup = axe.testUtils.fixtureSetup;
var findNearbyElms = axe.commons.dom.findNearbyElms;
var fixture;
describe('findNearbyElms', () => {
let fixture;
const fixtureSetup = axe.testUtils.fixtureSetup;
const findNearbyElms = axe.commons.dom.findNearbyElms;

function getIds(vNodeList) {
var ids = [];
const ids = [];
vNodeList.forEach(function (vNode) {
if (vNode.props.id && vNode.props.id !== 'fixture') {
ids.push(vNode.props.id);
Expand All @@ -14,8 +13,8 @@ describe('findNearbyElms', function () {
return ids;
}

describe('in the viewport', function () {
beforeEach(function () {
describe('in the viewport', () => {
beforeEach(() => {
fixture = fixtureSetup(
'<div id="n0" style="height:30px; margin-bottom:30px;">0</div>' +
'<div id="n1" style="height:30px; margin-bottom:30px;">1</div>' +
Expand All @@ -30,39 +29,64 @@ describe('findNearbyElms', function () {
);
});

it('returns node from the same grid cell', function () {
var nearbyElms = findNearbyElms(fixture.children[1]);
it('returns node from the same grid cell', () => {
const nearbyElms = findNearbyElms(fixture.children[1]);
assert.deepEqual(getIds(nearbyElms), ['n0', 'n2', 'n3']);
});

it('returns node from multiple grid cells when crossing a boundary', function () {
var nearbyElms = findNearbyElms(fixture.children[5]);
it('returns node from multiple grid cells when crossing a boundary', () => {
const nearbyElms = findNearbyElms(fixture.children[5]);
assert.deepEqual(getIds(nearbyElms), ['n3', 'n4', 'n6']);
});
});

describe('on the edge', function () {
beforeEach(function () {
describe('on the edge', () => {
beforeEach(() => {
fixture = fixtureSetup(
'<div id="n0" style="position: fixed; top:-30px; height: 60px">0</div>' +
'<div id="n1" style="position: fixed; top:-30px; height: 30px">1</div>' +
'<div id="n2" style="position: fixed; top:0; height: 30px">2</div>'
);
});

it('ignores cells outside the document boundary', function () {
var nearbyElms = findNearbyElms(fixture.children[0]);
it('ignores cells outside the document boundary', () => {
const nearbyElms = findNearbyElms(fixture.children[0]);
assert.deepEqual(getIds(nearbyElms), ['n2']);
});

it('returns no neighbors for off-screen elements', function () {
var nearbyElms = findNearbyElms(fixture.children[1]);
it('returns no neighbors for off-screen elements', () => {
const nearbyElms = findNearbyElms(fixture.children[1]);
assert.deepEqual(getIds(nearbyElms), []);
});

it('returns element partially on screen as neighbors', function () {
var nearbyElms = findNearbyElms(fixture.children[2]);
it('returns element partially on screen as neighbors', () => {
const nearbyElms = findNearbyElms(fixture.children[2]);
assert.deepEqual(getIds(nearbyElms), ['n0']);
});
});

describe('when some nodes are fixed', () => {
beforeEach(() => {
fixture = fixtureSetup(
'<div style=" position: fixed;" id="n0">' +
' <div id="n1" style="height:30px;">1</div>' +
' <div id="n2" style="height:30px;">2</div>' +
'</div>' +
'<div id="n3" style="height:30px;">3</div>' +
'<div id="n4" style="height:30px;">4</div>'
);
});

it('skips fixed position neighbors when not fixed', () => {
const n3 = axe.utils.querySelectorAll(fixture, '#n3')[0];
const nearbyElms = findNearbyElms(n3);
assert.deepEqual(getIds(nearbyElms), ['n4']);
});

it('includes only fixed position neighbors when fixed', () => {
const n1 = axe.utils.querySelectorAll(fixture, '#n1')[0];
const nearbyElms = findNearbyElms(n1);
assert.deepEqual(getIds(nearbyElms), ['n0', 'n2']);
});
});
});
7 changes: 7 additions & 0 deletions test/integration/rules/target-size/target-size.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
}
</style>

<!-- These fall on top of the elements immediately below it
this should not effect their outcome -->
<p style="position: fixed">
<a href="#" id="pass-fixed">Wide link</a>
<a href="#" id="fail-fixed">x</a>
</p>

<p>
<button id="pass1" style="display: inline-block; margin-right: 20px">
x
Expand Down
6 changes: 4 additions & 2 deletions test/integration/rules/target-size/target-size.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
["#fail4"],
["#fail5"],
["#fail6"],
["#fail7"]
["#fail7"],
["#fail-fixed"]
],
"passes": [
["#pass1"],
Expand All @@ -19,7 +20,8 @@
["#pass6"],
["#pass7"],
["#pass8"],
["#pass-adjacent"]
["#pass-adjacent"],
["#pass-fixed"]
],
"incomplete": [
["#incomplete1"],
Expand Down

0 comments on commit 73cbc0f

Please sign in to comment.