diff --git a/lib/checks/tables/td-has-header.js b/lib/checks/tables/td-has-header.js index cb9c9b70af..83b01179e8 100644 --- a/lib/checks/tables/td-has-header.js +++ b/lib/checks/tables/td-has-header.js @@ -9,10 +9,9 @@ cells.forEach((cell) => { !axe.commons.aria.label(cell) ) { // Check if it has any headers - var hasHeaders = tableUtils.getHeaders(cell); - hasHeaders = hasHeaders.reduce(function (hasHeaders, header) { - return (hasHeaders || header !== null && !!axe.commons.dom.hasContent(header)); - }, false); + const hasHeaders = tableUtils.getHeaders(cell).some(header => { + return header !== null && !!axe.commons.dom.hasContent(header); + }); // If no headers, put it on the naughty list if (!hasHeaders) { diff --git a/lib/commons/table/is-data-cell.js b/lib/commons/table/is-data-cell.js index 0a0b97e3f0..76e12c0c88 100644 --- a/lib/commons/table/is-data-cell.js +++ b/lib/commons/table/is-data-cell.js @@ -13,5 +13,10 @@ table.isDataCell = function (cell) { if (!cell.children.length && !cell.textContent.trim()) { return false; } - return cell.nodeName.toUpperCase() === 'TD'; + const role = cell.getAttribute('role'); + if (axe.commons.aria.isValidRole(role)) { + return ['cell', 'gridcell'].includes(role); + } else { + return cell.nodeName.toUpperCase() === 'TD'; + } }; diff --git a/test/commons/table/is-data-cell.js b/test/commons/table/is-data-cell.js index d800ccc26b..1e52561916 100644 --- a/test/commons/table/is-data-cell.js +++ b/test/commons/table/is-data-cell.js @@ -40,4 +40,42 @@ describe('table.isDataCell', function () { assert.isFalse(axe.commons.table.isDataCell(target)); }); + it('should ignore TDs with a valid role other than (grid)cell', function () { + fixture.innerHTML = '' + + '' + + '' + + '' + + '
heading
heading
'; + + var target1 = $id('target1'); + var target2 = $id('target2'); + var target3 = $id('target3'); + assert.isFalse(axe.commons.table.isDataCell(target1)); + assert.isFalse(axe.commons.table.isDataCell(target2)); + assert.isFalse(axe.commons.table.isDataCell(target3)); + }); + + it('should return true for elements with role="(grid)cell"', function () { + fixture.innerHTML = '' + + '' + + '' + + '
heading
heading
'; + + var target1 = $id('target1'); + var target2 = $id('target2'); + assert.isTrue(axe.commons.table.isDataCell(target1)); + assert.isTrue(axe.commons.table.isDataCell(target2)); + }); + + it('should ignore invalid roles', function () { + fixture.innerHTML = '' + + '' + + '' + + '
heading
heading
'; + + var target1 = $id('target1'); + var target2 = $id('target2'); + assert.isTrue(axe.commons.table.isDataCell(target1)); + assert.isFalse(axe.commons.table.isDataCell(target2)); + }); }); diff --git a/test/integration/rules/td-has-header/td-has-header.html b/test/integration/rules/td-has-header/td-has-header.html index 3d7e7e8fd8..c742f61640 100644 --- a/test/integration/rules/td-has-header/td-has-header.html +++ b/test/integration/rules/td-has-header/td-has-header.html @@ -27,7 +27,6 @@ AXE aXe aXe aXe - @@ -35,6 +34,25 @@
AXE AXE AXE AXE
AXE aXe aXe aXe
AXE aXe aXe aXe
+ + + + + + + + + + +
AXEAXEAXEAXE
aXe aXe aXe aXe
aXe aXe aXe aXe
aXe aXe aXe aXe
+ + + + + + +
AXE aXe aXe aXe
AXE aXe aXe aXe
AXE aXe aXe aXe
AXE aXe aXe aXe
+ diff --git a/test/integration/rules/td-has-header/td-has-header.json b/test/integration/rules/td-has-header/td-has-header.json index ec81742429..3e50ce53cf 100644 --- a/test/integration/rules/td-has-header/td-has-header.json +++ b/test/integration/rules/td-has-header/td-has-header.json @@ -2,5 +2,11 @@ "description": "td-has-header test", "rule": "td-has-header", "violations": [["#fail1"], ["#fail2"]], - "passes": [["#pass1"], ["#pass2"], ["#pass3"]] + "passes": [ + ["#pass1"], + ["#pass2"], + ["#pass3"], + ["#pass4"], + ["#pass5"] + ] }
AXE AXE AXE aXe
aXe aXe aXe aXe