Skip to content

Commit bc96242

Browse files
committed
Merge branch 'release-3.4.2' into release-3.5.0
2 parents a28c105 + 5dadee2 commit bc96242

File tree

5 files changed

+97
-2
lines changed

5 files changed

+97
-2
lines changed

lib/checks/color/link-in-text-block-evaluate.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ function getColorContrast(node, parentBlock) {
135135
nodeColor = getForegroundColor(node);
136136
parentColor = getForegroundColor(parentBlock);
137137

138+
if (!nodeColor) {
139+
nodeColor = new axe.commons.color.Color(0, 0, 0, 0);
140+
}
141+
142+
if (!parentColor) {
143+
parentColor = new axe.commons.color.Color(0, 0, 0, 0);
144+
}
145+
138146
if (!nodeColor || !parentColor) {
139147
return undefined;
140148
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Get the accessible name based on aria-describedby
3+
*
4+
* @deprecated Do not use Element directly. Pass VirtualNode instead
5+
* @param {VirtualNode|Element} element
6+
* @param {Object} context
7+
* @property {Bool} inLabelledByContext Whether or not the lookup is part of aria-describedby reference
8+
* @property {Bool} inControlContext Whether or not the lookup is part of a native label reference
9+
* @property {Element} startNode First node in accessible name computation
10+
* @property {Bool} debug Enable logging for formControlValue
11+
* @return {string} Concatenated text value for referenced elements
12+
*/
13+
function ariadescribedbyText(element, context = {}) {
14+
const { vNode } = axe.utils.nodeLookup(element);
15+
if (vNode?.props.nodeType !== 1) {
16+
return '';
17+
}
18+
19+
if (
20+
vNode.props.nodeType !== 1 ||
21+
context.inLabelledByContext ||
22+
context.inControlContext ||
23+
!vNode.attr('aria-describedby')
24+
) {
25+
return '';
26+
}
27+
28+
const refs = axe.commons.dom
29+
.idrefs(vNode, 'aria-describedby')
30+
.filter(elm => elm);
31+
return refs.reduce((accessibleName, elm) => {
32+
const accessibleNameAdd = axe.commons.text.accessibleText(elm, {
33+
// Prevent the infinite reference loop:
34+
inLabelledByContext: true,
35+
startNode: context.startNode || vNode,
36+
...context
37+
});
38+
39+
if (!accessibleName) {
40+
return accessibleNameAdd;
41+
}
42+
return `${accessibleName} ${accessibleNameAdd}`;
43+
}, '');
44+
}
45+
46+
export default ariadescribedbyText;

lib/commons/aria/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
export { default as allowedAttr } from './allowed-attr';
77
export { default as arialabelText } from './arialabel-text';
88
export { default as arialabelledbyText } from './arialabelledby-text';
9+
export { default as ariadescribedbyText } from './ariadescribedby-text';
910
export { default as getAccessibleRefs } from './get-accessible-refs';
1011
export { default as getElementUnallowedRoles } from './get-element-unallowed-roles';
1112
export { default as getExplicitRole } from './get-explicit-role';

lib/core/utils/dq-element.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ function getSource(element) {
2626
if (!source && typeof window.XMLSerializer === 'function') {
2727
source = new window.XMLSerializer().serializeToString(element);
2828
}
29-
return truncate(source || '');
29+
let htmlString = truncate(source || '');
30+
// Remove unwanted attributes
31+
const regex = /\s*data-percy-[^=]+="[^"]*"/g;
32+
htmlString = htmlString.replace(regex, '');
33+
return htmlString;
3034
}
3135

3236
/**

lib/rules/autocomplete-a11y-matches.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,50 @@ function nodeIsASearchFunctionality(actualNode, currLevel = 0, maxLevels = 4) {
5757
return currentLevelSearch(actualNode, currLevel);
5858
}
5959

60+
function quantityField(node) {
61+
const keywords = [
62+
'qty',
63+
'quantity',
64+
'quantities',
65+
'km',
66+
'kilometer',
67+
'drive',
68+
'code',
69+
'mileage',
70+
'power',
71+
'fuel'
72+
];
73+
const attributes = [
74+
'name',
75+
'id',
76+
'title',
77+
'placeholder',
78+
'aria-label',
79+
'data-label',
80+
'data-title',
81+
'data-placeholder',
82+
'role'
83+
];
84+
return attributes.some(attr => {
85+
if (node.hasAttribute(attr)) {
86+
const value = node.getAttribute(attr).toLowerCase();
87+
return keywords.some(
88+
keyword => value && value.includes(keyword.toLowerCase())
89+
);
90+
}
91+
return false;
92+
});
93+
}
94+
6095
function autocompleteA11yMatches(node, virtualNode) {
6196
const a11yEngineFlag = true;
6297
/* the flag is used to tell autocomplete matcher that it is being called
6398
by a11y-engine and thus bypass an if block
6499
The second condition is to check we are not matching with search functionality */
65100
return (
66101
autocompleteMatches(node, virtualNode, a11yEngineFlag) &&
67-
!nodeIsASearchFunctionality(node)
102+
!nodeIsASearchFunctionality(node) &&
103+
!quantityField(node)
68104
);
69105
}
70106

0 commit comments

Comments
 (0)