testaro 4.11.1 → 4.12.2
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/aceconfig.js +1 -1
- package/commands.js +1 -1
- package/high.js +1 -1
- package/package.json +1 -1
- package/run.js +28 -8
- package/tests/aatt.js +17 -2
- package/tests/alfa.js +14 -2
- package/tests/focAll.js +7 -12
- package/tests/focInd.js +6 -3
- package/tests/ibm.js +8 -6
- package/tests/tabNav.js +43 -10
package/aceconfig.js
CHANGED
package/commands.js
CHANGED
package/high.js
CHANGED
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
index.js
|
|
3
3
|
testaro main script.
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
// ########## IMPORTS
|
|
7
|
+
|
|
6
8
|
// Module to keep secrets.
|
|
7
9
|
require('dotenv').config();
|
|
8
10
|
// Requirements for commands.
|
|
9
11
|
const {commands} = require('./commands');
|
|
12
|
+
|
|
10
13
|
// ########## CONSTANTS
|
|
14
|
+
|
|
11
15
|
// Set DEBUG environment variable to 'true' to add debugging features.
|
|
12
16
|
const debug = process.env.DEBUG === 'true';
|
|
13
17
|
// Set WAITS environment variable to a positive number to insert delays (in ms).
|
|
@@ -77,7 +81,9 @@ const errorWords = [
|
|
|
77
81
|
'missing',
|
|
78
82
|
'deprecated'
|
|
79
83
|
];
|
|
84
|
+
|
|
80
85
|
// ########## VARIABLES
|
|
86
|
+
|
|
81
87
|
// Facts about the current session.
|
|
82
88
|
let logCount = 0;
|
|
83
89
|
let logSize = 0;
|
|
@@ -91,7 +97,11 @@ let actCount = 0;
|
|
|
91
97
|
let browserContext;
|
|
92
98
|
let browserTypeName;
|
|
93
99
|
let requestedURL = '';
|
|
100
|
+
// All browsers launched.
|
|
101
|
+
let browsers = [];
|
|
102
|
+
|
|
94
103
|
// ########## VALIDATORS
|
|
104
|
+
|
|
95
105
|
// Validates a browser type.
|
|
96
106
|
const isBrowserType = type => ['chromium', 'firefox', 'webkit'].includes(type);
|
|
97
107
|
// Validates a load state.
|
|
@@ -234,12 +244,17 @@ const isValidReport = async report => {
|
|
|
234
244
|
return false;
|
|
235
245
|
}
|
|
236
246
|
};
|
|
247
|
+
|
|
237
248
|
// ########## OTHER FUNCTIONS
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
249
|
+
|
|
250
|
+
// Closes all existing browsers.
|
|
251
|
+
const closeBrowsers = async () => {
|
|
252
|
+
for (const browserObj of browsers) {
|
|
253
|
+
const {browser, typeName} = browserObj;
|
|
254
|
+
if (browser) {
|
|
255
|
+
console.log(`Closing ${typeName} browser, version ${browser.version()}`);
|
|
256
|
+
await browser.close();
|
|
257
|
+
}
|
|
243
258
|
}
|
|
244
259
|
};
|
|
245
260
|
// Launches a browser.
|
|
@@ -248,7 +263,7 @@ const launch = async typeName => {
|
|
|
248
263
|
// If the specified browser type exists:
|
|
249
264
|
if (browserType) {
|
|
250
265
|
// Close any existing browser.
|
|
251
|
-
await
|
|
266
|
+
await closeBrowsers();
|
|
252
267
|
// Launch a browser of the specified type.
|
|
253
268
|
const browserOptions = {};
|
|
254
269
|
if (debug) {
|
|
@@ -258,6 +273,11 @@ const launch = async typeName => {
|
|
|
258
273
|
browserOptions.slowMo = waits;
|
|
259
274
|
}
|
|
260
275
|
const browser = await browserType.launch(browserOptions);
|
|
276
|
+
// Register it.
|
|
277
|
+
browsers.push({
|
|
278
|
+
browser,
|
|
279
|
+
typeName
|
|
280
|
+
});
|
|
261
281
|
// Create a new context (window) in it, taller if debugging is on.
|
|
262
282
|
const viewport = debug ? {
|
|
263
283
|
viewPort: {
|
|
@@ -1261,8 +1281,8 @@ const doScript = async (report) => {
|
|
|
1261
1281
|
report.testTimes = [];
|
|
1262
1282
|
// Perform the specified acts.
|
|
1263
1283
|
await doActs(report, 0, null);
|
|
1264
|
-
// Close
|
|
1265
|
-
await
|
|
1284
|
+
// Close all browsers.
|
|
1285
|
+
await closeBrowsers();
|
|
1266
1286
|
// Add the log statistics to the report.
|
|
1267
1287
|
report.logCount = logCount;
|
|
1268
1288
|
report.logSize = logSize;
|
package/tests/aatt.js
CHANGED
|
@@ -65,9 +65,12 @@ exports.reporter = async (page, waitLong, tryLimit = 4) => {
|
|
|
65
65
|
const issueArray = JSON.parse(reportJSON);
|
|
66
66
|
// Remove the notices from the array.
|
|
67
67
|
const nonNotices = issueArray.filter(issue => issue.type !== 'notice');
|
|
68
|
-
//
|
|
68
|
+
// For each non-notice issue:
|
|
69
|
+
let errors = 0;
|
|
70
|
+
let warnings = 0;
|
|
69
71
|
nonNotices.forEach(issue => {
|
|
70
72
|
if (issue.type) {
|
|
73
|
+
// Convert the technique property from a string to an array of strings.
|
|
71
74
|
const longTech = issue.techniques;
|
|
72
75
|
issue.techniques = longTech.replace(/a><a/g, 'a>%<a').split('%');
|
|
73
76
|
issue.id = issue
|
|
@@ -75,12 +78,24 @@ exports.reporter = async (page, waitLong, tryLimit = 4) => {
|
|
|
75
78
|
.map(technique => technique.replace(/^.+?>|<\/a>$/g, ''))
|
|
76
79
|
.sort()
|
|
77
80
|
.join('+');
|
|
81
|
+
// Add the issue to the totals.
|
|
82
|
+
if (issue.type === 'error') {
|
|
83
|
+
errors++;
|
|
84
|
+
}
|
|
85
|
+
else if (issue.type === 'warning') {
|
|
86
|
+
warnings++;
|
|
87
|
+
}
|
|
78
88
|
}
|
|
79
89
|
});
|
|
90
|
+
// Return the result.
|
|
80
91
|
return {
|
|
81
92
|
result: {
|
|
93
|
+
totals: {
|
|
94
|
+
errors,
|
|
95
|
+
warnings
|
|
96
|
+
},
|
|
82
97
|
report: nonNotices,
|
|
83
|
-
triesLeft
|
|
98
|
+
preventionCount: tryLimit - triesLeft - 1
|
|
84
99
|
}
|
|
85
100
|
};
|
|
86
101
|
}
|
package/tests/alfa.js
CHANGED
|
@@ -44,7 +44,13 @@ exports.reporter = async page => {
|
|
|
44
44
|
});
|
|
45
45
|
await rulePage.close();
|
|
46
46
|
}
|
|
47
|
-
const data =
|
|
47
|
+
const data = {
|
|
48
|
+
totals: {
|
|
49
|
+
failures: 0,
|
|
50
|
+
warnings: 0
|
|
51
|
+
},
|
|
52
|
+
items: []
|
|
53
|
+
};
|
|
48
54
|
await Scraper.with(async scraper => {
|
|
49
55
|
for (const input of await scraper.scrape(page.url())) {
|
|
50
56
|
const audit = Audit.of(input, alfaRules.default);
|
|
@@ -96,7 +102,13 @@ exports.reporter = async page => {
|
|
|
96
102
|
if (etcTags.length) {
|
|
97
103
|
outcomeData.etcTags = etcTags;
|
|
98
104
|
}
|
|
99
|
-
|
|
105
|
+
if (outcomeData.verdict === 'failed') {
|
|
106
|
+
data.totals.failures++;
|
|
107
|
+
}
|
|
108
|
+
else if (outcomeData.verdict === 'cantTell') {
|
|
109
|
+
data.totals.warnings++;
|
|
110
|
+
}
|
|
111
|
+
data.items.push(outcomeData);
|
|
100
112
|
}
|
|
101
113
|
}
|
|
102
114
|
});
|
package/tests/focAll.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
2
|
focAll
|
|
3
|
-
This test reports discrepancies between focusable and Tab-focused element counts.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
it
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from reaching all focusable elements. Either of these can complicate navigation for
|
|
11
|
-
users. It may disappoint the expectation that the content will remain stable as they
|
|
12
|
-
move with the Tab key, or the expectation that they can reach every focusable element
|
|
13
|
-
(or widget, such as one radio button or tab in each group) merely by pressing the Tab
|
|
14
|
-
key.
|
|
3
|
+
This test reports discrepancies between focusable and Tab-focused element counts. The test first
|
|
4
|
+
counts all the visible focusable (i.e. with tabIndex 0) elements (except counting each group of
|
|
5
|
+
radio buttons as only one focusable element). Then it repeatedly presses the Tab (or Option-Tab
|
|
6
|
+
in webkit) key until it has reached all the elements it can and counts those elements. If the
|
|
7
|
+
two counts differ, navigation can be made more difficult. The cause may be surprising changes in
|
|
8
|
+
content during navigation with the Tab key, or inability to reach every focusable element (or
|
|
9
|
+
widget, such as one radio button or tab in each group) merely by pressing the Tab key.
|
|
15
10
|
*/
|
|
16
11
|
exports.reporter = async page => {
|
|
17
12
|
// Identify the count of visible focusable elements.
|
package/tests/focInd.js
CHANGED
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
line thickness and non-transparent color. The test is based on the assumption that outlines are
|
|
6
6
|
the standard and thus most familiar focus indicator. Other focus indicators are assumed better
|
|
7
7
|
than none, but more likely to be misunderstood. For example, underlines may be mistaken for
|
|
8
|
-
selection indicators. Some pages delay the appearance of focus indicators.
|
|
9
|
-
|
|
8
|
+
selection indicators. Some pages delay the appearance of focus indicators. If a wait is
|
|
9
|
+
specified, the test checks every 100 ms for an outline until the allow wait time expires,
|
|
10
|
+
and once more after it expires. If no outline appears by then, the test checks for other focus
|
|
11
|
+
indicators. If an outline does not appear immediately but appears on a subsequent check, the test
|
|
12
|
+
reports the amount of the delay.
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
WARNING: This test fails to recognize outlines when run with firefox.
|
|
12
15
|
*/
|
|
13
16
|
exports.reporter = async (page, revealAll, allowedDelay, withItems) => {
|
|
14
17
|
// If required, make all elements visible.
|
package/tests/ibm.js
CHANGED
|
@@ -19,12 +19,13 @@
|
|
|
19
19
|
*/
|
|
20
20
|
// Import required modules.
|
|
21
21
|
const fs = require('fs').promises;
|
|
22
|
-
const {getCompliance} = require('accessibility-checker');
|
|
22
|
+
const {getCompliance, close} = require('accessibility-checker');
|
|
23
23
|
// Runs the IBM test.
|
|
24
24
|
const run = async content => {
|
|
25
25
|
const nowLabel = (new Date()).toISOString().slice(0, 19);
|
|
26
26
|
// Return the result of a test.
|
|
27
27
|
const ibmReport = await getCompliance(content, nowLabel);
|
|
28
|
+
await close();
|
|
28
29
|
return ibmReport;
|
|
29
30
|
};
|
|
30
31
|
// Trims an IBM report.
|
|
@@ -67,11 +68,11 @@ const doTest = async (content, withItems, timeLimit) => {
|
|
|
67
68
|
resolve({});
|
|
68
69
|
}, 1000 * timeLimit);
|
|
69
70
|
});
|
|
70
|
-
// Conduct and
|
|
71
|
+
// Conduct the test and get a Promise of the report.
|
|
71
72
|
const ibmReport = run(content);
|
|
72
|
-
// Wait for
|
|
73
|
+
// Wait for completion or until the time limit expires.
|
|
73
74
|
const ibmReportIfFast = await Promise.race([ibmReport, wait]);
|
|
74
|
-
// Delete
|
|
75
|
+
// Delete existing report files.
|
|
75
76
|
try {
|
|
76
77
|
const reportNames = await fs.readdir('results');
|
|
77
78
|
for (const reportName of reportNames) {
|
|
@@ -88,7 +89,6 @@ const doTest = async (content, withItems, timeLimit) => {
|
|
|
88
89
|
return ibmTypeReport;
|
|
89
90
|
}
|
|
90
91
|
else {
|
|
91
|
-
console.log('ERROR: getting ibm test report took too long');
|
|
92
92
|
return {
|
|
93
93
|
prevented: true,
|
|
94
94
|
error: 'ERROR: getting ibm test report took too long'
|
|
@@ -105,6 +105,7 @@ exports.reporter = async (page, withItems, withNewContent) => {
|
|
|
105
105
|
result.content = await doTest(typeContent, withItems, timeLimit);
|
|
106
106
|
if (result.content.prevented) {
|
|
107
107
|
result.prevented = true;
|
|
108
|
+
console.log('ERROR: Getting ibm test report from page took too long');
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
// If a test with new content is to be performed:
|
|
@@ -112,8 +113,9 @@ exports.reporter = async (page, withItems, withNewContent) => {
|
|
|
112
113
|
const timeLimit = 20;
|
|
113
114
|
const typeContent = page.url();
|
|
114
115
|
result.url = await doTest(typeContent, withItems, timeLimit);
|
|
115
|
-
if (result.
|
|
116
|
+
if (result.url.prevented) {
|
|
116
117
|
result.prevented = true;
|
|
118
|
+
console.log('ERROR: Getting ibm test report from URL took too long');
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
return {result};
|
package/tests/tabNav.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
tabNav
|
|
3
|
-
This test reports nonstandard keyboard navigation among tab elements in tab lists.
|
|
3
|
+
This test reports nonstandard keyboard navigation among tab elements in visible tab lists.
|
|
4
4
|
Standards are based on https://www.w3.org/TR/wai-aria-practices-1.1/#tabpanel.
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -73,8 +73,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
73
73
|
correct: []
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
-
// Identify an array of the tablists.
|
|
77
|
-
const tabLists = await page.$$('[role=tablist]');
|
|
76
|
+
// Identify an array of the visible tablists.
|
|
77
|
+
const tabLists = await page.$$('[role=tablist]:visible');
|
|
78
78
|
if (tabLists.length) {
|
|
79
79
|
// FUNCTION DEFINITIONS START
|
|
80
80
|
// Returns text associated with an element.
|
|
@@ -94,22 +94,34 @@ exports.reporter = async (page, withItems) => {
|
|
|
94
94
|
) => {
|
|
95
95
|
let pressed = true;
|
|
96
96
|
// Click the tab element, to make the focus on it effective.
|
|
97
|
-
await tabElement.click({
|
|
97
|
+
await tabElement.click({
|
|
98
|
+
timeout: 500
|
|
99
|
+
})
|
|
100
|
+
.catch(async error => {
|
|
101
|
+
await tabElement.click({
|
|
102
|
+
force: true
|
|
103
|
+
});
|
|
104
|
+
})
|
|
98
105
|
.catch(error => {
|
|
99
106
|
console.log(`ERROR: could not click tab element ${itemData.text} (${error.message})`);
|
|
100
|
-
|
|
107
|
+
pressed = false;
|
|
101
108
|
});
|
|
109
|
+
// Increment the counts of navigations and key navigations.
|
|
110
|
+
data.totals.navigations.all.total++;
|
|
111
|
+
data.totals.navigations.specific[keyProp].total++;
|
|
112
|
+
const {navigationErrors} = itemData;
|
|
113
|
+
// If the click succeeded:
|
|
102
114
|
if (pressed) {
|
|
103
115
|
// Refocus the tab element and press the specified key (page.keyboard.press may fail).
|
|
104
|
-
await tabElement.press(keyName
|
|
116
|
+
await tabElement.press(keyName, {
|
|
117
|
+
timeout: 1000
|
|
118
|
+
})
|
|
105
119
|
.catch(error => {
|
|
106
120
|
console.log(`ERROR: could not press ${keyName} (${error.message})`);
|
|
107
121
|
pressed = false;
|
|
108
122
|
});
|
|
123
|
+
// If the refocus and keypress succeeded:
|
|
109
124
|
if (pressed) {
|
|
110
|
-
// Increment the counts of navigations and key navigations.
|
|
111
|
-
data.totals.navigations.all.total++;
|
|
112
|
-
data.totals.navigations.specific[keyProp].total++;
|
|
113
125
|
// Identify which tab element is now focused, if any.
|
|
114
126
|
const focusIndex = await focusedTab(tabs);
|
|
115
127
|
// If the focus is correct:
|
|
@@ -128,15 +140,36 @@ exports.reporter = async (page, withItems) => {
|
|
|
128
140
|
// If itemization is required:
|
|
129
141
|
if (withItems) {
|
|
130
142
|
// Update the element report.
|
|
131
|
-
|
|
143
|
+
navigationErrors.push(keyName);
|
|
132
144
|
}
|
|
133
145
|
}
|
|
134
146
|
return elementIsCorrect;
|
|
135
147
|
}
|
|
148
|
+
// Otherwise, i.e. if the refocus or keypress failed:
|
|
136
149
|
else {
|
|
150
|
+
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
151
|
+
data.totals.navigations.all.incorrect++;
|
|
152
|
+
data.totals.navigations.specific[keyProp].incorrect++;
|
|
153
|
+
// If itemization is required and a focus failure has not yet been reported:
|
|
154
|
+
if (withItems && ! navigationErrors.includes('focus')) {
|
|
155
|
+
// Update the element report.
|
|
156
|
+
navigationErrors.push('focus');
|
|
157
|
+
}
|
|
137
158
|
return false;
|
|
138
159
|
}
|
|
139
160
|
}
|
|
161
|
+
// Otherwise, i.e. if the click failed:
|
|
162
|
+
else {
|
|
163
|
+
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
164
|
+
data.totals.navigations.all.incorrect++;
|
|
165
|
+
data.totals.navigations.specific[keyProp].incorrect++;
|
|
166
|
+
// If itemization is required and a click failure has not yet been reported:
|
|
167
|
+
if (withItems && ! navigationErrors.includes('click')) {
|
|
168
|
+
// Update the element report.
|
|
169
|
+
navigationErrors.push('click');
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
140
173
|
};
|
|
141
174
|
// Returns the index to which an arrow key should move the focus.
|
|
142
175
|
const arrowTarget = (startIndex, tabCount, orientation, direction) => {
|