testaro 67.0.0 → 68.0.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/LICENSE +4 -16
- package/README.md +10 -2
- package/UPGRADES.md +1 -1
- package/dirWatch.js +2 -3
- package/ed11y/editoria11y.min.js +109 -690
- package/ed11y/editoria11y210.min.js +747 -0
- package/netWatch.js +6 -6
- package/package.json +1 -1
- package/procs/aslint.js +2 -2
- package/procs/catalog.js +190 -0
- package/procs/{dateOf.js → dateTime.js} +6 -4
- package/procs/doActs.js +1227 -0
- package/procs/doTestAct.js +63 -29
- package/procs/error.js +53 -0
- package/procs/job.js +64 -38
- package/procs/launch.js +596 -0
- package/procs/nu.js +3 -18
- package/procs/shoot.js +18 -2
- package/procs/testaro.js +102 -125
- package/procs/xPath.js +62 -0
- package/run.js +42 -1938
- package/scratch/README.md +9 -0
- package/testaro/adbID.js +3 -3
- package/testaro/allCaps.js +4 -5
- package/testaro/allHidden.js +19 -18
- package/testaro/allSlanted.js +4 -5
- package/testaro/altScheme.js +3 -3
- package/testaro/attVal.js +19 -35
- package/testaro/autocomplete.js +65 -62
- package/testaro/bulk.js +21 -20
- package/testaro/buttonMenu.js +112 -33
- package/testaro/captionLoc.js +3 -3
- package/testaro/datalistRef.js +4 -5
- package/testaro/distortion.js +3 -3
- package/testaro/docType.js +6 -9
- package/testaro/dupAtt.js +12 -25
- package/testaro/elements.js +4 -3
- package/testaro/embAc.js +4 -2
- package/testaro/focAll.js +6 -13
- package/testaro/focAndOp.js +3 -3
- package/testaro/focInd.js +3 -3
- package/testaro/focVis.js +4 -3
- package/testaro/headEl.js +5 -12
- package/testaro/headingAmb.js +45 -88
- package/testaro/hovInd.js +5 -5
- package/testaro/hover.js +44 -8
- package/testaro/hr.js +4 -4
- package/testaro/imageLink.js +3 -3
- package/testaro/labClash.js +3 -3
- package/testaro/legendLoc.js +3 -3
- package/testaro/lineHeight.js +3 -3
- package/testaro/linkAmb.js +25 -17
- package/testaro/linkExt.js +5 -5
- package/testaro/linkOldAtt.js +4 -3
- package/testaro/linkTo.js +4 -3
- package/testaro/linkUl.js +4 -5
- package/testaro/miniText.js +4 -3
- package/testaro/motion.js +3 -22
- package/testaro/nonTable.js +4 -5
- package/testaro/optRoleSel.js +3 -3
- package/testaro/phOnly.js +3 -3
- package/testaro/pseudoP.js +5 -5
- package/testaro/radioSet.js +4 -5
- package/testaro/role.js +4 -5
- package/testaro/secHeading.js +4 -5
- package/testaro/shoot0.js +3 -2
- package/testaro/shoot1.js +3 -2
- package/testaro/styleDiff.js +5 -12
- package/testaro/tabNav.js +30 -118
- package/testaro/targetSmall.js +30 -15
- package/testaro/textNodes.js +3 -1
- package/testaro/textSem.js +4 -5
- package/testaro/title.js +4 -2
- package/testaro/titledEl.js +3 -3
- package/testaro/zIndex.js +3 -3
- package/tests/alfa.js +28 -54
- package/tests/aslint.js +20 -53
- package/tests/axe.js +76 -13
- package/tests/ed11y.js +69 -141
- package/tests/htmlcs.js +69 -38
- package/tests/ibm.js +54 -9
- package/tests/nuVal.js +65 -12
- package/tests/nuVnu.js +76 -26
- package/tests/qualWeb.js +89 -44
- package/tests/testaro.js +288 -273
- package/tests/wave.js +142 -117
- package/tests/wax.js +61 -42
- package/procs/getLocatorData.js +0 -192
- package/procs/identify.js +0 -250
- package/procs/isInlineLink.js +0 -42
- package/procs/screenShot.js +0 -32
- package/procs/standardize.js +0 -524
- package/procs/target.js +0 -90
- package/procs/tellServer.js +0 -43
- package/scripts/dumpAlts.js +0 -28
package/procs/doTestAct.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2024–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
-
© 2025 Jonathan Robert Pool.
|
|
3
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
4
4
|
|
|
5
5
|
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
6
|
https://opensource.org/license/mit/ for details.
|
|
@@ -9,18 +9,55 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/*
|
|
12
|
-
|
|
12
|
+
doActs
|
|
13
13
|
Performs the tests of an act.
|
|
14
|
+
This file is designed to be run as a child process.
|
|
14
15
|
*/
|
|
15
16
|
|
|
17
|
+
// ERROR LOGGING
|
|
18
|
+
|
|
19
|
+
// Log uncaught exceptions.
|
|
20
|
+
process.on('uncaughtException', error => {
|
|
21
|
+
console.error(`ERROR:\n${error.stack || 'Uncaught exception'}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Log unhandled rejections.
|
|
26
|
+
process.on('unhandledRejection', reason => {
|
|
27
|
+
console.error(`ERROR:\n${reason?.stack || 'Unhandled rejection'}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
|
|
16
31
|
// IMPORTS
|
|
17
32
|
|
|
18
33
|
// Module to perform file operations.
|
|
19
34
|
const fs = require('fs/promises');
|
|
20
|
-
//
|
|
21
|
-
const {browserClose, launch} = require(
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
// Module to close and launch browsers.
|
|
36
|
+
const {browserClose, launch} = require('./launch');
|
|
37
|
+
|
|
38
|
+
// CONSTANTS
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
Tool XPath requirements.
|
|
42
|
+
none: Needs no script or extra load time.
|
|
43
|
+
own: Needs extra load time for its own XPath computations.
|
|
44
|
+
script: Needs the window.getXPath script.
|
|
45
|
+
attribute: Needs data-xpath attributes made with window.getXPath.
|
|
46
|
+
*/
|
|
47
|
+
const xPathNeeds = {
|
|
48
|
+
alfa: 'own',
|
|
49
|
+
aslint: 'own',
|
|
50
|
+
axe: 'attribute',
|
|
51
|
+
ed11y: 'script',
|
|
52
|
+
htmlcs: 'attribute',
|
|
53
|
+
ibm: 'attribute',
|
|
54
|
+
nuVal: 'attribute',
|
|
55
|
+
nuVnu: 'attribute',
|
|
56
|
+
qualWeb: 'attribute',
|
|
57
|
+
wave: 'script',
|
|
58
|
+
wax: 'attribute'
|
|
59
|
+
};
|
|
60
|
+
const accessibleNameNeeders = ['testaro'];
|
|
24
61
|
|
|
25
62
|
// FUNCTIONS
|
|
26
63
|
|
|
@@ -52,19 +89,20 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
52
89
|
const browserID = act.launch && act.launch.browserID || report.browserID;
|
|
53
90
|
const targetURL = act.launch && act.launch.target && act.launch.target.url || report.target.url;
|
|
54
91
|
// Launch a browser, navigate to the URL, and update the run-module page export.
|
|
55
|
-
await launch(
|
|
92
|
+
page = await launch({
|
|
56
93
|
report,
|
|
57
94
|
actIndex,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
95
|
+
tempBrowserID: browserID,
|
|
96
|
+
tempURL: targetURL,
|
|
97
|
+
xPathNeed: xPathNeeds[which] ?? 'none',
|
|
98
|
+
needsAccessibleName: accessibleNameNeeders.includes(which)
|
|
99
|
+
});
|
|
62
100
|
// If the launch aborted the job:
|
|
63
|
-
if (report.jobData
|
|
64
|
-
// Close
|
|
65
|
-
await browserClose();
|
|
66
|
-
// Save the revised report.
|
|
101
|
+
if (report.jobData?.aborted) {
|
|
102
|
+
// Close the browser and its context, if they exist.
|
|
103
|
+
await browserClose(page);
|
|
67
104
|
const reportJSON = JSON.stringify(report);
|
|
105
|
+
// Save the revised report.
|
|
68
106
|
await fs.writeFile(reportPath, reportJSON);
|
|
69
107
|
// Report this.
|
|
70
108
|
sendMessage({
|
|
@@ -73,11 +111,6 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
73
111
|
});
|
|
74
112
|
process.exit(1);
|
|
75
113
|
}
|
|
76
|
-
// Otherwise, i.e. if the launch did not abort the job:
|
|
77
|
-
else {
|
|
78
|
-
// Get the updated page.
|
|
79
|
-
page = require('../run').page;
|
|
80
|
-
}
|
|
81
114
|
}
|
|
82
115
|
// If the page exists or the tool is Testaro:
|
|
83
116
|
if (page || which === 'testaro') {
|
|
@@ -89,11 +122,16 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
89
122
|
act.result = actReport.result;
|
|
90
123
|
// If the tool reported that the page prevented testing:
|
|
91
124
|
if (act.data && act.data.prevented) {
|
|
125
|
+
const {standardResult} = act.result;
|
|
126
|
+
// Add this to any standard result.
|
|
127
|
+
if (standardResult) {
|
|
128
|
+
standardResult.prevented = true;
|
|
129
|
+
}
|
|
92
130
|
// Add prevention data to the job data.
|
|
93
131
|
report.jobData.preventions[which] = act.data.error;
|
|
94
132
|
}
|
|
95
|
-
// Close
|
|
96
|
-
await browserClose();
|
|
133
|
+
// Close the browser and its context, if they exist.
|
|
134
|
+
await browserClose(page);
|
|
97
135
|
const reportJSON = JSON.stringify(report);
|
|
98
136
|
// Save the revised report.
|
|
99
137
|
await fs.writeFile(reportPath, reportJSON);
|
|
@@ -105,8 +143,8 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
105
143
|
}
|
|
106
144
|
// If the tool invocation failed:
|
|
107
145
|
catch(error) {
|
|
108
|
-
// Close
|
|
109
|
-
await browserClose();
|
|
146
|
+
// Close the browser and its context, if they exist.
|
|
147
|
+
await browserClose(page);
|
|
110
148
|
// Save the revised report.
|
|
111
149
|
const reportJSON = JSON.stringify(report);
|
|
112
150
|
await fs.writeFile(reportPath, reportJSON);
|
|
@@ -128,8 +166,6 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
128
166
|
act.data.error = 'No page';
|
|
129
167
|
// Add prevention data to the job data.
|
|
130
168
|
report.jobData.preventions[which] = act.data.error;
|
|
131
|
-
// Close any existing browser.
|
|
132
|
-
await browserClose();
|
|
133
169
|
const reportJSON = JSON.stringify(report);
|
|
134
170
|
// Save the revised report.
|
|
135
171
|
await fs.writeFile(reportPath, reportJSON);
|
|
@@ -143,7 +179,6 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
143
179
|
process.exit(1);
|
|
144
180
|
}
|
|
145
181
|
};
|
|
146
|
-
|
|
147
182
|
process.on('uncaughtException', error => {
|
|
148
183
|
console.log(`ERROR: uncaughtException (${error.message})`);
|
|
149
184
|
sendMessage({
|
|
@@ -152,7 +187,6 @@ process.on('uncaughtException', error => {
|
|
|
152
187
|
});
|
|
153
188
|
process.exit(1);
|
|
154
189
|
});
|
|
155
|
-
|
|
156
190
|
process.on('unhandledRejection', error => {
|
|
157
191
|
const message = error && error.message ? error.message : String(error);
|
|
158
192
|
console.log(`ERROR: unhandledRejection (${message})`);
|
|
@@ -162,6 +196,6 @@ process.on('unhandledRejection', error => {
|
|
|
162
196
|
});
|
|
163
197
|
process.exit(1);
|
|
164
198
|
});
|
|
165
|
-
|
|
166
199
|
const args = process.argv;
|
|
200
|
+
// Perform the specified test act.
|
|
167
201
|
doTestAct(args[2], Number.parseInt(args[3]));
|
package/procs/error.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2021–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
|
|
6
|
+
|
|
7
|
+
SPDX-License-Identifier: MIT
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
error.js
|
|
12
|
+
Handles errors.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Reports a job being aborted.
|
|
16
|
+
const abortActs = exports.abortActs = (report, actIndex) => {
|
|
17
|
+
// Add data on the aborted act to the report.
|
|
18
|
+
report.jobData.abortTime = nowString();
|
|
19
|
+
report.jobData.abortedAct = actIndex;
|
|
20
|
+
report.jobData.aborted = true;
|
|
21
|
+
// Report that the job is aborted.
|
|
22
|
+
console.log(`ERROR: Job aborted on act ${actIndex}`);
|
|
23
|
+
};
|
|
24
|
+
// Adds an error result to an act.
|
|
25
|
+
exports.addError = (alsoLog, alsoAbort, report, actIndex, message) => {
|
|
26
|
+
// If the error is to be logged:
|
|
27
|
+
if (alsoLog) {
|
|
28
|
+
// Log it.
|
|
29
|
+
console.log(message);
|
|
30
|
+
}
|
|
31
|
+
const act = report.acts[actIndex ?? -1];
|
|
32
|
+
// If an act was specified:
|
|
33
|
+
if (act) {
|
|
34
|
+
// Add error data to the result.
|
|
35
|
+
act.result ??= {};
|
|
36
|
+
act.result.success ??= false;
|
|
37
|
+
act.result.error ??= message;
|
|
38
|
+
// If the act is a test act:
|
|
39
|
+
if (act.type === 'test') {
|
|
40
|
+
act.data ??= {};
|
|
41
|
+
// Add prevention data to the act data.
|
|
42
|
+
act.data.prevented = true;
|
|
43
|
+
act.data.error = message;
|
|
44
|
+
// Add prevention data to the job data.
|
|
45
|
+
report.jobData.preventions[act.which] = message;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
// If the job is to be aborted:
|
|
49
|
+
if (alsoAbort) {
|
|
50
|
+
// Add this to the report.
|
|
51
|
+
abortActs(report, actIndex);
|
|
52
|
+
}
|
|
53
|
+
};
|
package/procs/job.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jonathan Robert Pool.
|
|
3
4
|
|
|
4
|
-
Licensed under the MIT License. See LICENSE file at the project root or
|
|
5
|
-
https://opensource.org/license/mit/ for details.
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
|
|
6
6
|
|
|
7
7
|
SPDX-License-Identifier: MIT
|
|
8
8
|
*/
|
|
@@ -19,20 +19,20 @@ const {actSpecs} = require('../actSpecs');
|
|
|
19
19
|
// Data on devices.
|
|
20
20
|
const {devices} = require('playwright');
|
|
21
21
|
// Module to get dates from time stamps.
|
|
22
|
-
const {dateOf} = require('./
|
|
22
|
+
const {dateOf} = require('./dateTime');
|
|
23
23
|
|
|
24
24
|
// CONSTANTS
|
|
25
25
|
|
|
26
26
|
// Names and descriptions of tools.
|
|
27
|
-
const tools = exports.tools ={
|
|
27
|
+
const tools = exports.tools = {
|
|
28
28
|
alfa: 'Alfa',
|
|
29
29
|
aslint: 'ASLint',
|
|
30
30
|
axe: 'Axe',
|
|
31
31
|
ed11y: 'Editoria11y',
|
|
32
|
-
htmlcs: 'HTML CodeSniffer
|
|
33
|
-
ibm: '
|
|
34
|
-
nuVal: '
|
|
35
|
-
nuVnu: '
|
|
32
|
+
htmlcs: 'HTML CodeSniffer',
|
|
33
|
+
ibm: 'Accessibility Checker',
|
|
34
|
+
nuVal: 'Html Checker API',
|
|
35
|
+
nuVnu: 'Html Checker',
|
|
36
36
|
qualWeb: 'QualWeb',
|
|
37
37
|
testaro: 'Testaro',
|
|
38
38
|
wax: 'WallyAX',
|
|
@@ -167,7 +167,7 @@ const isValidAct = exports.isValidAct = act => {
|
|
|
167
167
|
return false;
|
|
168
168
|
}
|
|
169
169
|
};
|
|
170
|
-
// Returns
|
|
170
|
+
// Returns whether a job is valid and, if not, why not.
|
|
171
171
|
exports.isValidJob = job => {
|
|
172
172
|
// If any job was provided:
|
|
173
173
|
if (job) {
|
|
@@ -187,38 +187,68 @@ exports.isValidJob = job => {
|
|
|
187
187
|
} = job;
|
|
188
188
|
// Return an error for the first missing or invalid property.
|
|
189
189
|
if (! id || typeof id !== 'string') {
|
|
190
|
-
return
|
|
190
|
+
return {
|
|
191
|
+
isValid: false,
|
|
192
|
+
error: 'Bad job ID'
|
|
193
|
+
};
|
|
191
194
|
}
|
|
192
195
|
if (typeof strict !== 'boolean') {
|
|
193
|
-
return
|
|
196
|
+
return {
|
|
197
|
+
isValid: false,
|
|
198
|
+
error: 'Bad job strict'
|
|
199
|
+
};
|
|
194
200
|
}
|
|
195
201
|
if (! ['also', 'only', 'no'].includes(standard)) {
|
|
196
|
-
return
|
|
202
|
+
return {
|
|
203
|
+
isValid: false,
|
|
204
|
+
error: 'Bad job standard'
|
|
205
|
+
};
|
|
197
206
|
}
|
|
198
207
|
if (typeof observe !== 'boolean') {
|
|
199
|
-
return
|
|
208
|
+
return {
|
|
209
|
+
isValid: false,
|
|
210
|
+
error: 'Bad job observe'
|
|
211
|
+
}
|
|
200
212
|
}
|
|
201
213
|
if (! isDeviceID(device.id)) {
|
|
202
|
-
return
|
|
214
|
+
return {
|
|
215
|
+
isValid: false,
|
|
216
|
+
error: 'Bad job deviceID'
|
|
217
|
+
};
|
|
203
218
|
}
|
|
204
219
|
if (! isBrowserID(browserID)) {
|
|
205
|
-
return
|
|
220
|
+
return {
|
|
221
|
+
isValid: false,
|
|
222
|
+
error: 'Bad job browserID'
|
|
223
|
+
};
|
|
206
224
|
}
|
|
207
225
|
if (
|
|
208
226
|
! (creationTimeStamp && typeof creationTimeStamp === 'string' && dateOf(creationTimeStamp))
|
|
209
227
|
) {
|
|
210
|
-
return
|
|
228
|
+
return {
|
|
229
|
+
isValid: false,
|
|
230
|
+
error: 'Bad job creationTimeStamp'
|
|
231
|
+
};
|
|
211
232
|
}
|
|
212
233
|
if (
|
|
213
234
|
! (executionTimeStamp && typeof executionTimeStamp === 'string') && dateOf(executionTimeStamp)
|
|
214
235
|
) {
|
|
215
|
-
return
|
|
236
|
+
return {
|
|
237
|
+
isValid: false,
|
|
238
|
+
error: 'Bad job executionTimeStamp'
|
|
239
|
+
};
|
|
216
240
|
}
|
|
217
241
|
if (typeof target !== 'object' || target.url && ! isURL(target.url) || target.what === '') {
|
|
218
|
-
return
|
|
242
|
+
return {
|
|
243
|
+
isValid: false,
|
|
244
|
+
error: 'Bad job target'
|
|
245
|
+
};
|
|
219
246
|
}
|
|
220
247
|
if (sources && typeof sources !== 'object') {
|
|
221
|
-
return
|
|
248
|
+
return {
|
|
249
|
+
isValid: false,
|
|
250
|
+
error: 'Bad job sources'
|
|
251
|
+
};
|
|
222
252
|
}
|
|
223
253
|
if (
|
|
224
254
|
! acts
|
|
@@ -226,32 +256,28 @@ exports.isValidJob = job => {
|
|
|
226
256
|
|| ! acts.length
|
|
227
257
|
|| ! acts.every(act => act.type && typeof act.type === 'string')
|
|
228
258
|
) {
|
|
229
|
-
return
|
|
259
|
+
return {
|
|
260
|
+
isValid: false,
|
|
261
|
+
error: 'Bad job acts'
|
|
262
|
+
};
|
|
230
263
|
}
|
|
231
264
|
const invalidAct = acts.find(act => ! isValidAct(act));
|
|
232
265
|
if (invalidAct) {
|
|
233
|
-
return
|
|
266
|
+
return {
|
|
267
|
+
isValid: false,
|
|
268
|
+
error: `Invalid act:\n${JSON.stringify(invalidAct, null, 2)}`
|
|
269
|
+
};
|
|
234
270
|
}
|
|
235
|
-
return
|
|
271
|
+
return {
|
|
272
|
+
isValid: true
|
|
273
|
+
};
|
|
236
274
|
}
|
|
237
275
|
// Otherwise, i.e. if no job was provided:
|
|
238
276
|
else {
|
|
239
277
|
// Return this.
|
|
240
|
-
return
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
exports.cap = rawString => {
|
|
245
|
-
const string = (rawString.trim() || '').replace(/[\s\u2028\u2029]+/g, ' ');
|
|
246
|
-
if (string && string.length > 1000) {
|
|
247
|
-
return `${string.slice(0, 500)} … ${string.slice(-500)}`;
|
|
248
|
-
}
|
|
249
|
-
else if (string) {
|
|
250
|
-
return string;
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
return '';
|
|
278
|
+
return {
|
|
279
|
+
isValid: false,
|
|
280
|
+
error: 'No job'
|
|
281
|
+
};
|
|
254
282
|
}
|
|
255
283
|
};
|
|
256
|
-
// Simplifies the spacing of a string.
|
|
257
|
-
exports.tidy = string => string.replace(/\s+/g, ' ');
|