testaro 60.3.0 → 60.4.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/screenShot.js +32 -0
- package/procs/testaro.js +4 -2
- package/procs/visChange.js +7 -25
- package/run.js +118 -43
- package/testaro/adbID.js +2 -2
- package/testaro/altScheme.js +2 -2
- package/testaro/attVal.js +2 -2
- package/testaro/autocomplete.js +2 -2
- package/testaro/captionLoc.js +2 -2
- package/testaro/datalistRef.js +2 -2
- package/testaro/embAc.js +2 -2
- package/testaro/focInd.js +2 -2
- package/testaro/focOp.js +2 -2
- package/testaro/focVis.js +2 -2
- package/testaro/hover.js +2 -2
- package/testaro/labClash.js +2 -2
- package/testaro/lineHeight.js +2 -2
- package/testaro/linkAmb.js +2 -2
- package/testaro/miniText.js +2 -2
- package/testaro/motion.js +67 -59
- package/testaro/motionSolo.js +94 -0
- package/testaro/opFoc.js +2 -2
- package/testaro/phOnly.js +2 -2
- package/testaro/pseudoP.js +2 -2
- package/testaro/radioSet.js +2 -2
- package/testaro/role.js +2 -2
- package/testaro/secHeading.js +2 -2
- package/testaro/shoot.js +57 -0
- package/testaro/targetSmall.js +2 -2
- package/testaro/targetTiny.js +2 -2
- package/testaro/textSem.js +2 -2
- package/testaro/zIndex.js +2 -2
- package/tests/testaro.js +608 -296
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
4
|
+
Licensed under the MIT License. See LICENSE file for details.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
screenShot
|
|
9
|
+
This procedure creates and returns a full-page screenshot, optionally with an exclused element.
|
|
10
|
+
This procedure uses the Playwright page.screenshot method, which is not implemented for the
|
|
11
|
+
firefox browser type.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// FUNCTIONS
|
|
15
|
+
|
|
16
|
+
// Creates and returns a screenshot.
|
|
17
|
+
exports.screenShot = async (page, exclusion = null) => {
|
|
18
|
+
const options = {
|
|
19
|
+
fullPage: true,
|
|
20
|
+
omitBackground: true,
|
|
21
|
+
timeout: 2000
|
|
22
|
+
};
|
|
23
|
+
if (exclusion) {
|
|
24
|
+
options.mask = [exclusion];
|
|
25
|
+
}
|
|
26
|
+
// Make and return a screenshot as a buffer.
|
|
27
|
+
return await page.screenshot(options)
|
|
28
|
+
.catch(error => {
|
|
29
|
+
console.log(`ERROR: Screenshot failed (${error.message})`);
|
|
30
|
+
return '';
|
|
31
|
+
});
|
|
32
|
+
};
|
package/procs/testaro.js
CHANGED
|
@@ -68,7 +68,9 @@ const init = exports.init = async (sampleMax, page, locAllSelector, options = {}
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
// Populates and returns a result.
|
|
71
|
-
const
|
|
71
|
+
const getRuleResult = exports.getRuleResult = async (
|
|
72
|
+
withItems, all, ruleID, whats, ordinalSeverity, tagName = ''
|
|
73
|
+
) => {
|
|
72
74
|
const {locs, result} = all;
|
|
73
75
|
const {data, totals, standardInstances} = result;
|
|
74
76
|
// For each violation locator:
|
|
@@ -149,7 +151,7 @@ exports.simplify = async (page, withItems, ruleData) => {
|
|
|
149
151
|
complaints.instance,
|
|
150
152
|
complaints.summary
|
|
151
153
|
];
|
|
152
|
-
const result = await
|
|
154
|
+
const result = await getRuleResult(withItems, all, ruleID, whats, ordinalSeverity, summaryTagName);
|
|
153
155
|
// Return the result.
|
|
154
156
|
return result;
|
|
155
157
|
};
|
package/procs/visChange.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
© 2023–
|
|
2
|
+
© 2023–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool. All rights reserved.
|
|
3
4
|
|
|
4
5
|
MIT License
|
|
5
6
|
|
|
@@ -25,37 +26,18 @@
|
|
|
25
26
|
/*
|
|
26
27
|
visChange
|
|
27
28
|
This procedure reports a change in the visible content of a page between two times, optionally
|
|
28
|
-
hovering over a locator-defined element immediately after the first time.
|
|
29
|
-
|
|
30
|
-
WARNING: This test uses the Playwright page.screenshot method, which produces incorrect results
|
|
31
|
-
when the browser type is chromium and is not implemented for the firefox browser type. The only
|
|
32
|
-
browser type usable with this test is webkit.
|
|
29
|
+
hovering over a locator-defined element immediately after the first time. This test uses the
|
|
30
|
+
Playwright page.screenshot method, which is not implemented for the firefox browser type.
|
|
33
31
|
*/
|
|
34
32
|
|
|
35
33
|
// IMPORTS
|
|
36
34
|
|
|
37
35
|
const pixelmatch = require('pixelmatch').default;
|
|
38
36
|
const {PNG} = require('pngjs');
|
|
37
|
+
const {screenShot} = require('./screenShot');
|
|
39
38
|
|
|
40
39
|
// FUNCTIONS
|
|
41
40
|
|
|
42
|
-
// Creates and returns a screenshot.
|
|
43
|
-
const shoot = async (page, exclusion = null) => {
|
|
44
|
-
// Make a screenshot as a buffer.
|
|
45
|
-
const options = {
|
|
46
|
-
fullPage: true,
|
|
47
|
-
omitBackground: true,
|
|
48
|
-
timeout: 2000
|
|
49
|
-
};
|
|
50
|
-
if (exclusion) {
|
|
51
|
-
options.mask = [exclusion];
|
|
52
|
-
}
|
|
53
|
-
return await page.screenshot(options)
|
|
54
|
-
.catch(error => {
|
|
55
|
-
console.log(`ERROR: Screenshot failed (${error.message})`);
|
|
56
|
-
return '';
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
41
|
exports.visChange = async (page, options = {}) => {
|
|
60
42
|
const {delayBefore, delayBetween, exclusion} = options;
|
|
61
43
|
// Wait, if required.
|
|
@@ -74,7 +56,7 @@ exports.visChange = async (page, options = {}) => {
|
|
|
74
56
|
});
|
|
75
57
|
}
|
|
76
58
|
// Make and get a screenshot, excluding an element if specified.
|
|
77
|
-
const shot0 = await
|
|
59
|
+
const shot0 = await screenShot(page, exclusion);
|
|
78
60
|
// If it succeeded:
|
|
79
61
|
if (shot0.length) {
|
|
80
62
|
// If an exclusion was specified:
|
|
@@ -96,7 +78,7 @@ exports.visChange = async (page, options = {}) => {
|
|
|
96
78
|
// Wait as specified, or 3 seconds.
|
|
97
79
|
await page.waitForTimeout(delayBetween || 3000);
|
|
98
80
|
// Make and get another screenshot.
|
|
99
|
-
const shot1 = await
|
|
81
|
+
const shot1 = await screenShot(page, exclusion);
|
|
100
82
|
// If it succeeded:
|
|
101
83
|
if (shot1.length) {
|
|
102
84
|
// Get the shots as PNG images.
|
package/run.js
CHANGED
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
const fs = require('fs/promises');
|
|
35
35
|
// Module to keep secrets.
|
|
36
36
|
require('dotenv').config({quiet: true});
|
|
37
|
+
// Module to execute shell commands.
|
|
38
|
+
const {execSync} = require('child_process');
|
|
37
39
|
// Module to validate jobs.
|
|
38
40
|
const {isBrowserID, isDeviceID, isURL, isValidJob, tools} = require('./procs/job');
|
|
39
41
|
// Module to evade automation detection.
|
|
@@ -109,12 +111,12 @@ const tmpDir = os.tmpdir();
|
|
|
109
111
|
|
|
110
112
|
// Facts about the current session.
|
|
111
113
|
let actCount = 0;
|
|
112
|
-
let browserCloseIntentional = false;
|
|
113
114
|
// Facts about the current act.
|
|
114
115
|
let actIndex = 0;
|
|
115
116
|
let browser;
|
|
116
117
|
let browserContext;
|
|
117
118
|
let page;
|
|
119
|
+
let report;
|
|
118
120
|
let requestedURL = '';
|
|
119
121
|
|
|
120
122
|
// FUNCTIONS
|
|
@@ -241,25 +243,6 @@ const goTo = async (report, page, url, timeout, waitUntil) => {
|
|
|
241
243
|
};
|
|
242
244
|
}
|
|
243
245
|
};
|
|
244
|
-
// Closes the current browser.
|
|
245
|
-
const browserClose = async () => {
|
|
246
|
-
if (browser) {
|
|
247
|
-
browserCloseIntentional = true;
|
|
248
|
-
for (const context of browser.contexts()) {
|
|
249
|
-
try {
|
|
250
|
-
await context.close();
|
|
251
|
-
}
|
|
252
|
-
catch(error) {
|
|
253
|
-
console.log(
|
|
254
|
-
`ERROR trying to close context: ${error.message.slice(0, 200).replace(/\n.+/s, '')}`
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
await browser.close();
|
|
259
|
-
browserCloseIntentional = false;
|
|
260
|
-
browser = null;
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
246
|
// Adds an error result to an act.
|
|
264
247
|
const addError = (alsoLog, alsoAbort, report, actIndex, message) => {
|
|
265
248
|
// If the error is to be logged:
|
|
@@ -286,6 +269,25 @@ const addError = (alsoLog, alsoAbort, report, actIndex, message) => {
|
|
|
286
269
|
abortActs(report, actIndex);
|
|
287
270
|
}
|
|
288
271
|
};
|
|
272
|
+
// Closes the current browser.
|
|
273
|
+
const browserClose = async () => {
|
|
274
|
+
if (browser) {
|
|
275
|
+
browserCloseIntentional = true;
|
|
276
|
+
for (const context of browser.contexts()) {
|
|
277
|
+
try {
|
|
278
|
+
await context.close();
|
|
279
|
+
}
|
|
280
|
+
catch(error) {
|
|
281
|
+
console.log(
|
|
282
|
+
`ERROR trying to close context: ${error.message.slice(0, 200).replace(/\n.+/s, '')}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
await browser.close();
|
|
287
|
+
browserCloseIntentional = false;
|
|
288
|
+
browser = null;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
289
291
|
// Launches a browser and navigates to a URL.
|
|
290
292
|
const launch = exports.launch = async (
|
|
291
293
|
report, debug, waits, tempBrowserID, tempURL, retries = 2
|
|
@@ -854,7 +856,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
854
856
|
// Otherwise, if a current page exists:
|
|
855
857
|
else if (page) {
|
|
856
858
|
// If the act is navigation to a url:
|
|
857
|
-
if (
|
|
859
|
+
if (type === 'url') {
|
|
858
860
|
// Identify the URL.
|
|
859
861
|
const resolved = act.which.replace('__dirname', __dirname);
|
|
860
862
|
requestedURL = resolved;
|
|
@@ -888,7 +890,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
888
890
|
}
|
|
889
891
|
}
|
|
890
892
|
// Otherwise, if the act is a wait for text:
|
|
891
|
-
else if (
|
|
893
|
+
else if (type === 'wait') {
|
|
892
894
|
const {what, which} = act;
|
|
893
895
|
console.log(`>> ${what}`);
|
|
894
896
|
const result = act.result = {};
|
|
@@ -956,7 +958,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
956
958
|
}
|
|
957
959
|
}
|
|
958
960
|
// Otherwise, if the act is a wait for a state:
|
|
959
|
-
else if (
|
|
961
|
+
else if (type === 'state') {
|
|
960
962
|
// Wait for it.
|
|
961
963
|
const stateIndex = ['loaded', 'idle'].indexOf(act.which);
|
|
962
964
|
await page.waitForLoadState(
|
|
@@ -978,7 +980,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
978
980
|
}
|
|
979
981
|
}
|
|
980
982
|
// Otherwise, if the act is a page switch:
|
|
981
|
-
else if (
|
|
983
|
+
else if (type === 'page') {
|
|
982
984
|
// Wait for a page to be created and identify it as current.
|
|
983
985
|
page = await browserContext.waitForEvent('page');
|
|
984
986
|
// Wait until it is idle.
|
|
@@ -995,7 +997,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
995
997
|
// Add the URL to the act.
|
|
996
998
|
act.actualURL = url;
|
|
997
999
|
// If the act is a revelation:
|
|
998
|
-
if (
|
|
1000
|
+
if (type === 'reveal') {
|
|
999
1001
|
act.result = {
|
|
1000
1002
|
success: true
|
|
1001
1003
|
};
|
|
@@ -1017,8 +1019,8 @@ const doActs = async (report, opts = {}) => {
|
|
|
1017
1019
|
});
|
|
1018
1020
|
}
|
|
1019
1021
|
// Otherwise, if the act is a move:
|
|
1020
|
-
else if (moves[
|
|
1021
|
-
const selector = typeof moves[
|
|
1022
|
+
else if (moves[type]) {
|
|
1023
|
+
const selector = typeof moves[type] === 'string' ? moves[type] : act.what;
|
|
1022
1024
|
// Try up to 5 times to:
|
|
1023
1025
|
act.result = {found: false};
|
|
1024
1026
|
let selection = {};
|
|
@@ -1127,18 +1129,18 @@ const doActs = async (report, opts = {}) => {
|
|
|
1127
1129
|
};
|
|
1128
1130
|
// FUNCTION DEFINITION END
|
|
1129
1131
|
// If the move is a button click, perform it.
|
|
1130
|
-
if (
|
|
1132
|
+
if (type === 'button') {
|
|
1131
1133
|
await selection.click({timeout: 3000});
|
|
1132
1134
|
act.result.success = true;
|
|
1133
1135
|
act.result.move = 'clicked';
|
|
1134
1136
|
}
|
|
1135
1137
|
// Otherwise, if it is checking a radio button or checkbox, perform it.
|
|
1136
|
-
else if (['checkbox', 'radio'].includes(
|
|
1138
|
+
else if (['checkbox', 'radio'].includes(type)) {
|
|
1137
1139
|
await selection.waitForElementState('stable', {timeout: 2000})
|
|
1138
1140
|
.catch(error => {
|
|
1139
|
-
console.log(`ERROR waiting for stable ${
|
|
1141
|
+
console.log(`ERROR waiting for stable ${type} (${error.message})`);
|
|
1140
1142
|
act.result.success = false;
|
|
1141
|
-
act.result.error = `ERROR waiting for stable ${
|
|
1143
|
+
act.result.error = `ERROR waiting for stable ${type}`;
|
|
1142
1144
|
});
|
|
1143
1145
|
if (! act.result.error) {
|
|
1144
1146
|
const isEnabled = await selection.isEnabled();
|
|
@@ -1148,9 +1150,9 @@ const doActs = async (report, opts = {}) => {
|
|
|
1148
1150
|
timeout: 2000
|
|
1149
1151
|
})
|
|
1150
1152
|
.catch(error => {
|
|
1151
|
-
console.log(`ERROR checking ${
|
|
1153
|
+
console.log(`ERROR checking ${type} (${error.message})`);
|
|
1152
1154
|
act.result.success = false;
|
|
1153
|
-
act.result.error = `ERROR checking ${
|
|
1155
|
+
act.result.error = `ERROR checking ${type}`;
|
|
1154
1156
|
});
|
|
1155
1157
|
if (! act.result.error) {
|
|
1156
1158
|
act.result.success = true;
|
|
@@ -1158,20 +1160,20 @@ const doActs = async (report, opts = {}) => {
|
|
|
1158
1160
|
}
|
|
1159
1161
|
}
|
|
1160
1162
|
else {
|
|
1161
|
-
const report = `ERROR: could not check ${
|
|
1163
|
+
const report = `ERROR: could not check ${type} because disabled`;
|
|
1162
1164
|
act.result.success = false;
|
|
1163
1165
|
act.result.error = report;
|
|
1164
1166
|
}
|
|
1165
1167
|
}
|
|
1166
1168
|
}
|
|
1167
1169
|
// Otherwise, if it is focusing the element, perform it.
|
|
1168
|
-
else if (
|
|
1170
|
+
else if (type === 'focus') {
|
|
1169
1171
|
await selection.focus({timeout: 2000});
|
|
1170
1172
|
act.result.success = true;
|
|
1171
1173
|
act.result.move = 'focused';
|
|
1172
1174
|
}
|
|
1173
1175
|
// Otherwise, if it is clicking a link:
|
|
1174
|
-
else if (
|
|
1176
|
+
else if (type === 'link') {
|
|
1175
1177
|
const href = await selection.getAttribute('href');
|
|
1176
1178
|
const target = await selection.getAttribute('target');
|
|
1177
1179
|
act.result.href = href || 'NONE';
|
|
@@ -1210,7 +1212,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1210
1212
|
}
|
|
1211
1213
|
}
|
|
1212
1214
|
// Otherwise, if it is selecting an option in a select list, perform it.
|
|
1213
|
-
else if (
|
|
1215
|
+
else if (type === 'select') {
|
|
1214
1216
|
const options = await selection.$$('option');
|
|
1215
1217
|
let optionText = '';
|
|
1216
1218
|
if (options && Array.isArray(options) && options.length) {
|
|
@@ -1233,7 +1235,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1233
1235
|
act.result.option = optionText;
|
|
1234
1236
|
}
|
|
1235
1237
|
// Otherwise, if it is entering text in an input element:
|
|
1236
|
-
else if (['text', 'search'].includes(
|
|
1238
|
+
else if (['text', 'search'].includes(type)) {
|
|
1237
1239
|
act.result.attributes = {};
|
|
1238
1240
|
const {attributes} = act.result;
|
|
1239
1241
|
const type = await selection.getAttribute('type');
|
|
@@ -1256,7 +1258,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1256
1258
|
act.result.success = true;
|
|
1257
1259
|
act.result.move = 'entered';
|
|
1258
1260
|
// If the input is a search input:
|
|
1259
|
-
if (
|
|
1261
|
+
if (type === 'search') {
|
|
1260
1262
|
// Press the Enter key and wait for a network to be idle.
|
|
1261
1263
|
doAndWait(false);
|
|
1262
1264
|
}
|
|
@@ -1280,7 +1282,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1280
1282
|
}
|
|
1281
1283
|
}
|
|
1282
1284
|
// Otherwise, if the act is a keypress:
|
|
1283
|
-
else if (
|
|
1285
|
+
else if (type === 'press') {
|
|
1284
1286
|
// Identify the number of times to press the key.
|
|
1285
1287
|
let times = 1 + (act.again || 0);
|
|
1286
1288
|
report.jobData.presses += times;
|
|
@@ -1296,7 +1298,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1296
1298
|
};
|
|
1297
1299
|
}
|
|
1298
1300
|
// Otherwise, if it is a repetitive keyboard navigation:
|
|
1299
|
-
else if (
|
|
1301
|
+
else if (type === 'presses') {
|
|
1300
1302
|
const {navKey, what, which, withItems} = act;
|
|
1301
1303
|
const matchTexts = which ? which.map(text => debloat(text)) : [];
|
|
1302
1304
|
// Initialize the loop variables.
|
|
@@ -1465,7 +1467,31 @@ const doActs = async (report, opts = {}) => {
|
|
|
1465
1467
|
console.log('Acts completed');
|
|
1466
1468
|
// If standardization is required:
|
|
1467
1469
|
if (['also', 'only'].includes(standard)) {
|
|
1468
|
-
|
|
1470
|
+
// If granular reporting has been specified:
|
|
1471
|
+
if (report.observe) {
|
|
1472
|
+
// If a progress callback has been provided:
|
|
1473
|
+
if (onProgress) {
|
|
1474
|
+
// Notify the observer of the start of standardization.
|
|
1475
|
+
try {
|
|
1476
|
+
onProgress({
|
|
1477
|
+
type: 'standardization',
|
|
1478
|
+
which: 'start'
|
|
1479
|
+
});
|
|
1480
|
+
console.log(`${'Standardization started'} (observer notified)`);
|
|
1481
|
+
}
|
|
1482
|
+
catch (error) {
|
|
1483
|
+
console.log(`${message} (observer notification failed: ${errorStart(error)})`);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
// Otherwise, i.e. if no progress callback has been provided:
|
|
1487
|
+
else {
|
|
1488
|
+
// Notify the observer of the act and log it.
|
|
1489
|
+
tellServer(report, messageParams, message);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// Notify the observer and log the start of standardization.
|
|
1493
|
+
tellServer(report, '', 'Starting result standardization');
|
|
1494
|
+
}
|
|
1469
1495
|
const launchSpecActs = {};
|
|
1470
1496
|
// For each act:
|
|
1471
1497
|
report.acts.forEach((act, index) => {
|
|
@@ -1534,7 +1560,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1534
1560
|
// Runs a job and returns a report.
|
|
1535
1561
|
exports.doJob = async (job, opts = {}) => {
|
|
1536
1562
|
// Make a report as a copy of the job.
|
|
1537
|
-
|
|
1563
|
+
report = JSON.parse(JSON.stringify(job));
|
|
1538
1564
|
const jobData = report.jobData = {};
|
|
1539
1565
|
// Get whether the job is valid and, if not, why.
|
|
1540
1566
|
const jobInvalidity = isValidJob(job);
|
|
@@ -1594,3 +1620,52 @@ exports.doJob = async (job, opts = {}) => {
|
|
|
1594
1620
|
// Return the report.
|
|
1595
1621
|
return report;
|
|
1596
1622
|
};
|
|
1623
|
+
|
|
1624
|
+
// CLEANUP HANDLERS
|
|
1625
|
+
|
|
1626
|
+
// Track whether cleanup is in progress.
|
|
1627
|
+
let cleanupInProgress = false;
|
|
1628
|
+
let browserCloseIntentional = false;
|
|
1629
|
+
|
|
1630
|
+
// Force-kills any Playwright browser processes synchronously.
|
|
1631
|
+
const forceKillBrowsers = () => {
|
|
1632
|
+
if (cleanupInProgress) {
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
cleanupInProgress = true;
|
|
1636
|
+
try {
|
|
1637
|
+
// Kill any Chromium headless shell processes.
|
|
1638
|
+
execSync('pkill -9 -f "chromium_headless_shell.*headless_shell"', {stdio: 'ignore'});
|
|
1639
|
+
}
|
|
1640
|
+
catch(error) {}
|
|
1641
|
+
};
|
|
1642
|
+
// Force-kills any headless shell processes synchronously on process exit.
|
|
1643
|
+
process.on('exit', () => {
|
|
1644
|
+
forceKillBrowsers();
|
|
1645
|
+
});
|
|
1646
|
+
// Force-kills any headless shell processes synchronously on beforeExit.
|
|
1647
|
+
process.on('beforeExit', async () => {
|
|
1648
|
+
if (!browserCloseIntentional) {
|
|
1649
|
+
await browserClose();
|
|
1650
|
+
}
|
|
1651
|
+
forceKillBrowsers();
|
|
1652
|
+
});
|
|
1653
|
+
// Force-kills any headless shell processes synchronously on uncaught exceptions.
|
|
1654
|
+
process.on('uncaughtException', async error => {
|
|
1655
|
+
console.error('Uncaught exception:', error);
|
|
1656
|
+
await browserClose();
|
|
1657
|
+
forceKillBrowsers();
|
|
1658
|
+
process.exit(1);
|
|
1659
|
+
});
|
|
1660
|
+
// Force-kills any headless shell processes synchronously on SIGINT.
|
|
1661
|
+
process.on('SIGINT', async () => {
|
|
1662
|
+
await browserClose();
|
|
1663
|
+
forceKillBrowsers();
|
|
1664
|
+
process.exit(0);
|
|
1665
|
+
});
|
|
1666
|
+
// Force-kills any headless shell processes synchronously on SIGTERM.
|
|
1667
|
+
process.on('SIGTERM', async () => {
|
|
1668
|
+
await browserClose();
|
|
1669
|
+
forceKillBrowsers();
|
|
1670
|
+
process.exit(0);
|
|
1671
|
+
});
|
package/testaro/adbID.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
Clean-room rule: report elements that reference aria-describedby targets that are missing or ambiguous (duplicate ids).
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
const {init,
|
|
31
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
32
32
|
|
|
33
33
|
exports.reporter = async (page, withItems) => {
|
|
34
34
|
// elements that reference aria-describedby
|
|
@@ -63,5 +63,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
63
63
|
'Referenced description of the element is ambiguous or missing',
|
|
64
64
|
'Referenced descriptions of elements are ambiguous or missing'
|
|
65
65
|
];
|
|
66
|
-
return await
|
|
66
|
+
return await getRuleResult(withItems, all, 'adbID', whats, 3);
|
|
67
67
|
};
|
package/testaro/altScheme.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
Identify img elements whose alt attribute is an entire URL or clearly a file name (favicon).
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
const {init,
|
|
31
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
32
32
|
|
|
33
33
|
exports.reporter = async (page, withItems) => {
|
|
34
34
|
// Candidate images: any img with an alt attribute (including empty)
|
|
@@ -54,5 +54,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
54
54
|
'Element has an alt attribute with a URL as its entire value',
|
|
55
55
|
'img elements have alt attributes with URLs as their entire values'
|
|
56
56
|
];
|
|
57
|
-
return await
|
|
57
|
+
return await getRuleResult(withItems, all, 'altScheme', whats, 2);
|
|
58
58
|
};
|
package/testaro/attVal.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
// ########## IMPORTS
|
|
31
31
|
|
|
32
32
|
// Module to perform common operations.
|
|
33
|
-
const {init,
|
|
33
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
34
34
|
|
|
35
35
|
// ########## FUNCTIONS
|
|
36
36
|
|
|
@@ -54,5 +54,5 @@ exports.reporter = async (page, withItems, attributeName, areLicit, values) => {
|
|
|
54
54
|
`Element has attribute ${attributeName} with illicit value “__param__”`,
|
|
55
55
|
`Elements have attribute ${attributeName} with illicit values`
|
|
56
56
|
];
|
|
57
|
-
return await
|
|
57
|
+
return await getRuleResult(withItems, all, 'attVal', whats, 2);
|
|
58
58
|
};
|
package/testaro/autocomplete.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
// ########## IMPORTS
|
|
31
31
|
|
|
32
32
|
// Module to perform common operations.
|
|
33
|
-
const {init,
|
|
33
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
34
34
|
// Module to get locator data.
|
|
35
35
|
const {getLocatorData} = require('../procs/getLocatorData');
|
|
36
36
|
|
|
@@ -81,5 +81,5 @@ exports.reporter = async (
|
|
|
81
81
|
'Input is missing an autocomplete attribute with value __param__',
|
|
82
82
|
'Inputs are missing applicable autocomplete attributes'
|
|
83
83
|
];
|
|
84
|
-
return await
|
|
84
|
+
return await getRuleResult(withItems, all, 'autocomplete', whats, 2);
|
|
85
85
|
};
|
package/testaro/captionLoc.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
Report caption elements that are not the first child of their table element.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
const {init,
|
|
31
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
32
32
|
|
|
33
33
|
exports.reporter = async (page, withItems) => {
|
|
34
34
|
const all = await init(100, page, 'caption');
|
|
@@ -44,5 +44,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
44
44
|
'Element is not the first child of a table element',
|
|
45
45
|
'caption elements are not the first children of table elements'
|
|
46
46
|
];
|
|
47
|
-
return await
|
|
47
|
+
return await getRuleResult(withItems, all, 'captionLoc', whats, 3, 'CAPTION');
|
|
48
48
|
};
|
package/testaro/datalistRef.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
Report inputs whose list attribute references a missing or ambiguous datalist
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
const {init,
|
|
31
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
32
32
|
|
|
33
33
|
exports.reporter = async (page, withItems) => {
|
|
34
34
|
const all = await init(100, page, 'input[list]');
|
|
@@ -45,5 +45,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
45
45
|
'list attribute of the element references an ambiguous or missing datalist element',
|
|
46
46
|
'list attributes of elements reference ambiguous or missing datalist elements'
|
|
47
47
|
];
|
|
48
|
-
return await
|
|
48
|
+
return await getRuleResult(withItems, all, 'datalistRef', whats, 3, 'INPUT');
|
|
49
49
|
};
|
package/testaro/embAc.js
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
// ########## IMPORTS
|
|
34
34
|
|
|
35
35
|
// Module to perform common operations.
|
|
36
|
-
const {init,
|
|
36
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
37
37
|
|
|
38
38
|
// ########## FUNCTIONS
|
|
39
39
|
|
|
@@ -66,5 +66,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
66
66
|
'Interactive element is embedded in __param__',
|
|
67
67
|
'Interactive elements are contained by links or buttons'
|
|
68
68
|
];
|
|
69
|
-
return await
|
|
69
|
+
return await getRuleResult(withItems, all, 'embAc', whats, 2);
|
|
70
70
|
};
|
package/testaro/focInd.js
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
// ########## IMPORTS
|
|
45
45
|
|
|
46
46
|
// Module to perform common operations.
|
|
47
|
-
const {init,
|
|
47
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
48
48
|
|
|
49
49
|
// ########## FUNCTIONS
|
|
50
50
|
|
|
@@ -126,5 +126,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
126
126
|
}
|
|
127
127
|
// Populate and return the result.
|
|
128
128
|
const whats = ['Element has __param__', 'Elements fail to have standard focus indicators'];
|
|
129
|
-
return await
|
|
129
|
+
return await getRuleResult(withItems, all, 'focInd', whats, 1);
|
|
130
130
|
};
|
package/testaro/focOp.js
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
// ########## IMPORTS
|
|
39
39
|
|
|
40
40
|
// Module to perform common operations.
|
|
41
|
-
const {init,
|
|
41
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
42
42
|
// Module to get operabilities.
|
|
43
43
|
const {isOperable} = require('../procs/operable');
|
|
44
44
|
|
|
@@ -70,6 +70,6 @@ exports.reporter = async (page, withItems) => {
|
|
|
70
70
|
const whats = [
|
|
71
71
|
'Element is Tab-focusable but not operable', 'Elements are Tab-focusable but not operable'
|
|
72
72
|
];
|
|
73
|
-
const result = await
|
|
73
|
+
const result = await getRuleResult(withItems, all, 'focOp', whats, 2);
|
|
74
74
|
return result;
|
|
75
75
|
};
|
package/testaro/focVis.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
// ########## IMPORTS
|
|
33
33
|
|
|
34
34
|
// Module to perform common operations.
|
|
35
|
-
const {init,
|
|
35
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
36
36
|
|
|
37
37
|
// ########## FUNCTIONS
|
|
38
38
|
|
|
@@ -69,5 +69,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
69
69
|
'Visible link is __param__ the display',
|
|
70
70
|
'Visible links are above or to the left of the display'
|
|
71
71
|
];
|
|
72
|
-
return await
|
|
72
|
+
return await getRuleResult(withItems, all, 'focVis', whats, 2);
|
|
73
73
|
};
|
package/testaro/hover.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
// ########## IMPORTS
|
|
37
37
|
|
|
38
38
|
// Module to perform common operations.
|
|
39
|
-
const {init,
|
|
39
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
40
40
|
|
|
41
41
|
// ########## FUNCTIONS
|
|
42
42
|
|
|
@@ -105,5 +105,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
105
105
|
'Hovering over the element __param__',
|
|
106
106
|
'Hovering over elements adds elements to or subtracts elements from the page'
|
|
107
107
|
];
|
|
108
|
-
return await
|
|
108
|
+
return await getRuleResult(withItems, all, 'hover', whats, 0);
|
|
109
109
|
};
|
package/testaro/labClash.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
// Module to perform common operations.
|
|
33
|
-
const {init,
|
|
33
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
34
34
|
|
|
35
35
|
// ########## FUNCTIONS
|
|
36
36
|
|
|
@@ -66,5 +66,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
66
66
|
const whats = [
|
|
67
67
|
'Element has inconsistent label types (__param__)', 'Elements have inconsistent label types'
|
|
68
68
|
];
|
|
69
|
-
return await
|
|
69
|
+
return await getRuleResult(withItems, all, 'labClash', whats, 2);
|
|
70
70
|
};
|
package/testaro/lineHeight.js
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
// IMPORTS
|
|
36
36
|
|
|
37
37
|
// Module to perform common operations.
|
|
38
|
-
const {init,
|
|
38
|
+
const {init, getRuleResult} = require('../procs/testaro');
|
|
39
39
|
|
|
40
40
|
// FUNCTIONS
|
|
41
41
|
|
|
@@ -66,5 +66,5 @@ exports.reporter = async (page, withItems) => {
|
|
|
66
66
|
'Element line height is less than 1.5 times its font size (__param__)',
|
|
67
67
|
'Elements have line heights less than 1.5 times their font sizes'
|
|
68
68
|
];
|
|
69
|
-
return await
|
|
69
|
+
return await getRuleResult(withItems, all, 'lineHeight', whats, 1);
|
|
70
70
|
};
|