Skip to content

Commit

Permalink
refactor(table-duplicate-name): use virtual node (#3604)
Browse files Browse the repository at this point in the history
- use virtual node

references: #3473
  • Loading branch information
dbowling authored Aug 18, 2022
1 parent b5ceabc commit 4e57881
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 23 deletions.
2 changes: 1 addition & 1 deletion doc/rule-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Rules that do not necessarily conform to WCAG success criterion but are industry
| [scope-attr-valid](https://dequeuniversity.com/rules/axe/4.4/scope-attr-valid?application=RuleDescription) | Ensures the scope attribute is used correctly on tables | Moderate, Critical | cat.tables, best-practice | failure | |
| [skip-link](https://dequeuniversity.com/rules/axe/4.4/skip-link?application=RuleDescription) | Ensure all skip links have a focusable target | Moderate | cat.keyboard, best-practice | failure, needs review | |
| [tabindex](https://dequeuniversity.com/rules/axe/4.4/tabindex?application=RuleDescription) | Ensures tabindex attribute values are not greater than 0 | Serious | cat.keyboard, best-practice | failure | |
| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.4/table-duplicate-name?application=RuleDescription) | Ensure the <caption> element does not contain the same text as the summary attribute | Minor | cat.tables, best-practice | failure | |
| [table-duplicate-name](https://dequeuniversity.com/rules/axe/4.4/table-duplicate-name?application=RuleDescription) | Ensure the <caption> element does not contain the same text as the summary attribute | Minor | cat.tables, best-practice | failure, needs review | |

## WCAG 2.0 and 2.1 level AAA rules

Expand Down
31 changes: 21 additions & 10 deletions lib/checks/tables/same-caption-summary-evaluate.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { accessibleText } from '../../commons/text';

function sameCaptionSummaryEvaluate(node) {
// passing node.caption to accessibleText instead of using
// the logic in accessibleTextVirtual on virtualNode
return (
!!(node.summary && node.caption) &&
node.summary.toLowerCase() === accessibleText(node.caption).toLowerCase()
);
}
import { sanitize, subtreeText } from '../../commons/text';

export default sameCaptionSummaryEvaluate;

function sameCaptionSummaryEvaluate(node, options, virtualNode) {
if (virtualNode.children === undefined) {
return undefined;
}

var summary = virtualNode.attr('summary');
var captionNode = virtualNode.children.find(isCaptionNode);
var caption = captionNode ? sanitize(subtreeText(captionNode)) : false;

if (!caption || !summary) {
return false;
}

return sanitize(summary).toLowerCase() === sanitize(caption).toLowerCase();
}

function isCaptionNode(virtualNode) {
return virtualNode.props.nodeName === 'caption';
}
3 changes: 2 additions & 1 deletion lib/checks/tables/same-caption-summary.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"impact": "minor",
"messages": {
"pass": "Content of summary attribute and <caption> are not duplicated",
"fail": "Content of summary attribute and <caption> element are identical"
"fail": "Content of summary attribute and <caption> element are identical",
"incomplete": "Unable to determine if <table> element has a caption"
}
}
}
3 changes: 2 additions & 1 deletion locales/_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,8 @@
},
"same-caption-summary": {
"pass": "Content of summary attribute and <caption> are not duplicated",
"fail": "Content of summary attribute and <caption> element are identical"
"fail": "Content of summary attribute and <caption> element are identical",
"incomplete": "Unable to determine if <table> element has a caption"
},
"scope-value": {
"pass": "Scope attribute is used correctly",
Expand Down
18 changes: 8 additions & 10 deletions test/checks/tables/same-caption-summary.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
describe('same-caption-summary', function() {
describe('same-caption-summary', function () {
'use strict';

var fixture = document.getElementById('fixture');
var checkSetup = axe.testUtils.checkSetup;
var shadowCheckSetup = axe.testUtils.shadowCheckSetup;
var shadowSupport = axe.testUtils.shadowSupport;

var checkContext = axe.testUtils.MockCheckContext();

afterEach(function() {
fixture.innerHTML = '';
afterEach(function () {
checkContext.reset();
axe._tree = undefined;
});

it('should return false there is no caption', function() {
it('should return false there is no caption', function () {
var params = checkSetup(
'<table summary="hi" id="target"><tr><td></td></tr></table>'
);
Expand All @@ -26,7 +24,7 @@ describe('same-caption-summary', function() {
);
});

it('should return false there is no summary', function() {
it('should return false there is no summary', function () {
var params = checkSetup(
'<table id="target"><caption>Hi</caption><tr><td></td></tr></table>'
);
Expand All @@ -38,7 +36,7 @@ describe('same-caption-summary', function() {
);
});

it('should return false if summary and caption are different', function() {
it('should return false if summary and caption are different', function () {
var params = checkSetup(
'<table summary="bye" id="target"><caption>Hi</caption><tr><td></td></tr></table>'
);
Expand All @@ -50,7 +48,7 @@ describe('same-caption-summary', function() {
);
});

it('should return true if summary and caption are the same', function() {
it('should return true if summary and caption are the same', function () {
var params = checkSetup(
'<table summary="Hi" id="target"><caption>Hi</caption><tr><td></td></tr></table>'
);
Expand All @@ -62,7 +60,7 @@ describe('same-caption-summary', function() {
);
});

it('should return true if summary and caption are the same with mixed casing', function() {
it('should return true if summary and caption are the same with mixed casing', function () {
var params = checkSetup(
'<table summary="My Table" id="target">' +
'<caption> my table </caption>' +
Expand All @@ -84,7 +82,7 @@ describe('same-caption-summary', function() {

(shadowSupport.v1 ? it : xit)(
'should match slotted caption elements',
function() {
function () {
var params = shadowCheckSetup(
'<div>' +
'<span slot="caption">Caption</span>' +
Expand Down
138 changes: 138 additions & 0 deletions test/integration/virtual-rules/table-duplicate-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
describe('table-duplicate-name virtual-rule', function () {
it('should incomplete on table element with children undefined', function () {
var tableNode = new axe.SerialVirtualNode({
nodeName: 'table'
});
tableNode.children = undefined;

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 1);
});

it('should pass on table element', function () {
var tableNode = new axe.SerialVirtualNode({
nodeName: 'table'
});

tableNode.children = [];

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should pass when table has empty summary', function () {
var tableNode = new axe.SerialVirtualNode({
nodeName: 'table',
attributes: {
summary: ''
}
});
tableNode.children = [];

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should pass when table has empty caption and summary', function () {
var tableNode = new axe.SerialVirtualNode({
nodeName: 'table',
attributes: {
summary: ''
}
});

var captionNode = new axe.SerialVirtualNode({
nodeName: 'caption'
});
captionNode.parent = tableNode;

var textNode = new axe.SerialVirtualNode({
nodeName: '#text',
nodeType: 3,
nodeValue: ''
});
textNode.parent = captionNode;

captionNode.children = [textNode];
tableNode.children = [captionNode];

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 1);
assert.lengthOf(results.violations, 0);
assert.lengthOf(results.incomplete, 0);
});

it('should fail when table summary and <caption> have the same text', function () {
var DUPLICATED_TEXT = 'foobar';

var tableNode = new axe.SerialVirtualNode({
nodeName: 'table',
attributes: {
summary: DUPLICATED_TEXT
}
});

var captionNode = new axe.SerialVirtualNode({
nodeName: 'caption'
});
captionNode.parent = tableNode;

var textNode = new axe.SerialVirtualNode({
nodeName: '#text',
nodeType: 3,
nodeValue: DUPLICATED_TEXT
});
textNode.parent = captionNode;

captionNode.children = [textNode];
tableNode.children = [captionNode];

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.incomplete, 0);
});

it('should fail when table summary and <caption> have the same text, excluding whitespace', function () {
var DUPLICATED_TEXT = 'foobar';

var tableNode = new axe.SerialVirtualNode({
nodeName: 'table',
attributes: {
summary: ' ' + DUPLICATED_TEXT
}
});

var captionNode = new axe.SerialVirtualNode({
nodeName: 'caption'
});
captionNode.parent = tableNode;

var textNode = new axe.SerialVirtualNode({
nodeName: '#text',
nodeType: 3,
nodeValue: ' \t ' + DUPLICATED_TEXT
});
textNode.parent = captionNode;

captionNode.children = [textNode];
tableNode.children = [captionNode];

var results = axe.runVirtualRule('table-duplicate-name', tableNode);

assert.lengthOf(results.passes, 0);
assert.lengthOf(results.violations, 1);
assert.lengthOf(results.incomplete, 0);
});
});

0 comments on commit 4e57881

Please sign in to comment.