testaro 60.16.2 → 60.18.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/package.json +1 -1
- package/procs/testaro.js +3 -118
- package/testaro/allCaps.js +32 -36
- package/testaro/allSlanted.js +16 -21
- package/testaro/distortion.js +20 -22
- package/testaro/focAndOp.js +7 -8
- package/testaro/hover.js +1 -1
- package/testaro/hr.js +32 -0
- package/testaro/imageLink.js +19 -16
- package/testaro/legendLoc.js +18 -23
- package/testaro/linkExt.js +31 -0
- package/testaro/linkOldAtt.js +43 -0
- package/testaro/linkTo.js +37 -0
- package/testaro/linkUl.js +24 -30
- package/testaro/nonTable.js +39 -55
- package/testaro/optRoleSel.js +18 -15
- package/testaro/pseudoP.js +54 -0
- package/testaro/role.js +1 -1
- package/testaro/textSem.js +1 -1
- package/testaro/titledEl.js +34 -0
- package/tests/testaro.js +124 -175
- package/data/template.js +0 -39
- package/testaro/hr.json +0 -10
- package/testaro/linkExt.json +0 -10
- package/testaro/linkOldAtt.json +0 -10
- package/testaro/linkTitle.js +0 -46
- package/testaro/linkTo.json +0 -10
- package/testaro/pseudoP.json +0 -10
- package/testaro/titledEl.json +0 -10
package/package.json
CHANGED
package/procs/testaro.js
CHANGED
|
@@ -26,122 +26,6 @@ const {xPath} = require('playwright-dompath');
|
|
|
26
26
|
|
|
27
27
|
// ########## FUNCTIONS
|
|
28
28
|
|
|
29
|
-
// Initializes violation locators and a result and returns them in an object.
|
|
30
|
-
const init = exports.init = async (sampleMax, page, locAllSelector, options = {}) => {
|
|
31
|
-
// Get locators for the specified elements.
|
|
32
|
-
const locPop = page.locator(locAllSelector, options);
|
|
33
|
-
const locPops = await locPop.all();
|
|
34
|
-
const populationSize = locPops.length;
|
|
35
|
-
const sampleSize = Math.min(sampleMax, populationSize);
|
|
36
|
-
const locIndexes = getSample(locPops, sampleSize);
|
|
37
|
-
const allLocs = locIndexes.map(index => locPops[index]);
|
|
38
|
-
const result = {
|
|
39
|
-
data: {
|
|
40
|
-
populationSize,
|
|
41
|
-
sampleSize,
|
|
42
|
-
populationRatio: sampleSize ? populationSize / sampleSize : null
|
|
43
|
-
},
|
|
44
|
-
totals: [0, 0, 0, 0],
|
|
45
|
-
standardInstances: []
|
|
46
|
-
};
|
|
47
|
-
// Return the result.
|
|
48
|
-
return {
|
|
49
|
-
allLocs,
|
|
50
|
-
locs: [],
|
|
51
|
-
result
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Populates and returns a result.
|
|
56
|
-
const getRuleResult = exports.getRuleResult = async (
|
|
57
|
-
withItems, all, ruleID, whats, ordinalSeverity, tagName = ''
|
|
58
|
-
) => {
|
|
59
|
-
const {locs, result} = all;
|
|
60
|
-
const {data, totals, standardInstances} = result;
|
|
61
|
-
// For each violation locator:
|
|
62
|
-
for (const locItem of locs) {
|
|
63
|
-
// Get data on its element.
|
|
64
|
-
let loc, whatParam;
|
|
65
|
-
if (Array.isArray(locItem)) {
|
|
66
|
-
loc = locItem[0];
|
|
67
|
-
whatParam = locItem[1];
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
loc = locItem;
|
|
71
|
-
}
|
|
72
|
-
const elData = await getLocatorData(loc);
|
|
73
|
-
// Increment the totals.
|
|
74
|
-
totals[ordinalSeverity] += data.populationRatio;
|
|
75
|
-
// If itemization is required:
|
|
76
|
-
if (withItems) {
|
|
77
|
-
// Get the bounding box of the element.
|
|
78
|
-
const {tagName, id, location, excerpt} = elData;
|
|
79
|
-
const box = location.type === 'box' ? location.spec : await boxOf(loc);
|
|
80
|
-
// Add a standard instance to the result.
|
|
81
|
-
standardInstances.push({
|
|
82
|
-
ruleID,
|
|
83
|
-
what: whatParam ? whats[0].replace('__param__', whatParam) : whats[0],
|
|
84
|
-
ordinalSeverity,
|
|
85
|
-
tagName,
|
|
86
|
-
id,
|
|
87
|
-
location,
|
|
88
|
-
excerpt,
|
|
89
|
-
boxID: boxToString(box),
|
|
90
|
-
pathID: tagName === 'HTML' ? '/html' : await xPath(loc)
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
// If itemization is not required and any instances exist:
|
|
95
|
-
if (! withItems && locs.length) {
|
|
96
|
-
// Add a summary standard instance to the result.
|
|
97
|
-
standardInstances.push({
|
|
98
|
-
ruleID,
|
|
99
|
-
what: whats[1],
|
|
100
|
-
ordinalSeverity,
|
|
101
|
-
count: Math.round(totals[ordinalSeverity]),
|
|
102
|
-
tagName,
|
|
103
|
-
id: '',
|
|
104
|
-
location: {
|
|
105
|
-
doc: '',
|
|
106
|
-
type: '',
|
|
107
|
-
spec: ''
|
|
108
|
-
},
|
|
109
|
-
excerpt: '',
|
|
110
|
-
boxID: '',
|
|
111
|
-
pathID: ''
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
// Return the result.
|
|
115
|
-
return result;
|
|
116
|
-
};
|
|
117
|
-
// Performs a simplifiable test.
|
|
118
|
-
exports.simplify = async (page, withItems, ruleData) => {
|
|
119
|
-
const {
|
|
120
|
-
ruleID, selector, pruner, complaints, ordinalSeverity, summaryTagName
|
|
121
|
-
} = ruleData;
|
|
122
|
-
// Get an object with initialized violation locators and result as properties.
|
|
123
|
-
const all = await init(100, page, selector);
|
|
124
|
-
// For each locator:
|
|
125
|
-
for (const loc of all.allLocs) {
|
|
126
|
-
// Get whether its element violates the rule.
|
|
127
|
-
const isBad = await pruner(loc);
|
|
128
|
-
// If it does:
|
|
129
|
-
if (isBad) {
|
|
130
|
-
// Add the locator of the element to the array of violation locators.
|
|
131
|
-
all.locs.push(loc);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// Populate and return the result.
|
|
135
|
-
const whats = [
|
|
136
|
-
complaints.instance,
|
|
137
|
-
complaints.summary
|
|
138
|
-
];
|
|
139
|
-
const result = await getRuleResult(
|
|
140
|
-
withItems, all, ruleID, whats, ordinalSeverity, summaryTagName
|
|
141
|
-
);
|
|
142
|
-
// Return the result.
|
|
143
|
-
return result;
|
|
144
|
-
};
|
|
145
29
|
// Performs a standard test.
|
|
146
30
|
exports.doTest = async (
|
|
147
31
|
page,
|
|
@@ -169,12 +53,13 @@ exports.doTest = async (
|
|
|
169
53
|
const candidates = document.body.querySelectorAll(candidateSelector);
|
|
170
54
|
let violationCount = 0;
|
|
171
55
|
const instances = [];
|
|
172
|
-
// Get a violation
|
|
56
|
+
// Get a function that returns a violation description, if any, for the candidate.
|
|
173
57
|
const getBadWhat = eval(`(${getBadWhatString})`);
|
|
174
58
|
// For each candidate:
|
|
175
59
|
for (const candidate of candidates) {
|
|
60
|
+
// Get the violation description, if any.
|
|
176
61
|
const violationWhat = await getBadWhat(candidate);
|
|
177
|
-
// If
|
|
62
|
+
// If the candidate violates the rule:
|
|
178
63
|
if (violationWhat) {
|
|
179
64
|
// Increment the violation count.
|
|
180
65
|
violationCount++;
|
package/testaro/allCaps.js
CHANGED
|
@@ -14,48 +14,44 @@
|
|
|
14
14
|
This test reports elements with native or transformed upper-case text at least 8 characters long. Blocks of upper-case text are difficult to read.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// IMPORTS
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const {simplify} = require('../procs/testaro');
|
|
19
|
+
const {doTest} = require('../procs/testaro');
|
|
21
20
|
|
|
22
|
-
//
|
|
21
|
+
// FUNCTIONS
|
|
23
22
|
|
|
24
23
|
// Runs the test and returns the result.
|
|
25
24
|
exports.reporter = async (page, withItems) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
const getBadWhat = element => {
|
|
26
|
+
// Get the child text nodes of the element.
|
|
27
|
+
const childTextNodes = Array.from(element.childNodes).filter(
|
|
28
|
+
node => node.nodeType === Node.TEXT_NODE
|
|
29
|
+
);
|
|
30
|
+
// Get the concatenation of their texts that contain 8 or more consecutive letters.
|
|
31
|
+
let longText = childTextNodes
|
|
32
|
+
.map(node => node.nodeValue.trim())
|
|
33
|
+
.filter(text => /[A-Z]{8,}/i.test(text))
|
|
34
|
+
.join(' ');
|
|
35
|
+
// If there is any:
|
|
36
|
+
if (longText) {
|
|
37
|
+
// Get the style declaration of the element.
|
|
38
|
+
const styleDec = window.getComputedStyle(element);
|
|
39
|
+
const {textTransform} = styleDec;
|
|
40
|
+
// If the style declaration transforms the text to upper case:
|
|
41
|
+
if (textTransform === 'uppercase') {
|
|
42
|
+
// Return a violation description.
|
|
43
|
+
return 'Element text is rendered as all-capital';
|
|
43
44
|
}
|
|
44
|
-
// Otherwise:
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
const transformStyle = elStyleDec.textTransform;
|
|
49
|
-
return transformStyle === 'uppercase' && elText.length > 7;
|
|
45
|
+
// Otherwise, if the text contains 8 or more consecutive upper-case letters:
|
|
46
|
+
if (/[A-Z]{8,}/.test(longText)) {
|
|
47
|
+
// Return a violation description.
|
|
48
|
+
return 'Element contains all-capital text';
|
|
50
49
|
}
|
|
51
|
-
}
|
|
52
|
-
complaints: {
|
|
53
|
-
instance: 'Element contains all-capital text',
|
|
54
|
-
summary: 'Elements contain all-capital text'
|
|
55
|
-
},
|
|
56
|
-
ordinalSeverity: 0,
|
|
57
|
-
summaryTagName: ''
|
|
50
|
+
}
|
|
58
51
|
};
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const selector = 'body *:not(style, script, svg)';
|
|
53
|
+
const whats = 'Elements have all-capital text';
|
|
54
|
+
return await doTest(
|
|
55
|
+
page, withItems, 'allCaps', selector, whats, 0, null, getBadWhat.toString()
|
|
56
|
+
);
|
|
61
57
|
};
|
package/testaro/allSlanted.js
CHANGED
|
@@ -14,31 +14,26 @@
|
|
|
14
14
|
This test reports elements with italic or oblique text at least 40 characters long. Blocks of slanted text are difficult to read.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// IMPORTS
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const {simplify} = require('../procs/testaro');
|
|
19
|
+
const {doTest} = require('../procs/testaro');
|
|
21
20
|
|
|
22
|
-
//
|
|
21
|
+
// FUNCTIONS
|
|
23
22
|
|
|
24
23
|
// Runs the test and returns the result.
|
|
25
24
|
exports.reporter = async (page, withItems) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}),
|
|
35
|
-
complaints: {
|
|
36
|
-
instance: 'Element contains all-italic or all-oblique text',
|
|
37
|
-
summary: 'Elements contain all-italic or all-oblique text'
|
|
38
|
-
},
|
|
39
|
-
ordinalSeverity: 0,
|
|
40
|
-
summaryTagName: ''
|
|
25
|
+
const getBadWhat = element => {
|
|
26
|
+
const styleDec = window.getComputedStyle(element);
|
|
27
|
+
const {textContent} = element;
|
|
28
|
+
// If the element contains 40 or more characters of slanted text:
|
|
29
|
+
if (['italic', 'oblique'].includes(styleDec.fontStyle) && textContent.length > 39) {
|
|
30
|
+
// Return a violation description.
|
|
31
|
+
return 'Element contains all-slanted text';
|
|
32
|
+
}
|
|
41
33
|
};
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
const selector = 'body *:not(style, script, svg)';
|
|
35
|
+
const whats = 'Elements contain all-slanted text';
|
|
36
|
+
return await doTest(
|
|
37
|
+
page, withItems, 'allSlanted', selector, whats, 0, null, getBadWhat.toString()
|
|
38
|
+
);
|
|
44
39
|
};
|
package/testaro/distortion.js
CHANGED
|
@@ -14,32 +14,30 @@
|
|
|
14
14
|
This test reports elements whose transform style properties distort the content. Distortion makes text difficult to read.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// IMPORTS
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const {simplify} = require('../procs/testaro');
|
|
19
|
+
const {doTest} = require('../procs/testaro');
|
|
21
20
|
|
|
22
|
-
//
|
|
21
|
+
// FUNCTIONS
|
|
23
22
|
|
|
24
23
|
// Runs the test and returns the result.
|
|
25
24
|
exports.reporter = async (page, withItems) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
ordinalSeverity: 1,
|
|
41
|
-
summaryTagName: ''
|
|
25
|
+
const getBadWhat = element => {
|
|
26
|
+
const styleDec = window.getComputedStyle(element);
|
|
27
|
+
const {transform} = styleDec;
|
|
28
|
+
const badTransformTypes = ['matrix', 'perspective', 'rotate', 'scale', 'skew'];
|
|
29
|
+
// If the element style transforms the text:
|
|
30
|
+
if (transform) {
|
|
31
|
+
const transformType = badTransformTypes.find(key => transform.includes(key));
|
|
32
|
+
// If the transformation is distortive:
|
|
33
|
+
if (transformType) {
|
|
34
|
+
// Return a violation description.
|
|
35
|
+
return `Element distorts its text with ${transformType} transformation`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
42
38
|
};
|
|
43
|
-
|
|
44
|
-
return await
|
|
39
|
+
const whats = 'Elements distort their texts';
|
|
40
|
+
return await doTest(
|
|
41
|
+
page, withItems, 'distortion', 'body *', whats, 0, null, getBadWhat.toString()
|
|
42
|
+
);
|
|
45
43
|
};
|
package/testaro/focAndOp.js
CHANGED
|
@@ -70,19 +70,18 @@ exports.reporter = async (page, withItems) => {
|
|
|
70
70
|
]);
|
|
71
71
|
// Initialize the operabilities of the element.
|
|
72
72
|
const opHow = [];
|
|
73
|
-
let hasPointer = false;
|
|
74
73
|
// If the element is not a label:
|
|
75
74
|
if (element.tagName !== 'LABEL') {
|
|
76
|
-
const
|
|
77
|
-
hasPointer = styleDec.cursor === 'pointer';
|
|
75
|
+
const liveStyleDec = window.getComputedStyle(element);
|
|
78
76
|
// If it has a pointer cursor:
|
|
79
|
-
if (
|
|
77
|
+
if (liveStyleDec.cursor === 'pointer') {
|
|
80
78
|
// Neutralize the cursor style of the parent element of the element.
|
|
81
79
|
element.parentElement.style.cursor = 'default';
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
// If, after this, the element still has a pointer cursor:
|
|
81
|
+
if (liveStyleDec.cursor === 'pointer') {
|
|
82
|
+
// Add this to the operabilities of the element.
|
|
83
|
+
opHow.push('pointer cursor');
|
|
84
|
+
}
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
// If the element has a click event listener:
|
package/testaro/hover.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
/*
|
|
12
12
|
hover
|
|
13
|
-
This test reports unexpected impacts of hovering. The elements that are subjected to hovering (called “triggers”) include all the elements that have attributes associated with control over the visibility of other elements. If hovering over an element results in an increase or decrease in the total count of visible elements in the tree rooted in the grandparent of the trigger, the rule is considered violated.
|
|
13
|
+
This test reports unexpected impacts of hovering. The elements that are subjected to hovering (called “triggers”) include all the elements that have attributes associated with control over the visibility of other elements. If hovering over an element results in an increase or decrease in the total count of visible elements in the tree rooted in the grandparent of the trigger, the rule is considered violated. This test uses the getBasicResult function in order to use Playwright for the most realistic hover simulation.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
// IMPORTS
|
package/testaro/hr.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
|
+
https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
hr
|
|
13
|
+
This test reports the use of hr elements.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// IMPORTS
|
|
17
|
+
|
|
18
|
+
const {doTest} = require('../procs/testaro');
|
|
19
|
+
|
|
20
|
+
// FUNCTIONS
|
|
21
|
+
|
|
22
|
+
// Runs the test and returns the result.
|
|
23
|
+
exports.reporter = async (page, withItems) => {
|
|
24
|
+
const getBadWhat = element => {
|
|
25
|
+
// Return a violation description.
|
|
26
|
+
return `hr element is used for vertical segmentation`;
|
|
27
|
+
}
|
|
28
|
+
const whats = 'HR elements are used for vertical segmentation';
|
|
29
|
+
return await doTest(
|
|
30
|
+
page, withItems, 'hr', 'hr', whats, 0, 'HR', getBadWhat.toString()
|
|
31
|
+
);
|
|
32
|
+
};
|
package/testaro/imageLink.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
3
|
© 2025 Juan S. Casado.
|
|
4
|
+
© 2025 Jonathan Robert Pool
|
|
4
5
|
|
|
5
6
|
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
7
|
https://opensource.org/license/mit/ for details.
|
|
@@ -11,25 +12,27 @@
|
|
|
11
12
|
/*
|
|
12
13
|
imageLink
|
|
13
14
|
Clean-room rule.
|
|
14
|
-
This test reports
|
|
15
|
+
This test reports links whose destinations are image files.
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
// IMPORTS
|
|
18
19
|
|
|
20
|
+
const {doTest} = require('../procs/testaro');
|
|
21
|
+
|
|
22
|
+
// FUNCTIONS
|
|
23
|
+
|
|
24
|
+
// Runs the test and returns the result.
|
|
19
25
|
exports.reporter = async (page, withItems) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
complaints: {
|
|
28
|
-
instance: 'Link destination is an image file',
|
|
29
|
-
summary: 'Links have image files as their destinations'
|
|
30
|
-
},
|
|
31
|
-
ordinalSeverity: 0,
|
|
32
|
-
summaryTagName: 'A'
|
|
26
|
+
const getBadWhat = element => {
|
|
27
|
+
const href = element.getAttribute('href') || '';
|
|
28
|
+
// If the destination of the element is an image file:
|
|
29
|
+
if (/\.(?:png|jpe?g|gif|svg|webp|ico)(?:$|[?#])/i.test(href)) {
|
|
30
|
+
// Return a violation description.
|
|
31
|
+
return 'Link destination is an image file';
|
|
32
|
+
}
|
|
33
33
|
};
|
|
34
|
-
|
|
34
|
+
const whats = 'Links have image files as their destinations';
|
|
35
|
+
return await doTest(
|
|
36
|
+
page, withItems, 'imageLink', 'a[href]', whats, 0, 'A', getBadWhat.toString()
|
|
37
|
+
);
|
|
35
38
|
};
|
package/testaro/legendLoc.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
3
|
© 2025 Juan S. Casado.
|
|
4
|
+
© 2025 Jonathan Robert Pool.
|
|
4
5
|
|
|
5
6
|
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
7
|
https://opensource.org/license/mit/ for details.
|
|
@@ -14,30 +15,24 @@
|
|
|
14
15
|
This test reports legend elements that are not the first children of fieldset elements.
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
// IMPORTS
|
|
18
19
|
|
|
20
|
+
const {doTest} = require('../procs/testaro');
|
|
21
|
+
|
|
22
|
+
// FUNCTIONS
|
|
23
|
+
|
|
24
|
+
// Runs the test and returns the result.
|
|
19
25
|
exports.reporter = async (page, withItems) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Check if this legend is the first element child of the fieldset
|
|
28
|
-
for (const child of parent.children) {
|
|
29
|
-
if (child.nodeType === 1) {
|
|
30
|
-
return child !== el; // true if not first child
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return true;
|
|
34
|
-
}),
|
|
35
|
-
complaints: {
|
|
36
|
-
instance: 'Element is not the first child of a fieldset element',
|
|
37
|
-
summary: 'legend elements are not the first children of fieldset elements'
|
|
38
|
-
},
|
|
39
|
-
ordinalSeverity: 3,
|
|
40
|
-
summaryTagName: 'LEGEND'
|
|
26
|
+
const getBadWhat = element => {
|
|
27
|
+
const parent = element.parentElement;
|
|
28
|
+
// If the element violates the rule:
|
|
29
|
+
if (! (parent && parent.tagName === 'FIELDSET' && parent.firstElementChild === element)) {
|
|
30
|
+
// Return a violation description.
|
|
31
|
+
return 'Element is not the first child of a fieldset element';
|
|
32
|
+
}
|
|
41
33
|
};
|
|
42
|
-
|
|
34
|
+
const whats = 'Legend elements are not the first children of fieldset elements';
|
|
35
|
+
return await doTest(
|
|
36
|
+
page, withItems, 'legendLoc', 'legend', whats, 3, 'LEGEND', getBadWhat.toString()
|
|
37
|
+
);
|
|
43
38
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
|
+
https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
linkExt
|
|
13
|
+
This test reports links with target=_blank attributes.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// IMPORTS
|
|
17
|
+
|
|
18
|
+
const {doTest} = require('../procs/testaro');
|
|
19
|
+
|
|
20
|
+
// FUNCTIONS
|
|
21
|
+
|
|
22
|
+
exports.reporter = async (page, withItems) => {
|
|
23
|
+
const getBadWhat = element => {
|
|
24
|
+
// Return a violation description.
|
|
25
|
+
return `Link has a target=_blank attribute`;
|
|
26
|
+
};
|
|
27
|
+
const whats = 'Links have target=_blank attributes';
|
|
28
|
+
return await doTest(
|
|
29
|
+
page, withItems, 'linkExt', 'a[target=_blank]', whats, 0, 'A', getBadWhat.toString()
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
|
+
https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
linkOldAtt
|
|
13
|
+
This test reports links with deprecated attributes.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// IMPORTS
|
|
17
|
+
|
|
18
|
+
const {doTest} = require('../procs/testaro');
|
|
19
|
+
|
|
20
|
+
// FUNCTIONS
|
|
21
|
+
|
|
22
|
+
exports.reporter = async (page, withItems) => {
|
|
23
|
+
const getBadWhat = element => {
|
|
24
|
+
const attNames = element.getAttributeNames();
|
|
25
|
+
const allBadAttNames = ['charset', 'coords', 'name', 'rev', 'shape'];
|
|
26
|
+
const elementBadAttNames = allBadAttNames.filter(att => attNames.includes(att));
|
|
27
|
+
// If the element has 1 deprecated attribute:
|
|
28
|
+
if (elementBadAttNames.length === 1) {
|
|
29
|
+
// Return a violation description.
|
|
30
|
+
return `${elementBadAttNames[0]} attribute is deprecated`;
|
|
31
|
+
}
|
|
32
|
+
// Otherwise, if the element has 2 or more deprecated attributes:
|
|
33
|
+
if (elementBadAttNames.length > 1) {
|
|
34
|
+
// Return a violation description.
|
|
35
|
+
return `Element has deprecated attributes: ${elementBadAttNames.join(', ')}`;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const selector = 'a[charset], a[coords], a[name], a[rev], a[shape]';
|
|
39
|
+
const whats = 'Links have deprecated attributes';
|
|
40
|
+
return await doTest(
|
|
41
|
+
page, withItems, 'linkOldAtt', selector, whats, 1, 'A', getBadWhat.toString()
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
|
+
https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
/*
|
|
11
|
+
linkTo
|
|
12
|
+
This test reports links without href attributes.
|
|
13
|
+
*/
|
|
14
|
+
// IMPORTS
|
|
15
|
+
|
|
16
|
+
const {doTest} = require('../procs/testaro');
|
|
17
|
+
|
|
18
|
+
// FUNCTIONS
|
|
19
|
+
|
|
20
|
+
exports.reporter = async (page, withItems) => {
|
|
21
|
+
const getBadWhat = element => {
|
|
22
|
+
const isVisible = element.checkVisibility({
|
|
23
|
+
contentVisibilityAuto: true,
|
|
24
|
+
opacityProperty: true,
|
|
25
|
+
visibilityProperty: true
|
|
26
|
+
});
|
|
27
|
+
// If the element is visible:
|
|
28
|
+
if (isVisible) {
|
|
29
|
+
// Return a violation description.
|
|
30
|
+
return `Element has no href attribute`;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const whats = 'Links are missing href attributes';
|
|
34
|
+
return await doTest(
|
|
35
|
+
page, withItems, 'linkTo', 'a:not([href]', whats, 2, 'A', getBadWhat.toString()
|
|
36
|
+
);
|
|
37
|
+
};
|