testaro 28.2.4 → 29.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/CONTRIBUTING.md +2 -3
- package/README.md +1 -1
- package/package.json +1 -1
- package/procs/tellServer.js +28 -0
- package/run.js +13 -25
- package/tests/testaro.js +31 -15
package/CONTRIBUTING.md
CHANGED
|
@@ -12,7 +12,6 @@ Testaro can benefit from contributions of various types, such as:
|
|
|
12
12
|
|
|
13
13
|
Tools that may merit consideration include:
|
|
14
14
|
- Arc (by TPGi). Costs $0.05 per page tested, and requires each user to have an account with the tool maker and to allow the tool maker to charge a charge account for payment.
|
|
15
|
-
- Aslint (by Essential Accessibility). Apparently requires using a bundle file that is in the repository but is also listed in the `.gitignore` file and is missing from the published package, so would need to be physically included in the Testaro code rather than referenced as a dependency.
|
|
16
15
|
|
|
17
16
|
## Improving execution speed
|
|
18
17
|
|
|
@@ -24,13 +23,13 @@ To come.
|
|
|
24
23
|
|
|
25
24
|
## Implementing new rules
|
|
26
25
|
|
|
27
|
-
Testaro has about 50 of its own rules, in addition to the approximately
|
|
26
|
+
Testaro has about 50 of its own rules, in addition to the approximately 900 rules of the other tools that it integrates. According to the issue classifications in the [Testilo](https://www.npmjs.com/package/testilo) package, these 950 or so rules can be classified into about 290 accessibility _issues_, because some rules of some tools at least approximately duplicate some rules of other tools.
|
|
28
27
|
|
|
29
28
|
However, many other significant accessibility issues exist that are not covered by any of the existing rules. Thus, Testaro welcomes contributions of new rules for such issues.
|
|
30
29
|
|
|
31
30
|
### Step 1
|
|
32
31
|
|
|
33
|
-
The first step in contributing a new rule to Testaro is to satisfy yourself that it will not duplicate existing rules. The `procs/score/
|
|
32
|
+
The first step in contributing a new rule to Testaro is to satisfy yourself that it will not duplicate existing rules. The `procs/score/tic36.js` file in the Testilo package should be helpful here.
|
|
34
33
|
|
|
35
34
|
### Step 2
|
|
36
35
|
|
package/README.md
CHANGED
|
@@ -221,7 +221,7 @@ Testaro helps overcome this format diversity by offering to represent the main f
|
|
|
221
221
|
|
|
222
222
|
In the conceptual scheme underlying the format standardization of Testaro, each tool has its own set of _rules_, where a rule is an algorithm for evaluating a target and determining whether instances of some kind of problem exist in it. With standardization, Testaro reports, in a uniform way, the outcomes from the application of rules by tools to a target.
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
Each job can specify how Testaro is to handle report standardization. A job can contain a `standard` property. If the value of that property is `'also'` or `'only'`, Testaro converts some data in each tool report to the standard format. That permits you to ignore the format idiosyncrasies of the tools. If `standard` has the value `'also'`, the job report includes both formats. If the value is `'only'`, the job report includes only the standard format. If the value is `'no'` (or anything else, or there is no `standard` property), the job report includes only the original format of each tool report.
|
|
225
225
|
|
|
226
226
|
The standard format of each tool report has these properties:
|
|
227
227
|
- `prevented`: `true` if the tool failed to run on the page, or otherwise omitted.
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
tellServer
|
|
3
|
+
Notify the server.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// CONSTANTS
|
|
7
|
+
|
|
8
|
+
const httpClient = require('http');
|
|
9
|
+
const httpsClient = require('https');
|
|
10
|
+
const agent = process.env.AGENT;
|
|
11
|
+
|
|
12
|
+
// FUNCTIONS
|
|
13
|
+
|
|
14
|
+
exports.tellServer = (report, messageParams, logMessage) => {
|
|
15
|
+
const observer = report.sources.sendReportTo.replace(/report$/, 'granular');
|
|
16
|
+
const whoParams = `agent=${agent}&jobID=${report.id || ''}`;
|
|
17
|
+
const wholeURL = `${observer}?${whoParams}&${messageParams}`;
|
|
18
|
+
const client = wholeURL.startsWith('https://') ? httpsClient : httpClient;
|
|
19
|
+
const request = client.request(wholeURL);
|
|
20
|
+
// If the notification threw an error:
|
|
21
|
+
request.on('error', error => {
|
|
22
|
+
// Report the error.
|
|
23
|
+
const errorMessage = 'ERROR notifying the server';
|
|
24
|
+
console.log(`${errorMessage} (${error.message})`);
|
|
25
|
+
});
|
|
26
|
+
request.end();
|
|
27
|
+
console.log(`${logMessage} (server notified)`);
|
|
28
|
+
};
|
package/run.js
CHANGED
|
@@ -13,6 +13,8 @@ const {actSpecs} = require('./actSpecs');
|
|
|
13
13
|
const {browserClose, getNonce, goTo, launch} = require('./procs/nav');
|
|
14
14
|
// Module to standardize report formats.
|
|
15
15
|
const {standardize} = require('./procs/standardize');
|
|
16
|
+
// Module to send a notice to the server.
|
|
17
|
+
const {tellServer} = require('./procs/tellServer');
|
|
16
18
|
|
|
17
19
|
// ########## CONSTANTS
|
|
18
20
|
|
|
@@ -20,8 +22,6 @@ const {standardize} = require('./procs/standardize');
|
|
|
20
22
|
const debug = process.env.DEBUG === 'true';
|
|
21
23
|
// Set WAITS environment variable to a positive number to insert delays (in ms).
|
|
22
24
|
const waits = Number.parseInt(process.env.WAITS) || 0;
|
|
23
|
-
// Set STANDARD environment variable to also if not set.
|
|
24
|
-
process.env.STANDARD ??= 'also';
|
|
25
25
|
// CSS selectors for targets of moves.
|
|
26
26
|
const moves = {
|
|
27
27
|
button: 'button, [role=button], input[type=submit]',
|
|
@@ -45,10 +45,6 @@ const tests = {
|
|
|
45
45
|
testaro: 'Testaro',
|
|
46
46
|
wave: 'WAVE',
|
|
47
47
|
};
|
|
48
|
-
// Observation items.
|
|
49
|
-
const httpClient = require('http');
|
|
50
|
-
const httpsClient = require('https');
|
|
51
|
-
const agent = process.env.AGENT;
|
|
52
48
|
|
|
53
49
|
// ########## VARIABLES
|
|
54
50
|
|
|
@@ -466,26 +462,12 @@ const doActs = async (report, actIndex, page) => {
|
|
|
466
462
|
actInfo = act.which;
|
|
467
463
|
}
|
|
468
464
|
}
|
|
469
|
-
const whichSuffix = actInfo ? ` (${actInfo})` : '';
|
|
470
465
|
// If granular reporting has been specified:
|
|
471
|
-
let granularSuffix = '';
|
|
472
466
|
if (report.observe) {
|
|
473
467
|
// Notify the server of the act.
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
const wholeURL = `${observer}?${whoParams}&${actParams}`;
|
|
478
|
-
const client = wholeURL.startsWith('https://') ? httpsClient : httpClient;
|
|
479
|
-
const request = client.request(wholeURL);
|
|
480
|
-
// If the notification threw an error:
|
|
481
|
-
request.on('error', error => {
|
|
482
|
-
// Report the error.
|
|
483
|
-
const errorMessage = 'ERROR notifying the server of an act';
|
|
484
|
-
console.log(`${errorMessage} (${error.message})`);
|
|
485
|
-
});
|
|
486
|
-
request.end();
|
|
487
|
-
granularSuffix = ' with notice to server';
|
|
488
|
-
console.log(`>>>> ${act.type}${whichSuffix}${granularSuffix}`);
|
|
468
|
+
const whichParam = act.which ? `&which=${act.which}` : '';
|
|
469
|
+
const messageParams = `act=${act.type}${whichParam}`;
|
|
470
|
+
tellServer(report, messageParams, `>>>> ${act.type}: ${actInfo}`);
|
|
489
471
|
}
|
|
490
472
|
// Increment the count of acts performed.
|
|
491
473
|
actCount++;
|
|
@@ -709,7 +691,9 @@ const doActs = async (report, actIndex, page) => {
|
|
|
709
691
|
act.what = tests[act.which];
|
|
710
692
|
// Initialize the options argument.
|
|
711
693
|
const options = {
|
|
694
|
+
report,
|
|
712
695
|
act,
|
|
696
|
+
granular: report.observe,
|
|
713
697
|
scriptNonce: report.jobData.lastScriptNonce || ''
|
|
714
698
|
};
|
|
715
699
|
// Add any specified arguments to it.
|
|
@@ -746,7 +730,7 @@ const doActs = async (report, actIndex, page) => {
|
|
|
746
730
|
const resultCount = Object.keys(toolReport.result).length;
|
|
747
731
|
act.result = resultCount ? toolReport.result : {success: false};
|
|
748
732
|
// If a standard-format result is to be included in the report:
|
|
749
|
-
const standard =
|
|
733
|
+
const standard = report.standard || 'only';
|
|
750
734
|
if (['also', 'only'].includes(standard)) {
|
|
751
735
|
// Initialize it.
|
|
752
736
|
act.standardResult = {
|
|
@@ -757,7 +741,11 @@ const doActs = async (report, actIndex, page) => {
|
|
|
757
741
|
standardize(act);
|
|
758
742
|
// If the original-format result is not to be included in the report:
|
|
759
743
|
if (standard === 'only') {
|
|
760
|
-
// Remove it.
|
|
744
|
+
// Remove it, except any important property.
|
|
745
|
+
if (act.result.important) {
|
|
746
|
+
act.data = act.result.important;
|
|
747
|
+
console.log('>>>>>> Important result data protected from deletion');
|
|
748
|
+
}
|
|
761
749
|
delete act.result;
|
|
762
750
|
}
|
|
763
751
|
// If the test has expectations:
|
package/tests/testaro.js
CHANGED
|
@@ -9,21 +9,27 @@
|
|
|
9
9
|
const {init, report} = require('../procs/testaro');
|
|
10
10
|
// Module to handle files.
|
|
11
11
|
const fs = require('fs/promises');
|
|
12
|
+
// Module to send a notice to the server.
|
|
13
|
+
const {tellServer} = require('../procs/tellServer');
|
|
12
14
|
|
|
13
15
|
// ######## CONSTANTS
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
/*
|
|
18
|
+
const futureEvalRulesTraining = {
|
|
17
19
|
altScheme: 'img elements with alt attributes having URLs as their entire values',
|
|
18
20
|
captionLoc: 'caption elements that are not first children of table elements',
|
|
19
21
|
datalistRef: 'elements with ambiguous or missing referenced datalist elements',
|
|
22
|
+
secHeading: 'headings that violate the logical level order in their sectioning containers',
|
|
23
|
+
textSem: 'semantically vague elements i, b, and/or small'
|
|
24
|
+
};
|
|
25
|
+
const futureEvalRulesCleanRoom = {
|
|
26
|
+
adbID: 'elements with ambiguous or missing referenced descriptions',
|
|
20
27
|
imageLink: 'links with image files as their destinations',
|
|
21
28
|
legendLoc: 'legend elements that are not first children of fieldset elements',
|
|
22
29
|
optRoleSel: 'Non-option elements with option roles that have no aria-selected attributes',
|
|
23
|
-
phOnly: 'input elements with placeholders but no accessible names'
|
|
24
|
-
secHeading: 'headings that violate the logical level order in their sectioning containers',
|
|
25
|
-
textSem: 'semantically vague elements i, b, and/or small',
|
|
30
|
+
phOnly: 'input elements with placeholders but no accessible names'
|
|
26
31
|
};
|
|
32
|
+
*/
|
|
27
33
|
const evalRules = {
|
|
28
34
|
allCaps: 'leaf elements with entirely upper-case text longer than 7 characters',
|
|
29
35
|
allHidden: 'page that is entirely or mostly hidden',
|
|
@@ -95,15 +101,17 @@ const jsonTest = async (ruleID, ruleArgs) => {
|
|
|
95
101
|
};
|
|
96
102
|
// Conducts and reports Testaro tests.
|
|
97
103
|
exports.reporter = async (page, options) => {
|
|
98
|
-
const {withItems, stopOnFail, args} = options;
|
|
104
|
+
const {withItems, stopOnFail, granular, args} = options;
|
|
99
105
|
const argRules = args ? Object.keys(args) : null;
|
|
100
106
|
const rules = options.rules || ['y', ... Object.keys(evalRules)];
|
|
101
107
|
// Initialize the data.
|
|
102
108
|
const data = {
|
|
103
109
|
rules: {},
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
important: {
|
|
111
|
+
preventions: [],
|
|
112
|
+
invalid: [],
|
|
113
|
+
testTimes: {}
|
|
114
|
+
}
|
|
107
115
|
};
|
|
108
116
|
// If the rule specification is valid:
|
|
109
117
|
if (
|
|
@@ -129,13 +137,21 @@ exports.reporter = async (page, options) => {
|
|
|
129
137
|
// Add them to the argument array.
|
|
130
138
|
ruleArgs.push(... args[rule]);
|
|
131
139
|
}
|
|
132
|
-
//
|
|
140
|
+
// If granular reporting is specified:
|
|
133
141
|
const what = evalRules[rule] || etcRules[rule];
|
|
142
|
+
if (granular) {
|
|
143
|
+
// Report the rule to the server.
|
|
144
|
+
tellServer(
|
|
145
|
+
options.report,
|
|
146
|
+
`act=test&which=testaro&rule=${rule}&ruleWhat=${what}`,
|
|
147
|
+
`>>>>>> ${rule} (${what})`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
// Test the page.
|
|
134
151
|
if (! data.rules[rule]) {
|
|
135
152
|
data.rules[rule] = {};
|
|
136
153
|
}
|
|
137
154
|
data.rules[rule].what = what;
|
|
138
|
-
console.log(`>>>>>> ${rule} (${what})`);
|
|
139
155
|
try {
|
|
140
156
|
const startTime = Date.now();
|
|
141
157
|
const ruleReport = isJS
|
|
@@ -149,7 +165,7 @@ exports.reporter = async (page, options) => {
|
|
|
149
165
|
});
|
|
150
166
|
data.rules[rule].totals = data.rules[rule].totals.map(total => Math.round(total));
|
|
151
167
|
if (ruleReport.prevented) {
|
|
152
|
-
data.preventions.push(rule);
|
|
168
|
+
data.important.preventions.push(rule);
|
|
153
169
|
}
|
|
154
170
|
// If testing is to stop after a failure and the page failed the test:
|
|
155
171
|
if (stopOnFail && ruleReport.totals.some(total => total)) {
|
|
@@ -160,19 +176,19 @@ exports.reporter = async (page, options) => {
|
|
|
160
176
|
// If an error is thrown by the test:
|
|
161
177
|
catch(error) {
|
|
162
178
|
// Report this.
|
|
163
|
-
data.preventions.push(rule);
|
|
179
|
+
data.important.preventions.push(rule);
|
|
164
180
|
console.log(`ERROR: Test of testaro rule ${rule} prevented (${error.message})`);
|
|
165
181
|
}
|
|
166
182
|
}
|
|
167
183
|
// Otherwise, i.e. if the rule is undefined or doubly defined:
|
|
168
184
|
else {
|
|
169
185
|
// Report this.
|
|
170
|
-
data.invalid.push(rule);
|
|
186
|
+
data.important.invalid.push(rule);
|
|
171
187
|
console.log(`ERROR: Rule ${rule} not validly defined`);
|
|
172
188
|
}
|
|
173
189
|
}
|
|
174
190
|
testTimes.sort((a, b) => b[1] - a[1]).forEach(pair => {
|
|
175
|
-
data.testTimes[pair[0]] = pair[1];
|
|
191
|
+
data.important.testTimes[pair[0]] = pair[1];
|
|
176
192
|
});
|
|
177
193
|
}
|
|
178
194
|
// Otherwise, i.e. if the rule specification is invalid:
|