testilo 6.1.6 → 7.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/README.md +122 -24
- package/aim.js +4 -18
- package/digest.js +14 -42
- package/multiDigest.js +51 -0
- package/multiScore.js +45 -0
- package/package.json +1 -1
- package/score.js +11 -42
- package/procs/digest/dp19a/index.html +0 -55
- package/procs/digest/dp19a/index.js +0 -44
- package/procs/score/sp19a.js +0 -34
package/README.md
CHANGED
|
@@ -9,10 +9,20 @@ Testaro performs digital accessibility tests on web artifacts and creates report
|
|
|
9
9
|
|
|
10
10
|
Because Testilo supports Testaro, this `README` file presumes that you have access to the Testaro `README` file and therefore does not repeat information provided there.
|
|
11
11
|
|
|
12
|
+
## Branches
|
|
13
|
+
|
|
14
|
+
The `writer` branch contains the state of Testilo as of 2022-11-07. In that branch, Testilo must read and write files when it aims, scores, or digests. That makes Testilo unusable as a dependency in applications that do not have permission to both read and write files.
|
|
15
|
+
|
|
16
|
+
The `main` branch contains the state of Testilo starting on 2022-11-07. In that branch, Testilo does not need to read or write files when it aims, scores, or digests, so applications without write permission can still use Testilo as a dependency if they need only those functionalities.
|
|
17
|
+
|
|
18
|
+
This `README.md` file documents the `main` branch.
|
|
19
|
+
|
|
12
20
|
## Dependencies
|
|
13
21
|
|
|
14
22
|
The `dotenv` dependency lets you set environment variables in an untracked `.env` file. This prevents secret data, such as passwords, from being shared as part of this package.
|
|
15
23
|
|
|
24
|
+
When Testilo is a dependency of another application, the `.env` file is not imported, because it is not tracked, so all needed environment variables must be provided by the importing application.
|
|
25
|
+
|
|
16
26
|
## Architecture
|
|
17
27
|
|
|
18
28
|
Testilo is written in Node.js. Commands are given to Testilo in a command-line (terminal) interface or programmatically.
|
|
@@ -37,15 +47,23 @@ The `aim` function allows you to _aim_ a script at a host. That means modifying
|
|
|
37
47
|
Execution by a module:
|
|
38
48
|
|
|
39
49
|
```javaScript
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
fs.
|
|
50
|
+
const aimScript = async () => {
|
|
51
|
+
const fs = require('fs/promises');
|
|
52
|
+
const host = {
|
|
53
|
+
which: https://w3c.org/,
|
|
54
|
+
what: 'World Wide Web Consortium',
|
|
55
|
+
id: w3c
|
|
56
|
+
};
|
|
57
|
+
const {aim} = require('testilo/aim');
|
|
58
|
+
const scriptJSON = await fs.readFile(`${process.env.SCRIPTDIR}/tp25.json`, 'utf8');
|
|
59
|
+
const script = JSON.parse(scriptJSON);
|
|
60
|
+
const aimedScript = aim(script, host, 'developer@w3c.org');
|
|
61
|
+
await fs.writeFile(
|
|
62
|
+
`${process.env.JOBDIR}/${aimedScript.id}.json`, JSON.stringify(aimedScript, null, 2)
|
|
63
|
+
);
|
|
64
|
+
console.log(`Script ${aimedScript.source.script} aimed at ${aimedScript.host.what}`);
|
|
65
|
+
}
|
|
66
|
+
aimScript();
|
|
49
67
|
```
|
|
50
68
|
|
|
51
69
|
Execution by a user:
|
|
@@ -56,6 +74,8 @@ node call aim tp25 https://w3.org/ 'World Wide Web Consortium' w3c developer@w3c
|
|
|
56
74
|
|
|
57
75
|
In these examples, a copy of the script file named `tp25.json` in the `SCRIPTDIR` directory is aimed at the World Wide Web Consortium and then saved in the `JOBDIR` directory.
|
|
58
76
|
|
|
77
|
+
The `aim` function neither reads nor writes files. Its arguments are a script object, a host object, and a requester-email-address string, and it returns the script object, aimed at the host.
|
|
78
|
+
|
|
59
79
|
### `merge`
|
|
60
80
|
|
|
61
81
|
The `merge` function is similar to the `aim` function, but it aims a script at multiple hosts, not only one. The hosts are identified in a _batch_, a file in the `BATCHDIR` directory. The output of `merge` is multiple script files, one per host, saved in the `JOBDIR` directory.
|
|
@@ -99,17 +119,57 @@ Execution by a user:
|
|
|
99
119
|
node call merge tp25 weborgs
|
|
100
120
|
```
|
|
101
121
|
|
|
122
|
+
In these examples, a copy of the script file named `tp25.json` in the `SCRIPTDIR` directory is aimed at all the hosts in the batch file named `weborgs.json` in the `BATCHDIR` directory, and the resulting host-specific scripts are saved in the `JOBDIR` directory.
|
|
123
|
+
|
|
102
124
|
### `score`
|
|
103
125
|
|
|
104
126
|
Testaro performs tests and produces reports of test results. Testilo can add scores to those reports. In this way, each report can not only detail successes and failures of individual tests but also assign scores to those results and combine the partial scores into total scores.
|
|
105
127
|
|
|
106
|
-
The `score` function performs scoring. It depends on _score
|
|
128
|
+
The `score` function performs scoring. It depends on a _score proc_ to define the scoring rules. Some score procs are in the Testilo package (in the `procs/score` directory), and you can create more score procs to implement different rules.
|
|
129
|
+
|
|
130
|
+
Execution by a module:
|
|
131
|
+
|
|
132
|
+
```javaScript
|
|
133
|
+
const fs = require('fs/promises');
|
|
134
|
+
const scoreReport = async rawReport => {
|
|
135
|
+
const {score} = require('testilo/score');
|
|
136
|
+
const procJSON = await fs.readFile(`${process.env.SCOREPROCDIR}/sp25a.json`, 'utf8');
|
|
137
|
+
const proc = JSON.parse(procJSON);
|
|
138
|
+
const scoredReport = score(proc, rawReport);
|
|
139
|
+
await fs.writeFile(
|
|
140
|
+
`${process.env.REPORTDIR_SCORED}/${scoredReport.id}.json`, JSON.stringify(scoredReport, null, 2)
|
|
141
|
+
);
|
|
142
|
+
console.log(`Report ${scoredReport.id} scored`);
|
|
143
|
+
};
|
|
144
|
+
fs.readFile(`${process.env.REPORTDIR_RAW}/756mr-tp25-w3c.json`, 'utf8')
|
|
145
|
+
.then(rawReportJSON => {
|
|
146
|
+
const rawReport = JSON.parse(rawReportJSON);
|
|
147
|
+
scoreReport(rawReport);
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Execution by a user:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
node call score sp25a
|
|
155
|
+
node call score sp25a 756mr
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
In these examples, the `score` function applies a score proc named `sp25a`, of which a copy is in the file `sp25a.json` in the `SCOREPROCDIR` directory, to a raw report `756mr-tp25-w3c.json` in the `REPORTDIR_RAW` directory and returns the same report with score data added. The scored report is saved in the `REPORTDIR_SCORED` directory.
|
|
159
|
+
|
|
160
|
+
The user statement can pass only 2 arguments to `call` if the first report in the `REPORTDIR_RAW` directory is the desired raw report. If there are multiple reports in that directory and the desired one is not the first, the user must pass 3 arguments to `call`, and the third argument must be a string, such that the first report in that directory that begins with that string is the desired report.
|
|
161
|
+
|
|
162
|
+
The `score` function neither reads nor writes files. Its arguments are a score-proc string and a raw-report object, and it returns a scored-report object.
|
|
163
|
+
|
|
164
|
+
### `multiScore`
|
|
165
|
+
|
|
166
|
+
The `multiScore` function scores all the reports in the `REPORTDIR_RAW` directory and writes the scored reports in the `REPORTDIR_SCORED` directory.
|
|
107
167
|
|
|
108
168
|
Execution by a module:
|
|
109
169
|
|
|
110
170
|
```javaScript
|
|
111
|
-
const {
|
|
112
|
-
|
|
171
|
+
const {multiScore} = require('testilo/multiScore');
|
|
172
|
+
multiScore('sp25a')
|
|
113
173
|
.then(hostCount => {
|
|
114
174
|
console.log(`Scoring complete. Count of reports scored: ${hostCount}`);
|
|
115
175
|
});
|
|
@@ -118,40 +178,78 @@ score('sp25a', '756mr')
|
|
|
118
178
|
Execution by a user:
|
|
119
179
|
|
|
120
180
|
```bash
|
|
121
|
-
node call
|
|
181
|
+
node call multiScore sp25a
|
|
122
182
|
```
|
|
123
183
|
|
|
124
|
-
The
|
|
184
|
+
The argument to `multiScore` names the score proc to be used. The `multiScore` function scores all the reports in the `REPORTDIR_RAW` directory and writes the scored reports in the `REPORTDIR_SCORED` directory.
|
|
125
185
|
|
|
126
186
|
### `digest`
|
|
127
187
|
|
|
128
|
-
Testaro reports, both originally and after they are scored, are
|
|
188
|
+
Testaro reports, both originally and after they are scored, are JavaScript objects. When represented as JSON, they are human-readable, but basically designed for machine tractability.
|
|
129
189
|
|
|
130
|
-
The `digest` function converts scored reports into HTML documents with explanatory content. Thus, it converts machine-oriented reports into human-oriented reports, called _digests_. It depends on _digest
|
|
190
|
+
The `digest` function converts scored reports into HTML documents with explanatory content. Thus, it converts machine-oriented reports into human-oriented reports, called _digests_. It depends on a _digest proc_ to define the digesting rules. Some digest procs are in the Testilo package (in the `procs/digest` directory), and you can create more digest procs to implement different rules.
|
|
131
191
|
|
|
132
192
|
Execution by a module:
|
|
133
193
|
|
|
134
194
|
```javaScript
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
195
|
+
const fs = require('fs/promises');
|
|
196
|
+
const digestReport = async scoredReport => {
|
|
197
|
+
const {digest} = require('testilo/digest');
|
|
198
|
+
const procJSON = await fs.readFile(`${process.env.DIGESTPROCDIR}/dp25a.json`, 'utf8');
|
|
199
|
+
const proc = JSON.parse(procJSON);
|
|
200
|
+
const digest = digest(proc, scoredReport);
|
|
201
|
+
await fs.writeFile(
|
|
202
|
+
`${process.env.REPORTDIR_DIGESTED}/${digest.id}.json`, JSON.stringify(digest, null, 2)
|
|
203
|
+
);
|
|
204
|
+
console.log(`Report ${digest.id} digested`);
|
|
205
|
+
};
|
|
206
|
+
fs.readFile(`${process.env.REPORTDIR_SCORED}/756mr-tp25-w3c.json`, 'utf8')
|
|
207
|
+
.then(scoredReportJSON => {
|
|
208
|
+
const scoredReport = JSON.parse(scoredReportJSON);
|
|
209
|
+
digestReport(scoredReport);
|
|
139
210
|
});
|
|
140
211
|
```
|
|
141
212
|
|
|
142
213
|
Execution by a user:
|
|
143
214
|
|
|
144
215
|
```bash
|
|
216
|
+
node call digest sp25a
|
|
145
217
|
node call digest sp25a 756mr
|
|
146
218
|
```
|
|
147
219
|
|
|
148
|
-
|
|
220
|
+
In these examples, the `digest` function applies a digest proc named `dp25a`, of which a copy is in the file `dp25a.json` in the `DIGESTPROCDIR` directory, to a scored report `756mr-tp25-w3c.json` in the `REPORTDIR_SCORED` directory and returns an HTML digest for that same report. The digest is saved in the `REPORTDIR_DIGESTED` directory.
|
|
221
|
+
|
|
222
|
+
The user statement can pass only 2 arguments to `call` if the first report in the `REPORTDIR_SCORED` directory is the desired scored report. If there are multiple reports in that directory and the desired one is not the first, the user must pass 3 arguments to `call`, and the third argument must be a string, such that the first report in that directory that begins with that string is the desired report.
|
|
223
|
+
|
|
224
|
+
The `digest` function neither reads nor writes files. Its arguments are a digest-proc string and a scored-report object, and it returns a digest HTML string.
|
|
225
|
+
|
|
226
|
+
### `multiDigest`
|
|
227
|
+
|
|
228
|
+
The `multiDigest` function digests all the reports in the `REPORTDIR_SCORED` directory and writes the digests in the `REPORTDIR_DIGESTED` directory.
|
|
229
|
+
|
|
230
|
+
Execution by a module:
|
|
231
|
+
|
|
232
|
+
```javaScript
|
|
233
|
+
const {multiDigest} = require('testilo/multiDigest');
|
|
234
|
+
multiDigest('dp25a')
|
|
235
|
+
.then(hostCount => {
|
|
236
|
+
console.log(`Digesting complete. Count of reports digested: ${hostCount}`);
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Execution by a user:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
node call multiDigest dp25a
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The argument to `multiDigest` or the second argument to `call` names the digest proc to be used. The `multiDigest` function digests all the reports in the `REPORTDIR_SCORED` directory and writes the digests in the `REPORTDIR_DIGESTED` directory.
|
|
149
247
|
|
|
150
248
|
The digests created by `digest` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/digested/style.css` file in Testilo is an appropriate stylesheet to be copied into the `REPORTDIR_DIGESTED` directory.
|
|
151
249
|
|
|
152
250
|
### `compare`
|
|
153
251
|
|
|
154
|
-
You can summarize
|
|
252
|
+
You can summarize multiple scored reports by producing a document comparing the scores. The `compare` function does this. It gathers scores from a set of scored reports and produces an HTML document comparing the scores. It depends on a _comparison proc_ to define the rules for making and showing the comparative scores. Some compare procs are in the Testilo package (in the `procs/compare` directory), and you can create more compare procs to implement different rules.
|
|
155
253
|
|
|
156
254
|
Execution by a module:
|
|
157
255
|
|
|
@@ -169,6 +267,6 @@ Execution by a user:
|
|
|
169
267
|
node call compare cp25a legislators
|
|
170
268
|
```
|
|
171
269
|
|
|
172
|
-
The first argument to `compare`
|
|
270
|
+
The first argument to `compare`, or the second argument to `call`, names the comparison proc to be used. The subsequent argument specifies a base of the name of the comparative report that will be produced. The scores in all reports in the `REPORTDIR_SCORED` directory will be compared. The comparative report will be written in the `COMPARISONDIR` directory.
|
|
173
271
|
|
|
174
|
-
The
|
|
272
|
+
The comparison created by `compare` is an HTML file, and it expects a `style.css` file to exist in its directory. The `reports/comparative/style.css` file in Testilo is an appropriate stylesheet to be copied into the `COMPARISONDIR` directory.
|
package/aim.js
CHANGED
|
@@ -3,25 +3,11 @@
|
|
|
3
3
|
Module for aiming a script at a host.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
// ########## IMPORTS
|
|
7
|
-
|
|
8
|
-
// Module to keep secrets.
|
|
9
|
-
require('dotenv').config();
|
|
10
|
-
// Module to read and write files.
|
|
11
|
-
const fs = require('fs/promises');
|
|
12
|
-
|
|
13
|
-
// ########## CONSTANTS
|
|
14
|
-
|
|
15
|
-
const scriptDir = process.env.SCRIPTDIR || 'scripts';
|
|
16
|
-
|
|
17
6
|
// ########## FUNCTIONS
|
|
18
7
|
|
|
19
8
|
// Returns a script, aimed at a host.
|
|
20
|
-
exports.aim = async (
|
|
21
|
-
//
|
|
22
|
-
const scriptFile = await fs.readFile(`${scriptDir}/${scriptName}.json`, 'utf8');
|
|
23
|
-
const script = JSON.parse(scriptFile);
|
|
24
|
-
// In the copy, make all url commands visit the host.
|
|
9
|
+
exports.aim = async (script, host, requester) => {
|
|
10
|
+
// Make all url commands in the script visit the host.
|
|
25
11
|
script.commands.forEach(command => {
|
|
26
12
|
if (command.type === 'url') {
|
|
27
13
|
command.id = host.id;
|
|
@@ -37,8 +23,8 @@ exports.aim = async (scriptName, host, requester) => {
|
|
|
37
23
|
}
|
|
38
24
|
// Create a job-creation time stamp.
|
|
39
25
|
const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
|
|
40
|
-
//
|
|
41
|
-
script.
|
|
26
|
+
// Add a job-ID property to the script, including the time stamp, the script ID, and the host ID.
|
|
27
|
+
script.jobID = `${timeStamp}-${script.id}-${host.id}`;
|
|
42
28
|
// Return the host-specific script.
|
|
43
29
|
return script;
|
|
44
30
|
};
|
package/digest.js
CHANGED
|
@@ -1,53 +1,25 @@
|
|
|
1
1
|
/*
|
|
2
2
|
digest.js
|
|
3
|
-
Creates
|
|
4
|
-
Reads reports in process.env.REPORTDIR_SCORED and outputs into process.env.REPORTDIR_DIGESTED.
|
|
3
|
+
Creates a digest from a scored report.
|
|
5
4
|
Arguments:
|
|
6
|
-
0.
|
|
7
|
-
1
|
|
8
|
-
|
|
9
|
-
node digest dp18a 35k1r (to digest all scored reports with names starting with 35k1r)
|
|
10
|
-
node digest dp18a (to digest all scored reports)
|
|
5
|
+
0. Digest template.
|
|
6
|
+
1. Digest proc.
|
|
7
|
+
2. Scored report.
|
|
11
8
|
*/
|
|
12
9
|
|
|
13
|
-
// ########## IMPORTS
|
|
14
|
-
|
|
15
|
-
// Module to keep secrets.
|
|
16
|
-
require('dotenv').config();
|
|
17
|
-
// Module to read and write files.
|
|
18
|
-
const fs = require('fs/promises');
|
|
19
|
-
|
|
20
|
-
// ########## CONSTANTS
|
|
21
|
-
|
|
22
|
-
const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
|
|
23
|
-
const reportDirDigested = process.env.REPORTDIR_DIGESTED || 'reports/digested';
|
|
24
|
-
const digestProcDir = process.env.DIGESTPROCDIR || `${__dirname}/procs/digest`;
|
|
25
|
-
|
|
26
10
|
// ########## FUNCTIONS
|
|
27
11
|
|
|
28
12
|
// Replaces the placeholders in content with eponymous query parameters.
|
|
29
13
|
const replaceHolders = (content, query) => content
|
|
30
14
|
.replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
|
|
31
|
-
// Creates
|
|
32
|
-
exports.digest =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const reportJSON = await fs.readFile(`${reportDirScored}/${fileName}`, 'utf8');
|
|
42
|
-
const report = JSON.parse(reportJSON);
|
|
43
|
-
const query = {};
|
|
44
|
-
makeQuery(report, query);
|
|
45
|
-
const template = await fs
|
|
46
|
-
.readFile(`${digestProcDir}/${digesterID}/index.html`, 'utf8');
|
|
47
|
-
const digest = replaceHolders(template, query);
|
|
48
|
-
const fileNameBase = fileName.slice(0, -5);
|
|
49
|
-
await fs.writeFile(`${reportDirDigested}/${fileNameBase}.html`, digest);
|
|
50
|
-
console.log(`Report ${fileNameBase} digested and saved`);
|
|
51
|
-
};
|
|
52
|
-
return reportFileNames.length;
|
|
15
|
+
// Creates a digest.
|
|
16
|
+
exports.digest = (digestTemplate, digestProc, scoredReport) => {
|
|
17
|
+
// Create a query.
|
|
18
|
+
const query = {};
|
|
19
|
+
digestProc(scoredReport, query);
|
|
20
|
+
// Use it to replace the placeholders in the template.
|
|
21
|
+
const digest = replaceHolders(digestTemplate, query);
|
|
22
|
+
// Return the digest.
|
|
23
|
+
console.log(`Report ${scoredReport.id} digested`);
|
|
24
|
+
return digest;
|
|
53
25
|
};
|
package/multiDigest.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
multiDigest.js
|
|
3
|
+
Creates digests from scored reports.
|
|
4
|
+
Reads all reports in process.env.REPORTDIR_SCORED and outputs them, digested, into
|
|
5
|
+
process.env.REPORTDIR_DIGESTED.
|
|
6
|
+
Argument:
|
|
7
|
+
0. Base of name of digest proc located in process.env.DIGESTPROCDIR.
|
|
8
|
+
Usage example: node digest dp25a
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ########## IMPORTS
|
|
12
|
+
|
|
13
|
+
// Module to keep secrets.
|
|
14
|
+
require('dotenv').config();
|
|
15
|
+
// Module to read and write files.
|
|
16
|
+
const fs = require('fs/promises');
|
|
17
|
+
|
|
18
|
+
// ########## CONSTANTS
|
|
19
|
+
|
|
20
|
+
const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
|
|
21
|
+
const reportDirDigested = process.env.REPORTDIR_DIGESTED || 'reports/digested';
|
|
22
|
+
const digestProcDir = process.env.DIGESTPROCDIR || `${__dirname}/procs/digest`;
|
|
23
|
+
|
|
24
|
+
// ########## FUNCTIONS
|
|
25
|
+
|
|
26
|
+
// Replaces the placeholders in content with eponymous query parameters.
|
|
27
|
+
const replaceHolders = (content, query) => content
|
|
28
|
+
.replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
|
|
29
|
+
// Creates digests.
|
|
30
|
+
exports.multiDigest = async (digesterID, reportIDStart) => {
|
|
31
|
+
// Identify the reports to be digested.
|
|
32
|
+
let reportFileNames = await fs.readdir(reportDirScored);
|
|
33
|
+
reportFileNames = reportFileNames.filter(fileName => fileName.endsWith('.json'));
|
|
34
|
+
// For each report:
|
|
35
|
+
const {makeQuery} = require(`${digestProcDir}/${digesterID}/index.js`);
|
|
36
|
+
for (const fileName of reportFileNames) {
|
|
37
|
+
const reportJSON = await fs.readFile(`${reportDirScored}/${fileName}`, 'utf8');
|
|
38
|
+
const report = JSON.parse(reportJSON);
|
|
39
|
+
// Define its replacements for the placeholders in the digest template.
|
|
40
|
+
const query = {};
|
|
41
|
+
makeQuery(report, query);
|
|
42
|
+
// Replace the placeholders.
|
|
43
|
+
const template = await fs.readFile(`${digestProcDir}/${digesterID}/index.html`, 'utf8');
|
|
44
|
+
const digest = replaceHolders(template, query);
|
|
45
|
+
// Write its digest.
|
|
46
|
+
const fileNameBase = fileName.slice(0, -5);
|
|
47
|
+
await fs.writeFile(`${reportDirDigested}/${fileNameBase}.html`, digest);
|
|
48
|
+
console.log(`Report ${fileNameBase} digested and saved`);
|
|
49
|
+
};
|
|
50
|
+
return reportFileNames.length;
|
|
51
|
+
};
|
package/multiScore.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
multiScore.js
|
|
3
|
+
Scores multiple Testaro reports.
|
|
4
|
+
Reads all reports in process.env.REPORTDIR_RAW and outputs them, scored, into
|
|
5
|
+
process.env.REPORTDIR_SCORED.
|
|
6
|
+
Arguments:
|
|
7
|
+
0. Base of name of score proc located in process.env.SCOREPROCDIR.
|
|
8
|
+
Usage example: node score sp18a
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ########## IMPORTS
|
|
12
|
+
|
|
13
|
+
// Module to keep secrets.
|
|
14
|
+
require('dotenv').config();
|
|
15
|
+
// Module to read and write files.
|
|
16
|
+
const fs = require('fs/promises');
|
|
17
|
+
|
|
18
|
+
// ########## CONSTANTS
|
|
19
|
+
|
|
20
|
+
const reportDirRaw = process.env.REPORTDIR_RAW || 'reports/raw';
|
|
21
|
+
const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
|
|
22
|
+
const scoreProcDir = process.env.SCOREPROCDIR || `${__dirname}/procs/score`;
|
|
23
|
+
|
|
24
|
+
// ########## FUNCTIONS
|
|
25
|
+
|
|
26
|
+
// Score the specified reports and return their count.
|
|
27
|
+
exports.score = async scoreProcID => {
|
|
28
|
+
// Identify the reports to be scored.
|
|
29
|
+
let reportFileNames = await fs.readdir(reportDirRaw);
|
|
30
|
+
reportFileNames = reportFileNames.filter(fileName => fileName.endsWith('.json'));
|
|
31
|
+
// For each of them:
|
|
32
|
+
const {scorer} = require(`${scoreProcDir}/${scoreProcID}`);
|
|
33
|
+
for (const fileName of reportFileNames) {
|
|
34
|
+
// Score it.
|
|
35
|
+
const reportJSON = await fs.readFile(`${reportDirRaw}/${fileName}`, 'utf8');
|
|
36
|
+
const report = JSON.parse(reportJSON);
|
|
37
|
+
await scorer(report);
|
|
38
|
+
report.scoreProcID = scoreProcID;
|
|
39
|
+
// Write it to a file.
|
|
40
|
+
const scoredReportJSON = JSON.stringify(report, null, 2);
|
|
41
|
+
await fs.writeFile(`${reportDirScored}/${fileName}`, `${scoredReportJSON}\n`);
|
|
42
|
+
console.log(`Report ${fileName.slice(0, -5)} scored and saved`);
|
|
43
|
+
};
|
|
44
|
+
return reportFileNames.length;
|
|
45
|
+
};
|
package/package.json
CHANGED
package/score.js
CHANGED
|
@@ -1,50 +1,19 @@
|
|
|
1
1
|
/*
|
|
2
2
|
score.js
|
|
3
|
-
Scores Testaro
|
|
4
|
-
Reads reports in process.env.REPORTDIR_RAW and outputs into process.env.REPORTDIR_SCORED.
|
|
3
|
+
Scores a Testaro report.
|
|
5
4
|
Arguments:
|
|
6
|
-
0.
|
|
7
|
-
1
|
|
8
|
-
Usage examples:
|
|
9
|
-
node score sp18a 35k1r (to score all reports with names starting with 35k1r)
|
|
10
|
-
node score sp18a (to score all reports)
|
|
5
|
+
0. Score proc.
|
|
6
|
+
1. Raw report.
|
|
11
7
|
*/
|
|
12
8
|
|
|
13
|
-
// ########## IMPORTS
|
|
14
|
-
|
|
15
|
-
// Module to keep secrets.
|
|
16
|
-
require('dotenv').config();
|
|
17
|
-
// Module to read and write files.
|
|
18
|
-
const fs = require('fs/promises');
|
|
19
|
-
|
|
20
|
-
// ########## CONSTANTS
|
|
21
|
-
|
|
22
|
-
const reportDirRaw = process.env.REPORTDIR_RAW || 'reports/raw';
|
|
23
|
-
const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
|
|
24
|
-
const scoreProcDir = process.env.SCOREPROCDIR || `${__dirname}/procs/score`;
|
|
25
|
-
|
|
26
9
|
// ########## FUNCTIONS
|
|
27
10
|
|
|
28
|
-
// Score the specified
|
|
29
|
-
exports.score = async (
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// For each of them:
|
|
37
|
-
const {scorer} = require(`${scoreProcDir}/${scoreProcID}`);
|
|
38
|
-
for (const fileName of reportFileNames) {
|
|
39
|
-
// Score it.
|
|
40
|
-
const reportJSON = await fs.readFile(`${reportDirRaw}/${fileName}`, 'utf8');
|
|
41
|
-
const report = JSON.parse(reportJSON);
|
|
42
|
-
await scorer(report);
|
|
43
|
-
report.scoreProcID = scoreProcID;
|
|
44
|
-
// Write it to a file.
|
|
45
|
-
const scoredReportJSON = JSON.stringify(report, null, 2);
|
|
46
|
-
await fs.writeFile(`${reportDirScored}/${fileName}`, `${scoredReportJSON}\n`);
|
|
47
|
-
console.log(`Report ${fileName.slice(0, -5)} scored and saved`);
|
|
48
|
-
};
|
|
49
|
-
return reportFileNames.length;
|
|
11
|
+
// Score the specified raw report and return it, scored.
|
|
12
|
+
exports.score = async (scoreProc, rawReport) => {
|
|
13
|
+
// Initialize a scored report.
|
|
14
|
+
const scoredReport = JSON.parse(JSON.stringify(rawReport));
|
|
15
|
+
// Score it.
|
|
16
|
+
await scoreProc(scoredReport);
|
|
17
|
+
console.log(`Report ${rawReport.id} scored`);
|
|
18
|
+
return scoredReport;
|
|
50
19
|
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE HTML>
|
|
2
|
-
<html lang="en-US">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<meta name="author" content="Testilo">
|
|
7
|
-
<meta name="creator" content="Testilo">
|
|
8
|
-
<meta name="publisher" name="Testilo">
|
|
9
|
-
<meta name="description" content="report of accessibility testing of a web page">
|
|
10
|
-
<meta name="keywords" content="accessibility a11y web testing">
|
|
11
|
-
<title>Accessibility test digest</title>
|
|
12
|
-
<link rel="icon" href="favicon.png">
|
|
13
|
-
<link rel="stylesheet" href="style.css">
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<main>
|
|
17
|
-
<header>
|
|
18
|
-
<h1>Accessibility test digest</h1>
|
|
19
|
-
<h2>Synopsis</h2>
|
|
20
|
-
<div id="synopsis">
|
|
21
|
-
<p><strong>Page</strong>: __org__</p>
|
|
22
|
-
<p><strong>URL</strong>: __url__</p>
|
|
23
|
-
<p><strong>Score</strong>: __totalScore__</p>
|
|
24
|
-
<p><strong>Tested by</strong>: Testaro, procedure <code>__tp__</code></p>
|
|
25
|
-
<p><strong>Scored by</strong>: Testilo, procedure <code>__sp__</code></p>
|
|
26
|
-
<p><strong>Digested by</strong>: Testilo, procedure <code>__dp__</code></p>
|
|
27
|
-
</div>
|
|
28
|
-
</header>
|
|
29
|
-
<h2>Introduction</h2>
|
|
30
|
-
<p>The <a href="https://www.npmjs.com/package/testaro">Testaro</a> application used its <code>__tp__</code> testing procedure to test the <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/"><dfn>accessibility</dfn></a> (barrier-free design and coding) of the __org__ web page at <a href="__url__">__url__</a> on __dateSlash__. The procedure performed 1230 tests. Of these, 24 are custom tests or <q>quasi-tests</q> by Testaro, and the others belong to these eight other packages (programs that perform collections of tests):</p>
|
|
31
|
-
<ul>
|
|
32
|
-
<li><a href="https://github.com/Siteimprove/alfa">Alfa</a> by Siteimprove</li>
|
|
33
|
-
<li><a href="https://www.npmjs.com/package/axe-core">Axe-core</a> by Deque</li>
|
|
34
|
-
<li><a href="https://www.webaccessibility.com/tools/">Continuum</a> by Level Access</li>
|
|
35
|
-
<li>
|
|
36
|
-
<a href="https://www.npmjs.com/package/html_codesniffer">HTML CodeSniffer</a> by Squiz Labs
|
|
37
|
-
</li>
|
|
38
|
-
<li><a href="https://github.com/IBMa/equal-access">Equal Access</a> by IBM</li>
|
|
39
|
-
<li><a href="https://github.com/validator/validator">Nu Html Checker</a></li>
|
|
40
|
-
<li><a href="https://tenon.io/documentation/apiv2.php">Tenon</a> by Level Access</li>
|
|
41
|
-
<li><a href="https://wave.webaim.org/api/">WAVE</a> by WebAIM</li>
|
|
42
|
-
</ul>
|
|
43
|
-
<p>Testaro produced a report enumerating the test results.</p>
|
|
44
|
-
<p><a href="https://www.npmjs.com/package/testilo">Testilo</a> processed the report and used the <code>__sp__</code> scoring procedure to compute partial and total scores for the page. The total score is __totalScore__ (where 0 is the best possible score). The scored report is appended below.</p>
|
|
45
|
-
<p>Finally, Testilo used procedure <code>__dp__</code> to produce this digest, briefly explaining how <code>__sp__</code> computed the scores.</p>
|
|
46
|
-
<h2>Score summary</h2>
|
|
47
|
-
<p>Total score: __totalScore__</p>
|
|
48
|
-
<h2>Report</h2>
|
|
49
|
-
<pre>__report__</pre>
|
|
50
|
-
<footer>
|
|
51
|
-
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
52
|
-
</footer>
|
|
53
|
-
</main>
|
|
54
|
-
</body>
|
|
55
|
-
</html>
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
index: digester for scoring procedure sp19a.
|
|
3
|
-
Creator of parameters for substitution into index.html.
|
|
4
|
-
Usage example for selected files in REPORTDIR_SCORED: node digest dp18a 35k1r
|
|
5
|
-
Usage example for all files in REPORTDIR_SCORED: node digest dp18a
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// FUNCTIONS
|
|
9
|
-
|
|
10
|
-
// Makes strings HTML-safe.
|
|
11
|
-
const htmlEscape = textOrNumber => textOrNumber
|
|
12
|
-
.toString()
|
|
13
|
-
.replace(/&/g, '&')
|
|
14
|
-
.replace(/</g, '<');
|
|
15
|
-
// Adds parameters to a query for a digest.
|
|
16
|
-
exports.makeQuery = (report, query) => {
|
|
17
|
-
// Add an HTML-safe copy of the report to the query to be appended to the digest.
|
|
18
|
-
const {script, host, score} = report;
|
|
19
|
-
const reportJSON = JSON.stringify(report, null, 2);
|
|
20
|
-
const reportJSONSafe = htmlEscape(reportJSON);
|
|
21
|
-
query.report = reportJSONSafe;
|
|
22
|
-
query.tp = 'tp19';
|
|
23
|
-
query.sp = 'sp19a';
|
|
24
|
-
query.dp = 'dp19a';
|
|
25
|
-
// Add the job data to the query.
|
|
26
|
-
query.dateISO = report.jobData.endTime.slice(0, 10);
|
|
27
|
-
query.dateSlash = query.dateISO.replace(/-/g, '/');
|
|
28
|
-
if (host && host.what && host.which) {
|
|
29
|
-
query.org = host.what;
|
|
30
|
-
query.url = host.which;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
const firstURLCommand = script.commands.find(command => command.type === 'url');
|
|
34
|
-
if (firstURLCommand && firstURLCommand.what && firstURLCommand.which) {
|
|
35
|
-
query.org = firstURLCommand.what;
|
|
36
|
-
query.url = firstURLCommand.which;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
console.log('ERROR: host missing or invalid');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
query.totalScore = score;
|
|
44
|
-
};
|
package/procs/score/sp19a.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
sp18a
|
|
3
|
-
Testilo score proc 19a
|
|
4
|
-
|
|
5
|
-
Computes scores from Testaro script tp19 and adds them to a report.
|
|
6
|
-
Usage examples:
|
|
7
|
-
node score sp19a 35k1r
|
|
8
|
-
node score sp19a
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// Scores a report.
|
|
12
|
-
exports.scorer = async report => {
|
|
13
|
-
// If there are any acts in the report:
|
|
14
|
-
const {acts} = report;
|
|
15
|
-
if (Array.isArray(acts)) {
|
|
16
|
-
// If any of them are test acts:
|
|
17
|
-
const testActs = acts.filter(act => act.type === 'test');
|
|
18
|
-
if (testActs.length) {
|
|
19
|
-
report.scoreProcID = 'sp19a';
|
|
20
|
-
report.score = 0;
|
|
21
|
-
// For each test act:
|
|
22
|
-
testActs.forEach(test => {
|
|
23
|
-
const {which} = test;
|
|
24
|
-
if (which === 'bulk') {
|
|
25
|
-
const count = test.result && test.result.visibleElements;
|
|
26
|
-
if (typeof count === 'number') {
|
|
27
|
-
// Add 1 to the score per 300 visible elements beyond 300.
|
|
28
|
-
report.score += Math.max(0, count / 300 - 1);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|