Skip to content

Commit

Permalink
fix(valid-lang): run on aria-hidden text (#3634)
Browse files Browse the repository at this point in the history
  • Loading branch information
WilcoFiers authored Sep 7, 2022
1 parent 6f6a89e commit a0860bd
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 77 deletions.
4 changes: 2 additions & 2 deletions lib/commons/aria/get-element-unallowed-roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import getImplicitRole from './implicit-role';
import getRoleType from './get-role-type';
import isAriaRoleAllowedOnElement from './is-aria-role-allowed-on-element';
import { tokenList, isHtmlElement, getNodeFromTree } from '../../core/utils';
import AbstractVirtuaNode from '../../core/base/virtual-node/abstract-virtual-node';
import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node';

// dpub roles which are subclassing roles that are implicit on some native
// HTML elements (img, link, etc.)
Expand Down Expand Up @@ -55,7 +55,7 @@ function getRoleSegments(vNode) {
*/
function getElementUnallowedRoles(node, allowImplicit = true) {
const vNode =
node instanceof AbstractVirtuaNode ? node : getNodeFromTree(node);
node instanceof AbstractVirtualNode ? node : getNodeFromTree(node);
// by pass custom elements
if (!isHtmlElement(vNode)) {
return [];
Expand Down
22 changes: 13 additions & 9 deletions lib/commons/dom/has-lang-text.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import { hasChildTextNodes } from './has-content-virtual';
import isVisualContent from './is-visual-content';
import isVisible from './is-visible';
import isHiddenWithCSS from './is-hidden-with-css';

/**
* Check that a node has text, or an accessible name which language is defined by the
* Check that a node has text, or an accessible name which language is defined by the
* nearest ancestor's lang attribute.
* @param {VirtualNode} virtualNode
* @param {VirtualNode} virtualNode
* @return boolean
*/
export default function hasLangText(virtualNode) {
if (typeof virtualNode.children === 'undefined' || hasChildTextNodes(virtualNode)) {
if (
typeof virtualNode.children === 'undefined' ||
hasChildTextNodes(virtualNode)
) {
return true;
}
if (virtualNode.props.nodeType === 1 && isVisualContent(virtualNode)) {
// See: https://github.com/dequelabs/axe-core/issues/3281
return !!axe.commons.text.accessibleTextVirtual(virtualNode);
}
return virtualNode.children.some(child => (
!child.attr('lang') && // non-empty lang
hasLangText(child) && // has text
isVisible(child, true) // Not hidden for AT
));
return virtualNode.children.some(
child =>
!child.attr('lang') && // non-empty lang
hasLangText(child) && // has text
!isHiddenWithCSS(child) // Not hidden for anyone
);
}
7 changes: 5 additions & 2 deletions lib/commons/dom/is-hidden-with-css.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import getComposedParent from './get-composed-parent';
import { getNodeFromTree } from '../../core/utils';
import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node';

/**
* Determine whether an element is hidden based on css
Expand All @@ -10,8 +11,10 @@ import { getNodeFromTree } from '../../core/utils';
* @param {Boolean} descendentVisibilityValue (Optional) immediate descendant visibility value used for recursive computation
* @return {Boolean} the element's hidden status
*/
function isHiddenWithCSS(el, descendentVisibilityValue) {
const vNode = getNodeFromTree(el);
function isHiddenWithCSS(node, descendentVisibilityValue) {
const vNode =
node instanceof AbstractVirtualNode ? node : getNodeFromTree(node);
const el = node instanceof window.Node ? node : vNode?.actualNode;

if (!vNode) {
return _isHiddenWithCSS(el, descendentVisibilityValue);
Expand Down
5 changes: 5 additions & 0 deletions test/act-mapping/valid-lang.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "de46e4",
"title": "Element with lang attribute has valid language tag",
"axeRules": ["valid-lang"]
}
20 changes: 19 additions & 1 deletion test/commons/dom/has-lang-text.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
describe('dom.hasLangText', function() {
describe('dom.hasLangText', function () {
'use strict';
var hasLangText = axe.commons.dom.hasLangText;
var fixture = document.getElementById('fixture');
Expand All @@ -25,6 +25,24 @@ describe('dom.hasLangText', function() {
assert.isFalse(hasLangText(target));
});

it('returns true when the element has nested text is aria-hidden', function () {
fixture.innerHTML =
'<div id="target"> <span aria-hidden="true"> text </span> </div>';
tree = axe.utils.getFlattenedTree(fixture);
var target = axe.utils.querySelectorAll(tree, '#target')[0];
assert.isTrue(hasLangText(target));
});

it('returns true when the element has nested text is off screen', function () {
fixture.innerHTML =
'<div id="target">' +
' <span style="position: absolute; top:-99em;"> text </span> ' +
'</div>';
tree = axe.utils.getFlattenedTree(fixture);
var target = axe.utils.querySelectorAll(tree, '#target')[0];
assert.isTrue(hasLangText(target));
});

it('returns false when the element has an empty text node as its content', function () {
fixture.innerHTML = '<div id="target"> <!-- comment --> </div>';
tree = axe.utils.getFlattenedTree(fixture);
Expand Down
Loading

0 comments on commit a0860bd

Please sign in to comment.