testilo 7.1.1 → 9.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 +341 -149
- package/call.js +80 -154
- package/compare.js +14 -31
- package/digest.js +19 -11
- package/merge.js +109 -34
- package/package.json +1 -1
- package/procs/compare/cp20sqrt/index.html +48 -0
- package/procs/compare/cp20sqrt/index.js +69 -0
- package/procs/score/sp20b.js +1 -1
- package/score.js +18 -11
- package/validation/call/jobs/done/8oqso-script-accordion.json +57 -0
- package/validation/call/jobs/done/8oqso-script-example.json +47 -0
- package/validation/call/specs/batches/batch.json +43 -0
- package/validation/call/specs/scripts/script.json +23 -0
- package/validation/compare/comparer.js +18 -0
- package/validation/compare/comparison.html +19 -0
- package/validation/compare/report0.json +78 -0
- package/validation/compare/report1.json +78 -0
- package/validation/compare/validate.js +51 -0
- package/validation/digest/digest.html +19 -0
- package/validation/digest/digester.js +12 -0
- package/validation/digest/report.json +78 -0
- package/validation/digest/validate.js +64 -0
- package/validation/merge/batch.json +43 -0
- package/validation/merge/script.json +33 -0
- package/validation/merge/validate.js +179 -0
- package/validation/score/report.json +75 -0
- package/validation/score/scorer.js +17 -0
- package/validation/score/validate.js +62 -0
- package/aim.js +0 -45
- package/multiDigest.js +0 -51
- package/multiScore.js +0 -48
package/call.js
CHANGED
|
@@ -1,204 +1,130 @@
|
|
|
1
1
|
/*
|
|
2
|
-
|
|
2
|
+
call.js
|
|
3
3
|
Invokes Testilo modules with arguments.
|
|
4
4
|
This is the universal module for use of Testilo from a command line.
|
|
5
5
|
Arguments:
|
|
6
6
|
0. function to execute.
|
|
7
7
|
1+. arguments to pass to the function.
|
|
8
8
|
Usage examples:
|
|
9
|
-
node call
|
|
10
|
-
node call
|
|
11
|
-
node call
|
|
12
|
-
node call
|
|
13
|
-
node call multiScore sp25a
|
|
14
|
-
node call digest dp25a (to digest the first scored report)
|
|
15
|
-
node call digest dp25a 8ep9f (to digest the first scored report whose name starts with 8ep9f)
|
|
16
|
-
node call multiDigest dp25a
|
|
17
|
-
node call compare cp25a weborgs (to write weborgs.html, comparing all scored reports)
|
|
9
|
+
node call merge ts25 webOrgs user@domain.tld true
|
|
10
|
+
node call score sp25a
|
|
11
|
+
node call digest dp25a
|
|
12
|
+
node call compare cp25a weborgs
|
|
18
13
|
*/
|
|
19
14
|
|
|
20
15
|
// ########## IMPORTS
|
|
21
16
|
|
|
22
17
|
// Module to keep secrets.
|
|
23
18
|
require('dotenv').config();
|
|
24
|
-
// Function to process
|
|
19
|
+
// Function to process files.
|
|
25
20
|
const fs = require('fs/promises');
|
|
26
|
-
|
|
27
|
-
// Function to process a script-batch merger.
|
|
21
|
+
// Function to process a merger.
|
|
28
22
|
const {merge} = require('./merge');
|
|
29
|
-
// Function to score
|
|
23
|
+
// Function to score reports.
|
|
30
24
|
const {score} = require('./score');
|
|
31
|
-
// Function to
|
|
32
|
-
const {multiScore} = require('./multiScore');
|
|
33
|
-
// Function to digest a report.
|
|
25
|
+
// Function to digest reports.
|
|
34
26
|
const {digest} = require('./digest');
|
|
35
|
-
// Function to digest multiple reports.
|
|
36
|
-
const {multiDigest} = require('./multiDigest');
|
|
37
27
|
// Function to compare scores.
|
|
38
28
|
const {compare} = require('./compare');
|
|
39
29
|
|
|
40
30
|
// ########## CONSTANTS
|
|
41
31
|
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const digestProcDir = process.env.DIGESTPROCDIR;
|
|
32
|
+
const specDir = process.env.SPECDIR;
|
|
33
|
+
const functionDir = process.env.FUNCTIONDIR;
|
|
45
34
|
const jobDir = process.env.JOBDIR;
|
|
46
|
-
const
|
|
47
|
-
const scoredDir = process.env.REPORTDIR_SCORED;
|
|
48
|
-
const digestedDir = process.env.REPORTDIR_DIGESTED;
|
|
49
|
-
const comparisonDir = process.env.COMPARISONDIR;
|
|
35
|
+
const reportDir = process.env.REPORTDIR;
|
|
50
36
|
const fn = process.argv[2];
|
|
51
37
|
const fnArgs = process.argv.slice(3);
|
|
52
38
|
|
|
53
39
|
// ########## FUNCTIONS
|
|
54
40
|
|
|
55
|
-
// Fulfills
|
|
56
|
-
const
|
|
57
|
-
|
|
41
|
+
// Fulfills a merging request.
|
|
42
|
+
const callMerge = async (scriptID, batchID, requester, withIsolation = false) => {
|
|
43
|
+
// Get the script and the batch.
|
|
44
|
+
const scriptJSON = await fs.readFile(`${specDir}/scripts/${scriptID}.json`, 'utf8');
|
|
58
45
|
const script = JSON.parse(scriptJSON);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
46
|
+
const batchJSON = await fs.readFile(`${specDir}/batches/${batchID}.json`, 'utf8');
|
|
47
|
+
const batch = JSON.parse(batchJSON);
|
|
48
|
+
// Merge them into an array of jobs.
|
|
49
|
+
const jobs = merge(script, batch, requester, withIsolation);
|
|
50
|
+
// Save the jobs.
|
|
51
|
+
for (const job of jobs) {
|
|
52
|
+
const jobJSON = JSON.stringify(job, null, 2);
|
|
53
|
+
await fs.writeFile(`${jobDir}/todo/${job.id}.json`, jobJSON);
|
|
54
|
+
}
|
|
55
|
+
const {timeStamp} = jobs[0];
|
|
56
|
+
console.log(
|
|
57
|
+
`Script ${scriptID} and batch ${batchID} merged; jobs ${timeStamp}… saved in ${jobDir}/todo`
|
|
67
58
|
);
|
|
68
|
-
const scriptID = job.sources.script;
|
|
69
|
-
const jobID = job.id;
|
|
70
|
-
await fs.writeFile(`${jobDir}/${jobID}.json`, `${JSON.stringify(job, null, 2)}\n`);
|
|
71
|
-
console.log(`Script ${scriptID} aimed at ${hostName} saved as job ${jobID}.json in ${jobDir}`);
|
|
72
59
|
};
|
|
73
|
-
//
|
|
74
|
-
const
|
|
75
|
-
await
|
|
76
|
-
|
|
60
|
+
// Get selected reports.
|
|
61
|
+
const getReports = async (type, selector = '') => {
|
|
62
|
+
const allFileNames = await fs.readdir(`${reportDir}/${type}`);
|
|
63
|
+
const reportIDs = allFileNames
|
|
64
|
+
.filter(fileName => fileName.endsWith('.json'))
|
|
65
|
+
.filter(fileName => fileName.startsWith(selector))
|
|
66
|
+
.map(fileName => fileName.slice(0, -5));
|
|
67
|
+
const reports = [];
|
|
68
|
+
for (const reportID of reportIDs) {
|
|
69
|
+
const reportJSON = await fs.readFile(`${reportDir}/${type}/${reportID}.json`, 'utf8');
|
|
70
|
+
const report = JSON.parse(reportJSON);
|
|
71
|
+
reports.push(report);
|
|
72
|
+
}
|
|
73
|
+
return reports;
|
|
77
74
|
};
|
|
78
75
|
// Fulfills a scoring request.
|
|
79
|
-
const callScore = async (
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
const rawReportNames = rawFileNames.filter(fileName => fileName.endsWith('.json'));
|
|
76
|
+
const callScore = async (scorerID, selector = '') => {
|
|
77
|
+
// Get the raw reports to be scored.
|
|
78
|
+
const reports = getReports('raw', selector);
|
|
83
79
|
// If any exist:
|
|
84
|
-
if (
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// If it exists:
|
|
94
|
-
if (rawReportName) {
|
|
95
|
-
// Score it.
|
|
96
|
-
const rawReportJSON = await fs.readFile(`${rawDir}/${rawReportName}`, 'utf8');
|
|
97
|
-
const rawReport = JSON.parse(rawReportJSON);
|
|
98
|
-
const {scorer} = require(`./${scoreProcDir}/${scoreProcID}.js`);
|
|
99
|
-
const scoredReport = await score(scorer, rawReport);
|
|
100
|
-
// Save it, scored.
|
|
80
|
+
if (reports.length) {
|
|
81
|
+
// Get the scorer.
|
|
82
|
+
const {scorer} = require(`${functionDir}/score/${scorerID}`);
|
|
83
|
+
// Score the reports.
|
|
84
|
+
const scoredReports = score(scorer, reports);
|
|
85
|
+
const scoredReportDir = `${reportDir}/scored`;
|
|
86
|
+
// For each scored report:
|
|
87
|
+
for (const scoredReport of scoredReports) {
|
|
88
|
+
// Save it.
|
|
101
89
|
await fs.writeFile(
|
|
102
|
-
`${
|
|
90
|
+
`${scoredReportDir}/${scoredReport.id}.json`, JSON.stringify(scoredReport, null, 2)
|
|
103
91
|
);
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
// Otherwise, i.e. if it does not exist:
|
|
107
|
-
else {
|
|
108
|
-
// Report this.
|
|
109
|
-
console.log('ERROR: Specified raw report not found');
|
|
110
|
-
}
|
|
92
|
+
};
|
|
111
93
|
}
|
|
112
|
-
// Otherwise, i.e. if no raw
|
|
94
|
+
// Otherwise, i.e. if no raw reports are to be scored:
|
|
113
95
|
else {
|
|
114
96
|
// Report this.
|
|
115
|
-
console.log('ERROR: No raw
|
|
97
|
+
console.log('ERROR: No raw reports to be scored');
|
|
116
98
|
}
|
|
117
99
|
};
|
|
118
|
-
// Fulfills a multiple-report scoring request.
|
|
119
|
-
const callMultiScore = async scoreProcID => {
|
|
120
|
-
// Score all raw reports.
|
|
121
|
-
await multiScore(scoreProcID);
|
|
122
|
-
};
|
|
123
|
-
// Prepares to fulfill a digesting request.
|
|
124
|
-
const digestPrep = async digestProcID => {
|
|
125
|
-
const {digest} = require('./digest');
|
|
126
|
-
const {makeQuery} = require(`./${digestProcDir}/${digestProcID}/index`);
|
|
127
|
-
const digestTemplate = await fs.readFile(`${digestProcDir}/${digestProcID}/index.html`, 'utf8');
|
|
128
|
-
// Identify the scored reports.
|
|
129
|
-
const scoredFileNames = await fs.readdir(scoredDir);
|
|
130
|
-
const scoredReportNames = scoredFileNames.filter(fileName => fileName.endsWith('.json'));
|
|
131
|
-
// Return the data required for the fulfillment of the request.
|
|
132
|
-
return {
|
|
133
|
-
anyScoredReports: scoredReportNames.length > 0,
|
|
134
|
-
digest,
|
|
135
|
-
makeQuery,
|
|
136
|
-
digestTemplate,
|
|
137
|
-
scoredReportNames
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
// Digests and saves a report.
|
|
141
|
-
const digestReport = async (scoredReportName, prepData) => {
|
|
142
|
-
// Digest the specified report.
|
|
143
|
-
const scoredReportJSON = await fs.readFile(`${scoredDir}/${scoredReportName}`, 'utf8');
|
|
144
|
-
const scoredReport = JSON.parse(scoredReportJSON);
|
|
145
|
-
const digestedReport = digest(prepData.digestTemplate, prepData.makeQuery, scoredReport);
|
|
146
|
-
// Save it, digested.
|
|
147
|
-
await fs.writeFile(`${digestedDir}/${scoredReport.job.id}.html`, digestedReport);
|
|
148
|
-
console.log(`Digested report ${scoredReport.job.id} saved in ${digestedDir}`);
|
|
149
|
-
};
|
|
150
100
|
// Fulfills a digesting request.
|
|
151
|
-
const callDigest = async (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
101
|
+
const callDigest = async (digesterID, selector = '') => {
|
|
102
|
+
// Get the scored reports to be digested.
|
|
103
|
+
const reports = getReports('scored', selector);
|
|
104
|
+
// If any exist:
|
|
105
|
+
if (reports.length) {
|
|
106
|
+
const digesterDir = `${functionDir}/digest/${digesterID}`;
|
|
107
|
+
// Get the digester.
|
|
108
|
+
const {digester} = require(`${digesterDir}/index`);
|
|
109
|
+
// Get the template.
|
|
110
|
+
const template = await fs.readFile(`${digesterDir}/index.html`);
|
|
111
|
+
// Digest the reports.
|
|
112
|
+
const digestedReports = digest(template, digester, reports);
|
|
113
|
+
const digestedReportDir = `${reportDir}/digested`;
|
|
114
|
+
// For each digested report:
|
|
115
|
+
for (const digestedReport of digestedReports) {
|
|
116
|
+
// Save it.
|
|
117
|
+
await fs.writeFile(
|
|
118
|
+
`${digestedReportDir}/${digestedReport.id}.json`, JSON.stringify(digestedReport, null, 2)
|
|
160
119
|
);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
scoredReportName = prepData.scoredReportNames[0];
|
|
164
|
-
}
|
|
165
|
-
// If it exists:
|
|
166
|
-
if (scoredReportName) {
|
|
167
|
-
// Digest and save it.
|
|
168
|
-
await digestReport(scoredReportName, prepData);
|
|
169
|
-
}
|
|
170
|
-
// Otherwise, i.e. if it does not exist:
|
|
171
|
-
else {
|
|
172
|
-
// Report this.
|
|
173
|
-
console.log('ERROR: Specified scored report not found');
|
|
174
|
-
}
|
|
120
|
+
};
|
|
175
121
|
}
|
|
176
|
-
// Otherwise, i.e. if no scored
|
|
122
|
+
// Otherwise, i.e. if no scored reports are to be digested:
|
|
177
123
|
else {
|
|
178
124
|
// Report this.
|
|
179
|
-
console.log('ERROR: No scored
|
|
125
|
+
console.log('ERROR: No scored reports to be digested');
|
|
180
126
|
}
|
|
181
127
|
};
|
|
182
|
-
// Fulfills a multiple-report digesting request.
|
|
183
|
-
const callMultiDigest = async digestProcID => {
|
|
184
|
-
const prepData = await digestPrep(digestProcID);
|
|
185
|
-
// If any scored reports exist:
|
|
186
|
-
if (prepData.anyScoredReports) {
|
|
187
|
-
// For each of them:
|
|
188
|
-
for (const scoredReportName of prepData.scoredReportNames) {
|
|
189
|
-
// Digest and save it.
|
|
190
|
-
await digestReport(scoredReportName, prepData);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
// Otherwise, i.e. if no raw report exists:
|
|
194
|
-
else {
|
|
195
|
-
// Report this.
|
|
196
|
-
console.log('ERROR: No raw report found');
|
|
197
|
-
}
|
|
198
|
-
console.log(
|
|
199
|
-
`Digesting completed. Digest proc: ${digestProcID}. Report count: ${prepData.scoredReportNames.length}. Directory: ${digestedDir}.`
|
|
200
|
-
);
|
|
201
|
-
};
|
|
202
128
|
// Fulfills a comparison request.
|
|
203
129
|
const callCompare = async (compareProcID, comparisonNameBase) => {
|
|
204
130
|
await compare(compareProcID, comparisonNameBase);
|
|
@@ -216,7 +142,7 @@ if (fn === 'aim' && fnArgs.length === 5) {
|
|
|
216
142
|
console.log('Execution completed');
|
|
217
143
|
});
|
|
218
144
|
}
|
|
219
|
-
else if (fn === 'merge' && fnArgs.length >
|
|
145
|
+
else if (fn === 'merge' && fnArgs.length > 2 && fnArgs.length < 5) {
|
|
220
146
|
callMerge(... fnArgs)
|
|
221
147
|
.then(() => {
|
|
222
148
|
console.log('Execution completed');
|
package/compare.js
CHANGED
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
/*
|
|
2
2
|
compare.js
|
|
3
|
-
Creates
|
|
4
|
-
Reads reports in process.env.REPORTDIR_SCORED and outputs into process.env.COMPARISONDIR.
|
|
5
|
-
Arguments:
|
|
6
|
-
0. Base of name of compare proc located in procs/compare.
|
|
7
|
-
1. Base of name of comparative report to be written.
|
|
8
|
-
Usage example: node compare cp18a usFedExec
|
|
9
|
-
Note: Compares all reports in process.env.REPORTDIR_SCORED (but not in its subdirectories).
|
|
3
|
+
Creates a comparative report from scored reports.
|
|
10
4
|
*/
|
|
11
5
|
|
|
12
|
-
// ########## IMPORTS
|
|
13
|
-
|
|
14
|
-
// Module to keep secrets.
|
|
15
|
-
require('dotenv').config();
|
|
16
|
-
// Module to read and write files.
|
|
17
|
-
const fs = require('fs/promises');
|
|
18
|
-
|
|
19
|
-
// ########## CONSTANTS
|
|
20
|
-
|
|
21
|
-
const comparisonDir = process.env.COMPARISONDIR || 'reports/comparative';
|
|
22
|
-
|
|
23
6
|
// ########## FUNCTIONS
|
|
24
7
|
|
|
25
|
-
// Replaces the placeholders in
|
|
26
|
-
const replaceHolders = (
|
|
8
|
+
// Replaces the placeholders in a template with eponymous query parameters.
|
|
9
|
+
const replaceHolders = (template, query) => template
|
|
27
10
|
.replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
|
|
28
|
-
//
|
|
29
|
-
exports.compare =
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
11
|
+
// Compares the scored reports and returns a comparison.
|
|
12
|
+
exports.compare = (comparisonTemplate, comparer, reports) => {
|
|
13
|
+
// Create a query.
|
|
14
|
+
const query = {};
|
|
15
|
+
// Populate the query.
|
|
16
|
+
comparer(reports, query);
|
|
17
|
+
// Use it to create a comparison.
|
|
18
|
+
const comparison = replaceHolders(comparisonTemplate, query);
|
|
19
|
+
// Return the comparison.
|
|
20
|
+
console.log(`Comparison complete. Report count: ${reports.length}`);
|
|
21
|
+
return comparison;
|
|
39
22
|
};
|
package/digest.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
2
|
digest.js
|
|
3
|
-
Creates
|
|
3
|
+
Creates digests from a scored reports.
|
|
4
4
|
Arguments:
|
|
5
5
|
0. Digest template.
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
6
|
+
1. Digesting function.
|
|
7
|
+
2. Array of scored reports.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
// ########## FUNCTIONS
|
|
@@ -12,14 +12,22 @@
|
|
|
12
12
|
// Replaces the placeholders in content with eponymous query parameters.
|
|
13
13
|
const replaceHolders = (content, query) => content
|
|
14
14
|
.replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
|
|
15
|
-
//
|
|
16
|
-
exports.digest = (digestTemplate,
|
|
15
|
+
// Digests the scored reports and returns them, digested.
|
|
16
|
+
exports.digest = (digestTemplate, digester, reports) => {
|
|
17
|
+
const digests = [];
|
|
17
18
|
// Create a query.
|
|
18
19
|
const query = {};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
// For each report:
|
|
21
|
+
for (const report of reports) {
|
|
22
|
+
// Populate the query.
|
|
23
|
+
digester(report, query);
|
|
24
|
+
// Use it to create a digest.
|
|
25
|
+
const digestedReport = replaceHolders(digestTemplate, query);
|
|
26
|
+
// Add the digest to the array of digests.
|
|
27
|
+
digests.push(digestedReport);
|
|
28
|
+
console.log(`Report ${report.id} digested`);
|
|
29
|
+
};
|
|
30
|
+
// Return the digests.
|
|
31
|
+
console.log(`Digesting complete. Report count: ${reports.length}`);
|
|
32
|
+
return digests;
|
|
25
33
|
};
|
package/merge.js
CHANGED
|
@@ -1,53 +1,128 @@
|
|
|
1
1
|
/*
|
|
2
2
|
merge.js
|
|
3
|
-
Merges a
|
|
3
|
+
Merges a script and a batch and returns jobs.
|
|
4
4
|
Arguments:
|
|
5
|
-
0.
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
8
|
-
Usage examples:
|
|
9
|
-
node call merge ts25 weborgs developer@w3.org
|
|
10
|
-
node call merge ts25 weborgs
|
|
11
|
-
Note: The subdirectory for jobs will be created if it does not exist.
|
|
5
|
+
0. script
|
|
6
|
+
1. batch
|
|
7
|
+
2. whether to provide test isolation (no if omitted)
|
|
12
8
|
*/
|
|
13
9
|
|
|
14
10
|
// ########## IMPORTS
|
|
15
11
|
|
|
16
12
|
// Module to keep secrets.
|
|
17
13
|
require('dotenv').config();
|
|
18
|
-
// Module to read and write files.
|
|
19
|
-
const fs = require('fs/promises');
|
|
20
|
-
// Module to aim a script at a host.
|
|
21
|
-
const {aim} = require('./aim');
|
|
22
14
|
|
|
23
15
|
// ########## CONSTANTS
|
|
24
16
|
|
|
25
|
-
const scriptDir = process.env.SCRIPTDIR || 'scripts';
|
|
26
|
-
const batchDir = process.env.BATCHDIR || 'batches';
|
|
27
|
-
const jobDir = process.env.JOBDIR || 'watch';
|
|
28
17
|
const stdRequester = process.env.REQUESTER;
|
|
18
|
+
const contaminantNames = new Set([
|
|
19
|
+
'axe',
|
|
20
|
+
'continuum',
|
|
21
|
+
'focAll',
|
|
22
|
+
'focInd',
|
|
23
|
+
'focOp',
|
|
24
|
+
'hover',
|
|
25
|
+
'htmlcs',
|
|
26
|
+
'ibm',
|
|
27
|
+
'menuNav',
|
|
28
|
+
'textNodes',
|
|
29
|
+
'wave'
|
|
30
|
+
]);
|
|
29
31
|
|
|
30
32
|
// ########## FUNCTIONS
|
|
31
33
|
|
|
32
|
-
// Merges a
|
|
33
|
-
exports.merge =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
// Merges a script and a batch and returns jobs.
|
|
35
|
+
exports.merge = (script, batch, requester, isolate = false) => {
|
|
36
|
+
if (isolate === 'false') {
|
|
37
|
+
isolate = false;
|
|
38
|
+
}
|
|
39
|
+
// If the requester is unspecified, make it the standard requester.
|
|
40
|
+
requester ||= stdRequester;
|
|
41
|
+
// Create a timestamp.
|
|
39
42
|
const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
|
|
40
|
-
// Create
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
// Create a time description.
|
|
44
|
+
const creationTime = (new Date()).toISOString().slice(0, 19);
|
|
45
|
+
// Initialize a target-independent job.
|
|
46
|
+
const protoJob = JSON.parse(JSON.stringify(script));
|
|
47
|
+
// Add the timestamp to the ID of the job.
|
|
48
|
+
protoJob.id = `${timeStamp}-${protoJob.id}-`;
|
|
49
|
+
// Add a sources property to the job.
|
|
50
|
+
protoJob.sources = {
|
|
51
|
+
script: script.id,
|
|
52
|
+
batch: batch.id,
|
|
53
|
+
target: {
|
|
54
|
+
id: '',
|
|
55
|
+
what: ''
|
|
56
|
+
},
|
|
57
|
+
requester
|
|
51
58
|
};
|
|
52
|
-
|
|
59
|
+
// Add time properties to the job.
|
|
60
|
+
protoJob.creationTime = creationTime;
|
|
61
|
+
protoJob.timeStamp = timeStamp;
|
|
62
|
+
// If isolation was requested:
|
|
63
|
+
if (isolate) {
|
|
64
|
+
// Append a copy of the previous placeholder to each eligible contaminating test in the script.
|
|
65
|
+
let {acts} = protoJob;
|
|
66
|
+
let lastPlaceholder = {};
|
|
67
|
+
for (const actIndexString in acts) {
|
|
68
|
+
const actIndex = Number.parseInt(actIndexString);
|
|
69
|
+
const act = acts[actIndex];
|
|
70
|
+
if (act.type === 'placeholder') {
|
|
71
|
+
lastPlaceholder = act;
|
|
72
|
+
}
|
|
73
|
+
else if (
|
|
74
|
+
act.type === 'test'
|
|
75
|
+
&& contaminantNames.has(act.which)
|
|
76
|
+
&& actIndex < acts.length - 1
|
|
77
|
+
&& acts[actIndex + 1].type !== 'placeholder'
|
|
78
|
+
) {
|
|
79
|
+
acts[actIndex] = JSON.parse(JSON.stringify([act, lastPlaceholder]));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
protoJob.acts = acts.flat();
|
|
83
|
+
}
|
|
84
|
+
// Initialize an array of jobs.
|
|
85
|
+
const jobs = [];
|
|
86
|
+
// For each target in the batch:
|
|
87
|
+
const {targets} = batch;
|
|
88
|
+
for (const target of targets) {
|
|
89
|
+
// Initialize a job.
|
|
90
|
+
const job = JSON.parse(JSON.stringify(protoJob));
|
|
91
|
+
// Add the target ID to the job ID.
|
|
92
|
+
job.id += target.id;
|
|
93
|
+
// Add data on the target to the sources property of the job.
|
|
94
|
+
job.sources.target.id = target.id;
|
|
95
|
+
job.sources.target.what = target.what;
|
|
96
|
+
// Replace each placeholder object in the job with the named replacer array of the target.
|
|
97
|
+
let {acts} = job;
|
|
98
|
+
for (const actIndex in acts) {
|
|
99
|
+
const act = acts[actIndex];
|
|
100
|
+
if (act.type === 'placeholder') {
|
|
101
|
+
const replacerName = act.which;
|
|
102
|
+
if (replacerName && target.acts) {
|
|
103
|
+
let replacerActs = target.acts[replacerName];
|
|
104
|
+
if (replacerActs) {
|
|
105
|
+
// Add a which property to any launch act in the replacer.
|
|
106
|
+
replacerActs = JSON.parse(JSON.stringify(replacerActs));
|
|
107
|
+
for (const replacerAct of replacerActs) {
|
|
108
|
+
if (replacerAct.type === 'launch') {
|
|
109
|
+
replacerAct.which = act.launch;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
acts[actIndex] = replacerActs;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(`ERROR: Target ${target.id} has no ${replacerName} replacer`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.log(`ERROR: Placeholder for target ${target.id} not replaceable`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
job.acts = acts.flat();
|
|
124
|
+
// Append the job to the array of jobs.
|
|
125
|
+
jobs.push(job);
|
|
126
|
+
};
|
|
127
|
+
return jobs;
|
|
53
128
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
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="comparison of accessibility scores">
|
|
10
|
+
<meta name="keywords" content="accessibility a11y web testing">
|
|
11
|
+
<title>Accessibility score comparison</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 score comparison</h1>
|
|
19
|
+
</header>
|
|
20
|
+
<h2>Introduction</h2>
|
|
21
|
+
<p>The table below compares __pageCount__ web pages on <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessibility</a>. The page names are links to the pages on the web. The scores are links to digests that explain in detail how the scores were computed.</p>
|
|
22
|
+
<p>The pages were:</p>
|
|
23
|
+
<ol id="summary">
|
|
24
|
+
<li>Tested by <a href="https://www.npmjs.com/package/testaro">Testaro</a> with script <code>ts20</code></li>
|
|
25
|
+
<li>Scored by <a href="https://www.npmjs.com/package/testilo">Testilo</a> with procedure <code>sp20b</code></li>
|
|
26
|
+
<li>Digested by Testilo with procedure <code>dp20d</code></li>
|
|
27
|
+
<li>Compared by Testilo with procedure <code>cp20a</code></li>
|
|
28
|
+
</ol>
|
|
29
|
+
<p>The script made Testaro perform 1230 automated accessibility tests drawn from nine different packages: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, Tenon, Testaro, and WAVE. The scoring procedure made Testilo assign a score to each page, with 0 being perfect.</p>
|
|
30
|
+
<h2>Comparison</h2>
|
|
31
|
+
<table class="allBorder">
|
|
32
|
+
<caption>Accessibility scores of web pages</caption>
|
|
33
|
+
<thead>
|
|
34
|
+
<tr><th scope="col">Page</th><th scope="col" colspan="2">Score (lower is better)</tr>
|
|
35
|
+
</thead>
|
|
36
|
+
<tbody class="linkSmaller secondCellRight">
|
|
37
|
+
__tableBody__
|
|
38
|
+
</tbody>
|
|
39
|
+
</table>
|
|
40
|
+
<h2>Discussion</h2>
|
|
41
|
+
<p>The widths of the bars in the above table are proportional to the square roots of the scores that the bars represent. For example, if score A is 4 times score B, then bar A is 2 times as wide as bar B.</p>
|
|
42
|
+
<p>Tests and scoring formulae are fallible and subjective. The reported faults merit investigation as potential opportunities for improved accessibility. But some may not actually harm accessibility, and some other accessibility faults are not detectable with these tests. Different reasonable procedures could yield different test results and different scores. Testaro and Testilo can be customized to fit different definitions and weightings of types of accessibility.</p>
|
|
43
|
+
<footer>
|
|
44
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
45
|
+
</footer>
|
|
46
|
+
</main>
|
|
47
|
+
</body>
|
|
48
|
+
</html>
|