@afixt/test-utils 1.1.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +6 -1
- package/.github/workflows/ci.yml +71 -0
- package/.github/workflows/pr-check.yml +88 -0
- package/.github/workflows/security.yml +139 -0
- package/.husky/pre-commit +1 -0
- package/.jscpd.json +27 -0
- package/.markdownlint.json +9 -0
- package/.prettierignore +13 -0
- package/.prettierrc +10 -0
- package/docs/arrayUtils.js.html +2 -2
- package/docs/domUtils.js.html +2 -2
- package/docs/getAccessibleName.js.html +2 -2
- package/docs/getAccessibleText.js.html +2 -2
- package/docs/getAriaAttributesByElement.js.html +2 -2
- package/docs/getCSSGeneratedContent.js.html +2 -2
- package/docs/getComputedRole.js.html +2 -2
- package/docs/getFocusableElements.js.html +2 -2
- package/docs/getGeneratedContent.js.html +2 -2
- package/docs/getImageText.js.html +2 -2
- package/docs/getStyleObject.js.html +2 -2
- package/docs/global.html +2 -2
- package/docs/hasAccessibleName.js.html +2 -2
- package/docs/hasAttribute.js.html +2 -2
- package/docs/hasCSSGeneratedContent.js.html +2 -2
- package/docs/hasHiddenParent.js.html +2 -2
- package/docs/hasParent.js.html +2 -2
- package/docs/hasValidAriaAttributes.js.html +2 -2
- package/docs/hasValidAriaRole.js.html +2 -2
- package/docs/index.html +2 -2
- package/docs/index.js.html +2 -2
- package/docs/isAriaAttributesValid.js.html +2 -2
- package/docs/isComplexTable.js.html +2 -2
- package/docs/isDataTable.js.html +2 -2
- package/docs/isFocusable.js.html +2 -2
- package/docs/isHidden.js.html +2 -2
- package/docs/isOffScreen.js.html +2 -2
- package/docs/isValidUrl.js.html +2 -2
- package/docs/isVisible.js.html +2 -2
- package/docs/module-afixt-test-utils.html +2 -2
- package/docs/scripts/core.js +726 -726
- package/docs/scripts/core.min.js +22 -22
- package/docs/scripts/resize.js +90 -90
- package/docs/scripts/search.js +265 -265
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -202
- package/docs/scripts/third-party/fuse.js +8 -8
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -369
- package/docs/scripts/third-party/hljs-original.js +5171 -5171
- package/docs/scripts/third-party/popper.js +5 -5
- package/docs/scripts/third-party/tippy.js +1 -1
- package/docs/scripts/third-party/tocbot.js +671 -671
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -1159
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -412
- package/docs/styles/clean-jsdoc-theme-light.css +482 -482
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +29 -29
- package/docs/testContrast.js.html +2 -2
- package/docs/testLang.js.html +2 -2
- package/docs/testOrder.js.html +2 -2
- package/eslint.config.mjs +84 -0
- package/package.json +68 -41
- package/scratchpads/issue-6-standardize-repo.md +109 -0
- package/src/getAccessibleName.js +156 -112
- package/src/getAccessibleText.js +71 -42
- package/src/stringUtils.js +19 -21
- package/src/testContrast.js +103 -22
- package/test/getAccessibleName.test.js +379 -315
- package/test/getAccessibleText.test.js +375 -308
- package/test/stringUtils.test.js +376 -332
- package/test/testContrast.test.js +801 -651
- package/.eslintrc +0 -78
- package/.github/workflows/test.yml +0 -26
package/src/getAccessibleText.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
const { isEmpty } = require(
|
|
1
|
+
const { isEmpty } = require('./stringUtils.js');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Get all accessible text for an element, including aria-labels and content from children.
|
|
5
|
+
* Traverses the DOM subtree collecting text from text nodes, img alt attributes,
|
|
6
|
+
* and input[type="image"] alt attributes.
|
|
5
7
|
* @param {Element} el - The DOM element.
|
|
6
8
|
* @returns {string} The accessible text.
|
|
7
9
|
*/
|
|
@@ -13,55 +15,82 @@ function getAccessibleText(el) {
|
|
|
13
15
|
if (!el.isConnected) {
|
|
14
16
|
return '';
|
|
15
17
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (el.textContent) {
|
|
21
|
-
textContent = el.textContent.trim();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Check for aria-label
|
|
25
|
-
if (el.hasAttribute("aria-label")) {
|
|
26
|
-
const ariaLabel = el.getAttribute("aria-label").trim();
|
|
18
|
+
|
|
19
|
+
// Check for aria-label first (highest priority)
|
|
20
|
+
if (el.hasAttribute('aria-label')) {
|
|
21
|
+
const ariaLabel = el.getAttribute('aria-label').trim();
|
|
27
22
|
if (ariaLabel) {
|
|
28
|
-
// Prioritize aria-label if present
|
|
29
23
|
return ariaLabel;
|
|
30
24
|
}
|
|
31
25
|
}
|
|
32
|
-
|
|
33
|
-
// Check for img alt text
|
|
34
|
-
if (el.tagName.toLowerCase() ===
|
|
35
|
-
return el.getAttribute(
|
|
26
|
+
|
|
27
|
+
// Check for img alt text when the element itself is an img
|
|
28
|
+
if (el.tagName.toLowerCase() === 'img' && el.hasAttribute('alt')) {
|
|
29
|
+
return el.getAttribute('alt').trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check for input[type="image"] alt text when the element itself is one
|
|
33
|
+
if (
|
|
34
|
+
el.tagName.toLowerCase() === 'input' &&
|
|
35
|
+
el.getAttribute('type') === 'image' &&
|
|
36
|
+
el.hasAttribute('alt')
|
|
37
|
+
) {
|
|
38
|
+
return el.getAttribute('alt').trim();
|
|
36
39
|
}
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
|
|
41
|
+
// Collect accessible text from the subtree, including text nodes
|
|
42
|
+
// and alt text from embedded images
|
|
43
|
+
const parts = collectSubtreeText(el);
|
|
44
|
+
return parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Recursively collect accessible text parts from an element's subtree.
|
|
49
|
+
* Handles text nodes, img alt text, and input[type="image"] alt text.
|
|
50
|
+
* @param {Node} node - The DOM node to traverse.
|
|
51
|
+
* @returns {string[]} Array of text parts found in the subtree.
|
|
52
|
+
*/
|
|
53
|
+
function collectSubtreeText(node) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
|
|
56
|
+
for (let child = node.firstChild; child; child = child.nextSibling) {
|
|
57
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
58
|
+
const text = child.nodeValue.trim();
|
|
59
|
+
if (!isEmpty(text)) {
|
|
60
|
+
parts.push(text);
|
|
61
|
+
}
|
|
62
|
+
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
63
|
+
const tag = child.tagName.toLowerCase();
|
|
64
|
+
|
|
65
|
+
// img with non-empty alt contributes its alt text
|
|
66
|
+
if (tag === 'img' && child.hasAttribute('alt')) {
|
|
67
|
+
const alt = child.getAttribute('alt').trim();
|
|
68
|
+
if (alt) {
|
|
69
|
+
parts.push(alt);
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
50
72
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
|
|
74
|
+
// input[type="image"] with non-empty alt contributes its alt text
|
|
75
|
+
if (
|
|
76
|
+
tag === 'input' &&
|
|
77
|
+
child.getAttribute('type') === 'image' &&
|
|
78
|
+
child.hasAttribute('alt')
|
|
79
|
+
) {
|
|
80
|
+
const alt = child.getAttribute('alt').trim();
|
|
81
|
+
if (alt) {
|
|
82
|
+
parts.push(alt);
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Recurse into other element children
|
|
88
|
+
parts.push(...collectSubtreeText(child));
|
|
58
89
|
}
|
|
59
|
-
|
|
60
|
-
textContent = textNodes.join(" ").trim();
|
|
61
90
|
}
|
|
62
|
-
|
|
63
|
-
return
|
|
91
|
+
|
|
92
|
+
return parts;
|
|
64
93
|
}
|
|
65
94
|
|
|
66
95
|
// Export for CommonJS module usage
|
|
67
|
-
module.exports = { getAccessibleText };
|
|
96
|
+
module.exports = { getAccessibleText };
|
package/src/stringUtils.js
CHANGED
|
@@ -14,7 +14,7 @@ const stringUtils = (function () {
|
|
|
14
14
|
* @returns {boolean} Whether the value is a string.
|
|
15
15
|
*/
|
|
16
16
|
function isString(str) {
|
|
17
|
-
return typeof str ===
|
|
17
|
+
return typeof str === 'string' || str instanceof String;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -32,7 +32,7 @@ const stringUtils = (function () {
|
|
|
32
32
|
* @returns {boolean}
|
|
33
33
|
*/
|
|
34
34
|
function isNormalInteger(str) {
|
|
35
|
-
const n =
|
|
35
|
+
const n = Math.trunc(Number(str));
|
|
36
36
|
return String(n) === str && n >= 0;
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -49,14 +49,11 @@ const stringUtils = (function () {
|
|
|
49
49
|
let char;
|
|
50
50
|
let isUpper = true;
|
|
51
51
|
|
|
52
|
-
str = str.replace(/[^\w\s]|_/g,
|
|
52
|
+
str = str.replace(/[^\w\s]|_/g, '').replace(/\s+/g, ' ');
|
|
53
53
|
|
|
54
54
|
while (i <= str.length) {
|
|
55
55
|
char = str.charAt(i);
|
|
56
|
-
if (
|
|
57
|
-
char.trim() !== "" &&
|
|
58
|
-
false === (!isNaN(parseFloat(char)) && isFinite(char))
|
|
59
|
-
) {
|
|
56
|
+
if (char.trim() !== '' && false === (!isNaN(parseFloat(char)) && isFinite(char))) {
|
|
60
57
|
if (char === char.toLowerCase()) {
|
|
61
58
|
isUpper = false;
|
|
62
59
|
}
|
|
@@ -94,14 +91,15 @@ const stringUtils = (function () {
|
|
|
94
91
|
* @returns {string} A string containing all concatenated text content from the element.
|
|
95
92
|
*/
|
|
96
93
|
function getAllText(el) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
94
|
+
// Check for form element value (input, textarea, select)
|
|
95
|
+
if (el.value !== undefined && el.value !== '') {
|
|
96
|
+
return el.value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const walker = document.createTreeWalker(el, NodeFilter.SHOW_ALL, null, false);
|
|
103
100
|
const textNodes = [];
|
|
104
|
-
let node
|
|
101
|
+
let node;
|
|
102
|
+
let text;
|
|
105
103
|
|
|
106
104
|
while (walker.nextNode()) {
|
|
107
105
|
node = walker.currentNode;
|
|
@@ -113,15 +111,15 @@ const stringUtils = (function () {
|
|
|
113
111
|
textNodes.push(node.textContent.trim());
|
|
114
112
|
}
|
|
115
113
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
116
|
-
if (node.hasAttribute(
|
|
117
|
-
textNodes.push(node.getAttribute(
|
|
118
|
-
} else if (node.tagName ===
|
|
119
|
-
textNodes.push(node.getAttribute(
|
|
114
|
+
if (node.hasAttribute('aria-label')) {
|
|
115
|
+
textNodes.push(node.getAttribute('aria-label'));
|
|
116
|
+
} else if (node.tagName === 'IMG' && node.hasAttribute('alt')) {
|
|
117
|
+
textNodes.push(node.getAttribute('alt'));
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
return textNodes.join(
|
|
122
|
+
return textNodes.join(' ');
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
/**
|
|
@@ -131,7 +129,7 @@ const stringUtils = (function () {
|
|
|
131
129
|
* @returns {boolean} True if the element contains text, false otherwise.
|
|
132
130
|
*/
|
|
133
131
|
function hasText(element) {
|
|
134
|
-
return getAllText(element).trim() !==
|
|
132
|
+
return getAllText(element).trim() !== '';
|
|
135
133
|
}
|
|
136
134
|
|
|
137
135
|
return {
|
|
@@ -143,7 +141,7 @@ const stringUtils = (function () {
|
|
|
143
141
|
isAlphaNumeric,
|
|
144
142
|
getPathFromUrl,
|
|
145
143
|
getAllText,
|
|
146
|
-
hasText
|
|
144
|
+
hasText,
|
|
147
145
|
};
|
|
148
146
|
})();
|
|
149
147
|
|
package/src/testContrast.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get the computed background color for an element.
|
|
3
3
|
* @param {Element} el - the element to be tested
|
|
4
|
+
* @param {Object} [options] - Configuration options
|
|
5
|
+
* @param {string} [options.fallbackColor='rgb(255, 255, 255)'] - Color to use when background can't be determined
|
|
6
|
+
* @param {boolean} [options.skipBackgroundImages=true] - If true (default), return false for background images. If false, use fallbackColor instead.
|
|
4
7
|
* @returns {string|boolean} background color or false
|
|
5
8
|
*/
|
|
6
|
-
function getComputedBackgroundColor(el) {
|
|
9
|
+
function getComputedBackgroundColor(el, options) {
|
|
7
10
|
if (!window.getComputedStyle || !el || el.nodeType === 9) {
|
|
8
11
|
return false;
|
|
9
12
|
}
|
|
10
13
|
|
|
14
|
+
const opts = options || {};
|
|
15
|
+
const fallbackColor = opts.fallbackColor || 'rgb(255, 255, 255)';
|
|
16
|
+
const skipBackgroundImages =
|
|
17
|
+
opts.skipBackgroundImages !== undefined ? opts.skipBackgroundImages : true;
|
|
18
|
+
|
|
11
19
|
const styles = window.getComputedStyle(el);
|
|
12
20
|
if (!styles) {
|
|
13
21
|
return false;
|
|
@@ -17,12 +25,18 @@ function getComputedBackgroundColor(el) {
|
|
|
17
25
|
if (bgImage === 'none') {
|
|
18
26
|
const bgColor = styles.getPropertyValue('background-color');
|
|
19
27
|
|
|
20
|
-
if (bgColor === 'rgba(0, 0, 0, 0)'
|
|
21
|
-
|
|
28
|
+
if (bgColor === 'rgba(0, 0, 0, 0)') {
|
|
29
|
+
if (el.parentElement) {
|
|
30
|
+
return getComputedBackgroundColor(el.parentElement, options);
|
|
31
|
+
}
|
|
32
|
+
return opts.fallbackColor !== undefined ? fallbackColor : false;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
return bgColor;
|
|
25
36
|
} else {
|
|
37
|
+
if (!skipBackgroundImages) {
|
|
38
|
+
return fallbackColor;
|
|
39
|
+
}
|
|
26
40
|
return false;
|
|
27
41
|
}
|
|
28
42
|
}
|
|
@@ -40,9 +54,9 @@ function luminance(R8bit, G8bit, B8bit) {
|
|
|
40
54
|
const GsRGB = G8bit / 255;
|
|
41
55
|
const BsRGB = B8bit / 255;
|
|
42
56
|
|
|
43
|
-
const R =
|
|
44
|
-
const G =
|
|
45
|
-
const B =
|
|
57
|
+
const R = RsRGB <= 0.03928 ? RsRGB / 12.92 : Math.pow((RsRGB + 0.055) / 1.055, 2.4);
|
|
58
|
+
const G = GsRGB <= 0.03928 ? GsRGB / 12.92 : Math.pow((GsRGB + 0.055) / 1.055, 2.4);
|
|
59
|
+
const B = BsRGB <= 0.03928 ? BsRGB / 12.92 : Math.pow((BsRGB + 0.055) / 1.055, 2.4);
|
|
46
60
|
|
|
47
61
|
// For the sRGB colorspace, the relative luminance of a color is defined as:
|
|
48
62
|
const L = 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
|
@@ -50,6 +64,24 @@ function luminance(R8bit, G8bit, B8bit) {
|
|
|
50
64
|
return L;
|
|
51
65
|
}
|
|
52
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Calculate relative luminance from an RGB object.
|
|
69
|
+
* Wrapper around luminance() that accepts an object instead of three separate arguments.
|
|
70
|
+
* @param {{ r: number, g: number, b: number }} rgb - Object with r, g, b properties (0-255)
|
|
71
|
+
* @returns {number|null} Relative luminance value (0-1) or null if input is invalid
|
|
72
|
+
*/
|
|
73
|
+
function getRelativeLuminance(rgb) {
|
|
74
|
+
if (
|
|
75
|
+
!rgb ||
|
|
76
|
+
typeof rgb.r !== 'number' ||
|
|
77
|
+
typeof rgb.g !== 'number' ||
|
|
78
|
+
typeof rgb.b !== 'number'
|
|
79
|
+
) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return luminance(rgb.r, rgb.g, rgb.b);
|
|
83
|
+
}
|
|
84
|
+
|
|
53
85
|
/**
|
|
54
86
|
* Parse an RGB or RGBA color string into its components
|
|
55
87
|
* @param {string} rgb - RGB(A) color string (e.g., "rgb(255, 0, 0)" or "rgba(255, 0, 0, 0.5)")
|
|
@@ -60,6 +92,57 @@ function parseRGB(rgb) {
|
|
|
60
92
|
return rgbvals;
|
|
61
93
|
}
|
|
62
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Parse an RGB/RGBA color string into a structured object.
|
|
97
|
+
* @param {string} colorStr - e.g., 'rgb(255, 128, 0)' or 'rgba(255, 128, 0, 0.5)'
|
|
98
|
+
* @returns {{ r: number, g: number, b: number, a?: number } | null}
|
|
99
|
+
*/
|
|
100
|
+
function parseColor(colorStr) {
|
|
101
|
+
if (!colorStr) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const match = parseRGB(colorStr);
|
|
106
|
+
if (!match) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = {
|
|
111
|
+
r: parseInt(match[1], 10),
|
|
112
|
+
g: parseInt(match[2], 10),
|
|
113
|
+
b: parseInt(match[3], 10),
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (match[4] !== undefined) {
|
|
117
|
+
result.a = parseFloat(match[4]);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Calculate contrast ratio between two color strings.
|
|
125
|
+
* @param {string} color1 - e.g., 'rgb(0, 0, 0)'
|
|
126
|
+
* @param {string} color2 - e.g., 'rgb(255, 255, 255)'
|
|
127
|
+
* @returns {number|null} Contrast ratio (1 to 21) or null if colors can't be parsed
|
|
128
|
+
*/
|
|
129
|
+
function getContrastRatio(color1, color2) {
|
|
130
|
+
const c1 = parseColor(color1);
|
|
131
|
+
const c2 = parseColor(color2);
|
|
132
|
+
|
|
133
|
+
if (!c1 || !c2) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const lum1 = luminance(c1.r, c1.g, c1.b);
|
|
138
|
+
const lum2 = luminance(c2.r, c2.g, c2.b);
|
|
139
|
+
|
|
140
|
+
const lighter = Math.max(lum1, lum2);
|
|
141
|
+
const darker = Math.min(lum1, lum2);
|
|
142
|
+
|
|
143
|
+
return Math.round(((lighter + 0.05) / (darker + 0.05)) * 100) / 100;
|
|
144
|
+
}
|
|
145
|
+
|
|
63
146
|
/**
|
|
64
147
|
* Calculate color contrast ratio between foreground and background
|
|
65
148
|
* @param {Element} el - DOM element to check
|
|
@@ -105,7 +188,7 @@ function getColorContrast(el) {
|
|
|
105
188
|
lighter = fgLuminance;
|
|
106
189
|
}
|
|
107
190
|
|
|
108
|
-
return Math.round((lighter + 0.05) / (darker + 0.05) * 100) / 100;
|
|
191
|
+
return Math.round(((lighter + 0.05) / (darker + 0.05)) * 100) / 100;
|
|
109
192
|
}
|
|
110
193
|
|
|
111
194
|
/**
|
|
@@ -132,10 +215,11 @@ function testContrast(el, options = { level: 'AA' }) {
|
|
|
132
215
|
|
|
133
216
|
// Check if element is offscreen
|
|
134
217
|
const rect = el.getBoundingClientRect();
|
|
135
|
-
const selfOffscreen =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
218
|
+
const selfOffscreen =
|
|
219
|
+
rect.left + rect.width <= 0 ||
|
|
220
|
+
rect.top + rect.height <= 0 ||
|
|
221
|
+
rect.left >= window.innerWidth ||
|
|
222
|
+
rect.top >= window.innerHeight;
|
|
139
223
|
|
|
140
224
|
// Get direct text (excluding child elements)
|
|
141
225
|
let selfDirectText = '';
|
|
@@ -157,14 +241,6 @@ function testContrast(el, options = { level: 'AA' }) {
|
|
|
157
241
|
return true;
|
|
158
242
|
}
|
|
159
243
|
|
|
160
|
-
// JSDOM Test Compatibility: Handle test case for identical colors
|
|
161
|
-
if (selfFG === selfBG || (selfFG === 'rgb(0, 0, 0)' && selfBG === 'rgb(0, 0, 0)')) {
|
|
162
|
-
// Special case for test
|
|
163
|
-
if (el.textContent === 'Test text') {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
244
|
// Determine the contrast required based on the level passed to the function
|
|
169
245
|
if (level === 'AA') {
|
|
170
246
|
if (selfSize < 18) {
|
|
@@ -209,8 +285,10 @@ function testContrast(el, options = { level: 'AA' }) {
|
|
|
209
285
|
// Only test contrast if there's a difference between the element and its parent
|
|
210
286
|
// in terms of colors, font size, or font weight
|
|
211
287
|
if (
|
|
212
|
-
|
|
213
|
-
|
|
288
|
+
selfFG !== parentFG ||
|
|
289
|
+
selfBG !== parentBG ||
|
|
290
|
+
selfSize !== parentSize ||
|
|
291
|
+
selfWeight !== parentWeight
|
|
214
292
|
) {
|
|
215
293
|
const contrast = getColorContrast(el);
|
|
216
294
|
|
|
@@ -237,5 +315,8 @@ module.exports = {
|
|
|
237
315
|
getComputedBackgroundColor,
|
|
238
316
|
luminance,
|
|
239
317
|
parseRGB,
|
|
240
|
-
|
|
318
|
+
parseColor,
|
|
319
|
+
getRelativeLuminance,
|
|
320
|
+
getContrastRatio,
|
|
321
|
+
getColorContrast,
|
|
241
322
|
};
|