-
Notifications
You must be signed in to change notification settings - Fork 779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(empty-heading): use virtual node #3582
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
48d7e02
refactor(empty-heading): use virtual node
dbowling 0d4b387
wip - check
dbowling b1285e3
wip
dbowling 23b705c
wip
dbowling e4d58a0
wip
dbowling c98bc15
Merge branch 'develop' into chore/issue-3473/empty-heading
dbowling c64ab3c
Merge branch 'develop' into chore/issue-3473/empty-heading
dbowling e41211e
use virtual node instead of actual
dbowling 6738d78
Merge branch 'chore/issue-3473/empty-heading' of github.com:dequelabs…
dbowling 980c002
refactor to vnodes
dbowling 9b69990
heading-matches as virtual node
dbowling 89a20fe
add virtual rule tests
dbowling be37d06
complete jsdoc description
dbowling bdc9a2b
add failing/stubbed out tests
dbowling dd684ff
pass for title
dbowling 260ef5d
test for implicit and explicit roles
dbowling 8ad90d0
fix typo
dbowling eb6833a
remove debug
dbowling fb449cf
rm: should fail with no visible text (impossible)
dbowling 44a8499
fix aria-label test
dbowling b645ae6
fix title test
dbowling 407f850
clean up describes
dbowling 9a17afc
Merge branch 'develop' into chore/issue-3473/empty-heading
dbowling 8463715
add presentation conflict resolution failing test
dbowling a30d74b
add conflict resolution unit test
dbowling a2c28e2
set children in virtual rule to not incomplete
dbowling 8be5db2
fix: typo in test
dbowling File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,9 @@ | ||
import { sanitize, subtreeText } from '../../commons/text'; | ||
|
||
function hasTextContentEvaluate(node, options, virtualNode) { | ||
export default function hasTextContentEvaluate(node, options, virtualNode) { | ||
try { | ||
return sanitize(subtreeText(virtualNode)) !== ''; | ||
} catch (e) { | ||
return undefined; | ||
} | ||
} | ||
|
||
export default hasTextContentEvaluate; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,5 @@ | ||
function headingMatches(node) { | ||
// Get all valid roles | ||
let explicitRoles; | ||
if (node.hasAttribute('role')) { | ||
explicitRoles = node | ||
.getAttribute('role') | ||
.split(/\s+/i) | ||
.filter(axe.commons.aria.isValidRole); | ||
} | ||
import { getRole } from '../commons/aria'; | ||
|
||
// Check valid roles if there are any, otherwise fall back to the inherited role | ||
if (explicitRoles && explicitRoles.length > 0) { | ||
return explicitRoles.includes('heading'); | ||
} else { | ||
return axe.commons.aria.implicitRole(node) === 'heading'; | ||
} | ||
export default function headingMatches(node, virtualNode) { | ||
return getRole(virtualNode) === 'heading'; | ||
} | ||
|
||
export default headingMatches; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
describe('empty-heading virtual-rule', function () { | ||
it('should pass with visible text', function () { | ||
var node = new axe.SerialVirtualNode({ | ||
nodeName: 'h1', | ||
attributes: {} | ||
}); | ||
var child = new axe.SerialVirtualNode({ | ||
nodeName: '#text', | ||
nodeType: 3, | ||
nodeValue: 'OK', | ||
attributes: {} | ||
}); | ||
|
||
node.children = [child]; | ||
|
||
var results = axe.runVirtualRule('empty-heading', node); | ||
|
||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 0); | ||
assert.lengthOf(results.passes, 1); | ||
}); | ||
|
||
it('should incomplete if no other properties are set', function () { | ||
var node = new axe.SerialVirtualNode({ | ||
nodeName: 'h1' | ||
}); | ||
|
||
var results = axe.runVirtualRule('empty-heading', node); | ||
|
||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 1); | ||
assert.lengthOf(results.passes, 0); | ||
}); | ||
|
||
it('should pass for title', function () { | ||
var results = axe.runVirtualRule('empty-heading', { | ||
nodeName: 'h1', | ||
attributes: { | ||
title: 'it has a title' | ||
} | ||
}); | ||
|
||
assert.lengthOf(results.passes, 1); | ||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should pass on explicit role', function () { | ||
var results = axe.runVirtualRule('empty-heading', { | ||
nodeName: 'span', | ||
attributes: { | ||
role: 'heading', | ||
title: 'foobar' | ||
} | ||
}); | ||
|
||
assert.lengthOf(results.passes, 1); | ||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should pass on implicit role', function () { | ||
var results = axe.runVirtualRule('empty-heading', { | ||
nodeName: 'h1', | ||
attributes: { | ||
title: 'foobar' | ||
} | ||
}); | ||
|
||
assert.lengthOf(results.passes, 1); | ||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should pass for aria-label', function () { | ||
var results = axe.runVirtualRule('empty-heading', { | ||
nodeName: 'h1', | ||
attributes: { | ||
'aria-label': 'foobar' | ||
} | ||
}); | ||
|
||
assert.lengthOf(results.passes, 1); | ||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should fail when aria-label is empty', function () { | ||
var node = new axe.SerialVirtualNode({ | ||
nodeName: 'h1', | ||
attributes: { | ||
'aria-label': '' | ||
} | ||
}); | ||
node.children = []; | ||
|
||
var results = axe.runVirtualRule('empty-heading', node); | ||
|
||
assert.lengthOf(results.passes, 0); | ||
assert.lengthOf(results.violations, 1); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should incomplete for aria-labelledby', function () { | ||
var results = axe.runVirtualRule('empty-heading', { | ||
nodeName: 'h1', | ||
attributes: { | ||
'aria-labelledby': 'foobar' | ||
} | ||
}); | ||
|
||
assert.lengthOf(results.passes, 0); | ||
assert.lengthOf(results.violations, 0); | ||
assert.lengthOf(results.incomplete, 1); | ||
}); | ||
|
||
it('should fail when title is empty', function () { | ||
var node = new axe.SerialVirtualNode({ | ||
nodeName: 'h1', | ||
attributes: { | ||
title: '' | ||
} | ||
}); | ||
node.children = []; | ||
|
||
var results = axe.runVirtualRule('empty-heading', node); | ||
|
||
assert.lengthOf(results.passes, 0); | ||
assert.lengthOf(results.violations, 1); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
|
||
it('should fail in order to account for presentation conflict resolution', function () { | ||
var node = new axe.SerialVirtualNode({ | ||
nodeName: 'h1', | ||
attributes: { | ||
role: 'none', | ||
'aria-label': '' | ||
} | ||
}); | ||
node.children = []; | ||
|
||
var results = axe.runVirtualRule('empty-heading', node); | ||
|
||
assert.lengthOf(results.passes, 0); | ||
assert.lengthOf(results.violations, 1); | ||
assert.lengthOf(results.incomplete, 0); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,51 @@ | ||
describe('heading-matches', function() { | ||
describe('heading-matches', function () { | ||
'use strict'; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
var flatTreeSetup = axe.testUtils.flatTreeSetup; | ||
var queryFixture = axe.testUtils.queryFixture; | ||
var fixtureSetup = axe.testUtils.fixtureSetup; | ||
var rule; | ||
|
||
beforeEach(function() { | ||
beforeEach(function () { | ||
rule = axe.utils.getRule('empty-heading'); | ||
}); | ||
|
||
afterEach(function() { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('is a function', function() { | ||
it('is a function', function () { | ||
assert.isFunction(rule.matches); | ||
}); | ||
|
||
it('should return false on elements that are not headings', function() { | ||
var div = document.createElement('div'); | ||
fixture.appendChild(div); | ||
flatTreeSetup(fixture); | ||
assert.isFalse(rule.matches(div)); | ||
it('should return false on elements that are not headings', function () { | ||
var vNode = fixtureSetup('<div></div>'); | ||
assert.isFalse(rule.matches(null, vNode)); | ||
}); | ||
|
||
it('should return true on elements with "heading" in the role', function() { | ||
var div = document.createElement('div'); | ||
div.setAttribute('role', 'heading'); | ||
fixture.appendChild(div); | ||
flatTreeSetup(fixture); | ||
assert.isTrue(rule.matches(div)); | ||
|
||
div.setAttribute('role', 'slider heading'); | ||
assert.isTrue(rule.matches(div)); | ||
it('should return true on elements with role="heading"', function () { | ||
var vNode = queryFixture('<div role="heading" id="target"></div>'); | ||
assert.isTrue(rule.matches(null, vNode)); | ||
}); | ||
|
||
it('should return true on regular headings without roles', function() { | ||
var h1 = document.createElement('h1'); | ||
var h2 = document.createElement('h2'); | ||
var h3 = document.createElement('h3'); | ||
|
||
fixture.appendChild(h1); | ||
fixture.appendChild(h2); | ||
fixture.appendChild(h3); | ||
it('should return true on regular headings without roles', function () { | ||
for (var i = 1; i <= 6; i++) { | ||
var vNode = queryFixture('<h' + i + ' id="target"></h' + i + '>'); | ||
assert.isTrue(rule.matches(null, vNode)); | ||
} | ||
}); | ||
|
||
flatTreeSetup(fixture); | ||
assert.isTrue(rule.matches(h1)); | ||
assert.isTrue(rule.matches(h2)); | ||
assert.isTrue(rule.matches(h3)); | ||
it('should return false on headings with their role changes', function () { | ||
var vNode = queryFixture('<h1 role="banner" id="target"></h1>'); | ||
assert.isFalse(rule.matches(null, vNode)); | ||
}); | ||
|
||
it('should return false on headings with their role changes', function() { | ||
var h1 = document.createElement('h1'); | ||
h1.setAttribute('role', 'banner'); | ||
fixture.appendChild(h1); | ||
flatTreeSetup(fixture); | ||
assert.isFalse(rule.matches(h1)); | ||
it('should return true on headings with their role changes to an invalid role', function () { | ||
var vNode = queryFixture('<h1 role="bruce" id="target"></h1>'); | ||
assert.isTrue(rule.matches(null, vNode)); | ||
}); | ||
|
||
it('should return true on headings with their role changes to an invalid role', function() { | ||
var h1 = document.createElement('h1'); | ||
h1.setAttribute('role', 'bruce'); | ||
fixture.appendChild(h1); | ||
flatTreeSetup(fixture); | ||
assert.isTrue(rule.matches(h1)); | ||
it('should return true on headings with their role changes to an abstract role', function () { | ||
var vNode = queryFixture('<h1 role="widget" id="target"></h1>'); | ||
assert.isTrue(rule.matches(null, vNode)); | ||
}); | ||
|
||
it('should return true on headings with their role changes to an abstract role', function() { | ||
var h1 = document.createElement('h1'); | ||
h1.setAttribute('role', 'widget'); | ||
fixture.appendChild(h1); | ||
flatTreeSetup(fixture); | ||
assert.isTrue(rule.matches(h1)); | ||
it('should return true on headings with explicit role="none" and an empty aria-label to account for presentation conflict resolution', function () { | ||
var vNode = queryFixture('<h1 aria-label="" role="none" id="target"></h1>'); | ||
assert.isTrue(rule.matches(null, vNode)); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh, good ol' role=bruce