testilo 19.0.1 → 19.0.3
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 +5 -5
- package/call.js +11 -3
- package/merge.js +5 -5
- package/package.json +1 -1
- package/procs/digest/tdp37/index.html +72 -0
- package/procs/digest/tdp37/index.js +99 -0
- package/procs/score/tic37.js +8215 -0
- package/procs/score/tsp37.js +278 -0
package/README.md
CHANGED
|
@@ -362,10 +362,10 @@ A module can invoke `merge` in this way:
|
|
|
362
362
|
|
|
363
363
|
```javaScript
|
|
364
364
|
const {merge} = require('testilo/merge');
|
|
365
|
-
const jobs = merge(script, batch, requester, 'only', false
|
|
365
|
+
const jobs = merge(script, batch, requester, true, 'only', false);
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
-
This invocation references `script`, `batch`, and `requester` variables that the module must have already defined. The `script` and `batch` variables are a script object and a batch object, respectively. The `requester` variable is an email address. The fourth argument is a string that specifies the Testaro standardization option ('also', 'only', or 'no'). The
|
|
368
|
+
This invocation references `script`, `batch`, and `requester` variables that the module must have already defined. The `script` and `batch` variables are a script object and a batch object, respectively. The `requester` variable is an email address. The fourth argument is a boolean, specifying whether to perform test isolation. The fifth argument is a string that specifies the Testaro standardization option ('also', 'only', or 'no'). The sixth argument is a boolean, specifying whether Testaro will allow granular network watching of the job. The `merge()` function of the `merge` module generates jobs and returns them in an array. The invoking module can further dispose of the jobs as needed.
|
|
369
369
|
|
|
370
370
|
##### By a user
|
|
371
371
|
|
|
@@ -374,15 +374,15 @@ A user can invoke `merge` in this way:
|
|
|
374
374
|
- Create a script and save it as a JSON file in the `scripts` subdirectory of the `process.env.SPECDIR` directory.
|
|
375
375
|
- Create a batch and save it as a JSON file in the `batches` subdirectory of the `process.env.SPECDIR` directory.
|
|
376
376
|
- In the Testilo project directory, execute this statement:
|
|
377
|
-
- `node call merge s b e
|
|
377
|
+
- `node call merge s b e i f g t`
|
|
378
378
|
|
|
379
379
|
In these statements, replace:
|
|
380
380
|
- `s` with the base name of the script file
|
|
381
381
|
- `b` with the base name of the batch file
|
|
382
382
|
- `e` with an email address, or with an empty string if the environment variable `process.env.REQUESTER` exists and you want to use it
|
|
383
|
-
- `o` with `'also'`, `'only'`, or `'no'` to specify the Testaro standardization option
|
|
384
|
-
- `g` with `true` if you want Testaro to allow granular network watching or `false` if not.
|
|
385
383
|
- `i` with `true` if you want test isolation or `false` if not
|
|
384
|
+
- `f` with `'also'`, `'only'`, or `'no'` to specify the treatment of standard-format results.
|
|
385
|
+
- `g` with `true` if reporting is to be granular, or `false` if not.
|
|
386
386
|
- `t` with `true` if the job is to be saved in the `todo` subdirectory or `false` if it is to be saved in the `pending` subdirectory of the `process.env.JOBDIR` directory.
|
|
387
387
|
|
|
388
388
|
The `call` module will retrieve the named script and batch from their respective directories.
|
package/call.js
CHANGED
|
@@ -70,14 +70,22 @@ const callScript = async (scriptID, classificationID = null, ... issueIDs) => {
|
|
|
70
70
|
console.log(`Script ${scriptID} created and saved in ${specDir}/scripts`);
|
|
71
71
|
};
|
|
72
72
|
// Fulfills a merging request.
|
|
73
|
-
const callMerge = async (
|
|
73
|
+
const callMerge = async (
|
|
74
|
+
scriptID,
|
|
75
|
+
batchID,
|
|
76
|
+
requester,
|
|
77
|
+
withIsolation,
|
|
78
|
+
standard,
|
|
79
|
+
isGranular,
|
|
80
|
+
todo
|
|
81
|
+
) => {
|
|
74
82
|
// Get the script and the batch.
|
|
75
83
|
const scriptJSON = await fs.readFile(`${specDir}/scripts/${scriptID}.json`, 'utf8');
|
|
76
84
|
const script = JSON.parse(scriptJSON);
|
|
77
85
|
const batchJSON = await fs.readFile(`${specDir}/batches/${batchID}.json`, 'utf8');
|
|
78
86
|
const batch = JSON.parse(batchJSON);
|
|
79
87
|
// Merge them into an array of jobs.
|
|
80
|
-
const jobs = merge(script, batch, requester, withIsolation);
|
|
88
|
+
const jobs = merge(script, batch, requester, withIsolation, standard, isGranular);
|
|
81
89
|
// Save the jobs.
|
|
82
90
|
const destination = todo === 'true' ? 'todo' : 'pending';
|
|
83
91
|
for (const job of jobs) {
|
|
@@ -237,7 +245,7 @@ else if (fn === 'script' && fnArgs.length) {
|
|
|
237
245
|
console.log('Execution completed');
|
|
238
246
|
});
|
|
239
247
|
}
|
|
240
|
-
else if (fn === 'merge' && fnArgs.length ===
|
|
248
|
+
else if (fn === 'merge' && fnArgs.length === 7) {
|
|
241
249
|
callMerge(... fnArgs)
|
|
242
250
|
.then(() => {
|
|
243
251
|
console.log('Execution completed');
|
package/merge.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
0. script
|
|
6
6
|
1. batch
|
|
7
7
|
2. requester
|
|
8
|
-
3.
|
|
9
|
-
4. value of the
|
|
10
|
-
5. whether
|
|
8
|
+
3. whether to provide test isolation
|
|
9
|
+
4. value of the standard property
|
|
10
|
+
5. whether reporting is to be granular
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
// ########## IMPORTS
|
|
@@ -31,7 +31,7 @@ const contaminantNames = new Set([
|
|
|
31
31
|
// ########## FUNCTIONS
|
|
32
32
|
|
|
33
33
|
// Merges a script and a batch and returns jobs.
|
|
34
|
-
exports.merge = (script, batch, requester,
|
|
34
|
+
exports.merge = (script, batch, requester, isolate, standard, isGranular) => {
|
|
35
35
|
if (isolate === 'false') {
|
|
36
36
|
isolate = false;
|
|
37
37
|
}
|
|
@@ -61,7 +61,7 @@ exports.merge = (script, batch, requester, standard, granular, isolate = false)
|
|
|
61
61
|
protoJob.creationTime = creationTime;
|
|
62
62
|
protoJob.timeStamp = timeStamp;
|
|
63
63
|
protoJob.standard = standard || 'only';
|
|
64
|
-
protoJob.observe =
|
|
64
|
+
protoJob.observe = isGranular || false;
|
|
65
65
|
// If isolation was requested:
|
|
66
66
|
if (isolate) {
|
|
67
67
|
// Perform it.
|
package/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
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 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 digest</h1>
|
|
19
|
+
<table class="allBorder">
|
|
20
|
+
<caption>Synopsis</caption>
|
|
21
|
+
<tr><th>Page</th><td>__org__</td></tr>
|
|
22
|
+
<tr><th>URL</th><td>__url__</td></tr>
|
|
23
|
+
<tr><th>Requester</th><td>__requester__</td></tr>
|
|
24
|
+
<tr><th>Test date</th><td>__dateSlash__</td></tr>
|
|
25
|
+
<tr><th>Score</th><td>__total__</td></tr>
|
|
26
|
+
<tr><th>Tested by</th><td>Testaro, procedure <code>__ts__</code></td></tr>
|
|
27
|
+
<tr><th>Scored by</th><td>Testilo, procedure <code>__sp__</code></td></tr>
|
|
28
|
+
<tr><th>Digested by</th><td>Testilo, procedure <code>__dp__</code></td></tr>
|
|
29
|
+
<tr><th>Full report</th><td><a href="__reportURL__"><code>__reportURL__</code></a></td></tr>
|
|
30
|
+
</table>
|
|
31
|
+
</header>
|
|
32
|
+
<h2>Introduction</h2>
|
|
33
|
+
<p>How <a href="https://www.w3.org/WAI/">accessible</a> is the __org__ web page at <a href="__url__"><code>__url__</code></a>?</p>
|
|
34
|
+
<p>This digest can help answer that question. Nine different tools (Alfa, ASLint, Axe, Equal Access, HTML CodeSniffer, Nu Html Checker, QualWeb, Testaro, and WAVE) tested the page to check its compliance with their accessibility rules. In all, the tools define about 960 rules, which are classified here into about 290 accessibility issues. The results were interpreted to yield a score. If the page passed every test, its score would be 0. The score for this page was __total__.</p>
|
|
35
|
+
<h2>Total score</h2>
|
|
36
|
+
<p>The total score is the sum of five components.</p>
|
|
37
|
+
<table class="allBorder secondCellRight">
|
|
38
|
+
<caption>Score summary</caption>
|
|
39
|
+
<thead>
|
|
40
|
+
<tr><th>Component</th><th>Score</th><th>Description</th></tr>
|
|
41
|
+
</thead>
|
|
42
|
+
<tbody class="headersLeft">
|
|
43
|
+
<tr><th>issue</th><td>__issue__</td><td>Severity and number of reported defects</td></tr>
|
|
44
|
+
<tr><th>tool</th><td>__tool__</td><td>Tool-by-tool defect ratings</td></tr>
|
|
45
|
+
<tr><th>prevention</th><td>__prevention__</td><td>Failed attempts by tools to test the page</td></tr>
|
|
46
|
+
<tr><th>log</th><td>__log__</td><td>Browser warnings about the page</td></tr>
|
|
47
|
+
<tr><th>latency</th><td>__latency__</td><td>Abnormal delay in page responses</td></tr>
|
|
48
|
+
</tbody>
|
|
49
|
+
<tfoot>
|
|
50
|
+
<tr><th>total</th><td>__total__</td><td>Sum of the component scores</td></tr>
|
|
51
|
+
</tfoot>
|
|
52
|
+
</table>
|
|
53
|
+
<h2>Issue scores</h2>
|
|
54
|
+
<p>The score on an issue depends on the <dfn>severity</dfn> (user impact and certainty) of the issue and on how many instances were reported (by one or more tools).</p>
|
|
55
|
+
<table class="allBorder thirdCellRight">
|
|
56
|
+
<caption>Issue scores</caption>
|
|
57
|
+
<thead>
|
|
58
|
+
<tr><th>Issue</th><th>WCAG</th><th>Score</th><th>Tools Reporting the Issue</th></tr>
|
|
59
|
+
</thead>
|
|
60
|
+
<tbody class="headersLeft">
|
|
61
|
+
__issueRows__
|
|
62
|
+
</tbody>
|
|
63
|
+
</table>
|
|
64
|
+
<h2>Itemized issues</h2>
|
|
65
|
+
<p>The reported rule violations are itemized below, issue by issue. Additional details can be inspected in the <a href="__reportURL__">full report</a>.</p>
|
|
66
|
+
__issueDetailRows__
|
|
67
|
+
<footer>
|
|
68
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
69
|
+
</footer>
|
|
70
|
+
</main>
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// index: digester for scoring procedure tsp36.
|
|
2
|
+
|
|
3
|
+
// IMPORTS
|
|
4
|
+
|
|
5
|
+
// Module to classify tool rules into issues
|
|
6
|
+
const {issues} = require('../../score/tic37');
|
|
7
|
+
// Module to process files.
|
|
8
|
+
const fs = require('fs/promises');
|
|
9
|
+
|
|
10
|
+
// CONSTANTS
|
|
11
|
+
|
|
12
|
+
// Digester ID.
|
|
13
|
+
const id = 'tdp37';
|
|
14
|
+
// Newline with indentations.
|
|
15
|
+
const innerJoiner = '\n ';
|
|
16
|
+
|
|
17
|
+
// FUNCTIONS
|
|
18
|
+
|
|
19
|
+
// Gets a row of the score-summary table.
|
|
20
|
+
const getScoreRow = (componentName, score) => `<tr><th>${componentName}</th><td>${score}</td></tr>`;
|
|
21
|
+
// Gets a row of the issue-score-summary table.
|
|
22
|
+
const getIssueScoreRow = (issueID, wcag, score, [tools]) => {
|
|
23
|
+
const toolList = tools.join(', ');
|
|
24
|
+
return `<tr><th>${issueID}</th><td>${wcag}<td>${score}</td><td>${toolList}</tr>`;
|
|
25
|
+
};
|
|
26
|
+
// Adds parameters to a query for a digest.
|
|
27
|
+
const populateQuery = (report, query) => {
|
|
28
|
+
const {sources, jobData, score} = report;
|
|
29
|
+
const {script, target, requester} = sources;
|
|
30
|
+
const {scoreProcID, summary, details} = score;
|
|
31
|
+
query.ts = script;
|
|
32
|
+
query.sp = scoreProcID;
|
|
33
|
+
query.dp = id;
|
|
34
|
+
// Add the job data to the query.
|
|
35
|
+
query.dateISO = jobData.endTime.slice(0, 10);
|
|
36
|
+
query.dateSlash = query.dateISO.replace(/-/g, '/');
|
|
37
|
+
query.org = target.what;
|
|
38
|
+
query.url = target.which;
|
|
39
|
+
query.requester = requester;
|
|
40
|
+
query.reportURL = `report?jobID=${report.id}`;
|
|
41
|
+
// Add values for the score-summary table to the query.
|
|
42
|
+
const rows = {
|
|
43
|
+
summaryRows: [],
|
|
44
|
+
issueRows: []
|
|
45
|
+
};
|
|
46
|
+
['total', 'issue', 'tool', 'prevention', 'log', 'latency'].forEach(sumItem => {
|
|
47
|
+
query[sumItem] = summary[sumItem];
|
|
48
|
+
rows.summaryRows.push(getScoreRow(sumItem, query[sumItem]));
|
|
49
|
+
});
|
|
50
|
+
// Sort the issue IDs in descending score order.
|
|
51
|
+
const issueIDs = Object.keys(details.issue);
|
|
52
|
+
issueIDs.sort((a, b) => details.issue[b].score - details.issue[a].score);
|
|
53
|
+
// Get rows for the issue-score table.
|
|
54
|
+
issueIDs.forEach(issueID => {
|
|
55
|
+
const {score, tools} = details.issue[issueID];
|
|
56
|
+
rows.issueRows.push(
|
|
57
|
+
getIssueScoreRow(issueID, issues[issueID].wcag, score, Object.keys(tools))
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
// Add the rows to the query.
|
|
61
|
+
['summaryRows', 'issueRows'].forEach(rowType => {
|
|
62
|
+
query[rowType] = rows[rowType].join(innerJoiner);
|
|
63
|
+
});
|
|
64
|
+
// Add paragraph groups about the issue details to the query.
|
|
65
|
+
const issueDetailRows = [];
|
|
66
|
+
issueIDs.forEach(issueID => {
|
|
67
|
+
issueDetailRows.push(`<h3 class="bars">Issue <code>${issueID}</code></h3>`);
|
|
68
|
+
issueDetailRows.push(`<p>Impact: ${issues[issueID].why || 'N/A'}</p>`);
|
|
69
|
+
issueDetailRows.push(`<p>WCAG: ${issues[issueID].wcag || 'N/A'}</p>`);
|
|
70
|
+
const issueData = details.issue[issueID];
|
|
71
|
+
issueDetailRows.push(`<p>Score: ${issueData.score}</p>`);
|
|
72
|
+
const toolIDs = Object.keys(issueData.tools);
|
|
73
|
+
toolIDs.forEach(toolID => {
|
|
74
|
+
issueDetailRows.push(`<h4>Violations of <code>${toolID}</code> rules</h5>`);
|
|
75
|
+
const ruleIDs = Object.keys(issueData.tools[toolID]);
|
|
76
|
+
ruleIDs.forEach(ruleID => {
|
|
77
|
+
const ruleData = issueData.tools[toolID][ruleID];
|
|
78
|
+
issueDetailRows.push(`<h5>Rule <code>${ruleID}</code></h5>`);
|
|
79
|
+
issueDetailRows.push(`<p>Description: ${ruleData.what}</p>`);
|
|
80
|
+
issueDetailRows.push(`<p>Count of instances: ${ruleData.complaints.countTotal}</p>`);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
query.issueDetailRows = issueDetailRows.join(innerJoiner);
|
|
85
|
+
};
|
|
86
|
+
// Returns a digested report.
|
|
87
|
+
exports.digester = async report => {
|
|
88
|
+
// Create a query to replace placeholders.
|
|
89
|
+
const query = {};
|
|
90
|
+
populateQuery(report, query);
|
|
91
|
+
// Get the template.
|
|
92
|
+
let template = await fs.readFile(`${__dirname}/index.html`, 'utf8');
|
|
93
|
+
// Replace its placeholders.
|
|
94
|
+
Object.keys(query).forEach(param => {
|
|
95
|
+
template = template.replace(new RegExp(`__${param}__`, 'g'), query[param]);
|
|
96
|
+
});
|
|
97
|
+
// Return the digest.
|
|
98
|
+
return template;
|
|
99
|
+
};
|