testilo 41.0.4 → 41.1.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/package.json +1 -1
- package/procs/digest/{tdp44 → tdp46}/index.html +49 -3
- package/procs/digest/{tdp43e → tdp46}/index.js +57 -5
- package/procs/util.js +2 -2
- package/wcag.json +6287 -0
- package/procs/digest/tdp40/index.html +0 -57
- package/procs/digest/tdp40/index.js +0 -131
- package/procs/digest/tdp41/index.html +0 -59
- package/procs/digest/tdp41/index.js +0 -133
- package/procs/digest/tdp42/index.html +0 -60
- package/procs/digest/tdp42/index.js +0 -146
- package/procs/digest/tdp43/index.html +0 -60
- package/procs/digest/tdp43/index.js +0 -158
- package/procs/digest/tdp43e/index.html +0 -71
- package/procs/digest/tdp44/index.js +0 -188
package/package.json
CHANGED
|
@@ -11,6 +11,43 @@
|
|
|
11
11
|
<title>Accessibility digest</title>
|
|
12
12
|
<link rel="icon" href="favicon.ico">
|
|
13
13
|
<link rel="stylesheet" href="style.css">
|
|
14
|
+
<script id="script" type="module">
|
|
15
|
+
const sortButton = document.getElementById('sortButton');
|
|
16
|
+
const sortChangeSpan = document.getElementById('sortChange');
|
|
17
|
+
const sumBody = document.getElementById('sumBody');
|
|
18
|
+
const rows = Array.from(sumBody.children);
|
|
19
|
+
const sortRowsBy = basis => {
|
|
20
|
+
if (basis === 'wcag') {
|
|
21
|
+
rows.sort((a, b) => {
|
|
22
|
+
const sorters = [a, b].map(row => {
|
|
23
|
+
const wcagParts = row.children[1].textContent.split('.');
|
|
24
|
+
const wcagNums = wcagParts.map(part => Number.parseInt(part, 10));
|
|
25
|
+
return 100 * (wcagNums[0] || 0) + 20 * (wcagNums[1] || 0) + (wcagNums[2] || 0);
|
|
26
|
+
});
|
|
27
|
+
return sorters[0] - sorters[1];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
else if (basis === 'score') {
|
|
31
|
+
rows.sort((a, b) => {
|
|
32
|
+
const sorters = [a, b].map(row => Number.parseInt(row.children[2].textContent));
|
|
33
|
+
return sorters[1] - sorters[0];
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
sumBody.textContent = '';
|
|
37
|
+
rows.forEach(row => {
|
|
38
|
+
sumBody.appendChild(row);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
sortButton.addEventListener('click', event => {
|
|
42
|
+
// Add the new sorting basis to the page.
|
|
43
|
+
sortChangeSpan.textContent = sortChangeSpan.textContent === 'score to WCAG'
|
|
44
|
+
? 'WCAG to score'
|
|
45
|
+
: 'score to WCAG';
|
|
46
|
+
const newBasis = sortChangeSpan.textContent === 'score to WCAG' ? 'score' : 'wcag';
|
|
47
|
+
// Re-sort the table.
|
|
48
|
+
sortRowsBy(newBasis);
|
|
49
|
+
});
|
|
50
|
+
</script>
|
|
14
51
|
</head>
|
|
15
52
|
<body>
|
|
16
53
|
<main>
|
|
@@ -53,14 +90,23 @@
|
|
|
53
90
|
<p>This digest can help answer that question. Ten different tools (Alfa, ASLint, Axe, Editoria11y, 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 990 rules, which are classified here into about 310 accessibility issues.</p>
|
|
54
91
|
<p>The results were interpreted to yield a score, with 0 being ideal. The score for this page was __total__, the sum of __issueCount__ for the count of issues, __issue__ for specific issues, __solo__ for unclassified rule violations, __tool__ for tool-by-tool ratings, __element__ for the count of violating elements, __prevention__ for the page preventing tools from running, __log__ for browser warnings, and __latency__ for delayed page responses.</p>
|
|
55
92
|
<h2 id="summary">Issue summary</h2>
|
|
56
|
-
<
|
|
57
|
-
<
|
|
93
|
+
<h3>Details about this summary</h3>
|
|
94
|
+
<ul>
|
|
95
|
+
<li>This table shows the numbers of rule violations (<q>instances</q>) reported by one or more tools, classified by issue.</li>
|
|
96
|
+
<li>Tools often disagree on instance counts, because of non-equivalent rules or invalid tests. You can inspect the <a href="__reportURL__">full report</a> to diagnose differences.</li>
|
|
97
|
+
<li>The <q>WCAG</q> value is the principle, guideline, or success criterion of the <a href="https://www.w3.org/TR/WCAG22/">Web Content Accessibility Guidelines</a> most relevant to the issue.</li>
|
|
98
|
+
<li>The <q>Score</q> value is the contribution of the issue to the page score.</li>
|
|
99
|
+
<li>An instance count of 0 means the tool has a rule belonging to the issue but reported no violations of that rule, although at least one tool reported at least one violation.</li>
|
|
100
|
+
<li>You can sort this table by WCAG or score.</li>
|
|
101
|
+
</ul>
|
|
102
|
+
<h3>The summary</h3>
|
|
103
|
+
<p><button id="sortButton" type="button">Change sorting from <span id="sortChange">score to WCAG</span></button></p>
|
|
58
104
|
<table class="allBorder thirdCellRight">
|
|
59
105
|
<caption>How many violations each tool reported, by issue</caption>
|
|
60
106
|
<thead>
|
|
61
107
|
<tr><th>Issue</th><th>WCAG</th><th>Score</th><th>Instance counts</th></tr>
|
|
62
108
|
</thead>
|
|
63
|
-
<tbody class="headersLeft">
|
|
109
|
+
<tbody id="sumBody" class="headersLeft">
|
|
64
110
|
__issueRows__
|
|
65
111
|
</tbody>
|
|
66
112
|
</table>
|
|
@@ -36,27 +36,75 @@ const {getNowDate, getNowDateSlash} = require('../../util');
|
|
|
36
36
|
// CONSTANTS
|
|
37
37
|
|
|
38
38
|
// Digester ID.
|
|
39
|
-
const digesterID = '
|
|
39
|
+
const digesterID = 'tdp45';
|
|
40
40
|
// Newline with indentations.
|
|
41
41
|
const innerJoiner = '\n ';
|
|
42
42
|
const outerJoiner = '\n ';
|
|
43
|
+
// Directory of WCAG links.
|
|
44
|
+
const wcagPhrases = {};
|
|
43
45
|
|
|
44
46
|
// FUNCTIONS
|
|
45
47
|
|
|
46
48
|
// Gets a row of the score-summary table.
|
|
47
49
|
const getScoreRow = (componentName, score) => `<tr><th>${componentName}</th><td>${score}</td></tr>`;
|
|
50
|
+
// Gets a WCAG link or, if not obtainable, a numeric identifier.
|
|
51
|
+
const getWCAGTerm = wcag => {
|
|
52
|
+
const wcagPhrase = wcagPhrases[wcag];
|
|
53
|
+
const wcagTerm = wcagPhrase
|
|
54
|
+
? `<a href="https://www.w3.org/WAI/WCAG22/Understanding/${wcagPhrase}.html">${wcag}</a>`
|
|
55
|
+
: wcag;
|
|
56
|
+
return wcagTerm;
|
|
57
|
+
};
|
|
48
58
|
// Gets a row of the issue-score-summary table.
|
|
49
59
|
const getIssueScoreRow = (issueConstants, issueDetails) => {
|
|
50
60
|
const {summary, wcag} = issueConstants;
|
|
61
|
+
const wcagTerm = getWCAGTerm(wcag);
|
|
51
62
|
const {instanceCounts, score} = issueDetails;
|
|
52
63
|
const toolList = Object
|
|
53
64
|
.keys(instanceCounts)
|
|
54
65
|
.map(tool => `<code>${tool}</code>:${instanceCounts[tool]}`)
|
|
55
66
|
.join(', ');
|
|
56
|
-
return `<tr><th>${summary}</th><td class="center">${
|
|
67
|
+
return `<tr><th>${summary}</th><td class="center">${wcagTerm}<td class="right num">${score}</td><td>${toolList}</td></tr>`;
|
|
68
|
+
};
|
|
69
|
+
// Populates the directory of WCAG understanding verbal IDs.
|
|
70
|
+
const getWCAGPhrases = async () => {
|
|
71
|
+
// Get the copy of file https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json.
|
|
72
|
+
const wcagJSON = await fs.readFile(`${__dirname}/../../../wcag.json`, 'utf8');
|
|
73
|
+
const wcag = JSON.parse(wcagJSON);
|
|
74
|
+
const {principles} = wcag;
|
|
75
|
+
// For each principle in it:
|
|
76
|
+
principles.forEach(principle => {
|
|
77
|
+
// If it is usable:
|
|
78
|
+
if (principle.num && principle.id && principle.id.startsWith('WCAG2:')) {
|
|
79
|
+
// Add it to the directory.
|
|
80
|
+
wcagPhrases[principle.num] = principle.id.slice(6);
|
|
81
|
+
const {guidelines} = principle;
|
|
82
|
+
// For each guideline in the principle:
|
|
83
|
+
guidelines.forEach(guideline => {
|
|
84
|
+
// If it is usable:
|
|
85
|
+
if (guideline.num && guideline.id && guideline.id.startsWith('WCAG2:')) {
|
|
86
|
+
// Add it to the directory.
|
|
87
|
+
wcagPhrases[guideline.num] = guideline.id.slice(6);
|
|
88
|
+
const {successcriteria} = guideline;
|
|
89
|
+
// For each success criterion in the guideline:
|
|
90
|
+
successcriteria.forEach(successCriterion => {
|
|
91
|
+
// If it is usable:
|
|
92
|
+
if (
|
|
93
|
+
successCriterion.num
|
|
94
|
+
&& successCriterion.id
|
|
95
|
+
&& successCriterion.id.startsWith('WCAG2:')
|
|
96
|
+
) {
|
|
97
|
+
// Add it to the directory.
|
|
98
|
+
wcagPhrases[successCriterion.num] = successCriterion.id.slice(6);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
57
105
|
};
|
|
58
106
|
// Adds parameters to a query for a digest.
|
|
59
|
-
const populateQuery = (report, query) => {
|
|
107
|
+
const populateQuery = async (report, query) => {
|
|
60
108
|
const {
|
|
61
109
|
browserID, device, id, isolate, lowMotion, score, sources, standard, strict, target
|
|
62
110
|
} = report;
|
|
@@ -80,6 +128,8 @@ const populateQuery = (report, query) => {
|
|
|
80
128
|
query.browser = browserID;
|
|
81
129
|
query.agent = agent ? ` on agent ${agent}` : '';
|
|
82
130
|
query.reportURL = process.env.SCORED_REPORT_URL.replace('__id__', id);
|
|
131
|
+
// Populate the WCAG phrase directory.
|
|
132
|
+
await getWCAGPhrases();
|
|
83
133
|
// Add values for the score-summary table to the query.
|
|
84
134
|
const rows = {
|
|
85
135
|
summaryRows: [],
|
|
@@ -112,7 +162,9 @@ const populateQuery = (report, query) => {
|
|
|
112
162
|
const issueSummary = issues[issueID].summary;
|
|
113
163
|
issueDetailRows.push(`<h3 class="bars">Issue: ${issueSummary}</h3>`);
|
|
114
164
|
issueDetailRows.push(`<p>Impact: ${issues[issueID].why || 'N/A'}</p>`);
|
|
115
|
-
|
|
165
|
+
const wcag = issues[issueID].wcag;
|
|
166
|
+
const wcagTerm = wcag ? getWCAGTerm(wcag) : 'N/A';
|
|
167
|
+
issueDetailRows.push(`<p>WCAG: ${wcagTerm}</p>`);
|
|
116
168
|
const issueData = details.issue[issueID];
|
|
117
169
|
issueDetailRows.push(`<p>Score: ${issueData.score}</p>`);
|
|
118
170
|
issueDetailRows.push('<h4>Elements</h4>');
|
|
@@ -176,7 +228,7 @@ const populateQuery = (report, query) => {
|
|
|
176
228
|
exports.digester = async report => {
|
|
177
229
|
// Create a query to replace placeholders.
|
|
178
230
|
const query = {};
|
|
179
|
-
populateQuery(report, query);
|
|
231
|
+
await populateQuery(report, query);
|
|
180
232
|
// Get the template.
|
|
181
233
|
let template = await fs.readFile(`${__dirname}/index.html`, 'utf8');
|
|
182
234
|
// Replace its placeholders.
|
package/procs/util.js
CHANGED
|
@@ -34,7 +34,7 @@ const alphaNumChars = (() => {
|
|
|
34
34
|
return digits.concat(lowers);
|
|
35
35
|
})();
|
|
36
36
|
// Tools.
|
|
37
|
-
exports.tools = {
|
|
37
|
+
const tools = exports.tools = {
|
|
38
38
|
alfa: 'Alfa',
|
|
39
39
|
aslint: 'ASLint',
|
|
40
40
|
axe: 'Axe',
|
|
@@ -123,4 +123,4 @@ exports.getBarCell = (num, colMax, svgWidth, isRight = false) => {
|
|
|
123
123
|
return cell;
|
|
124
124
|
};
|
|
125
125
|
// Returns whether a tool ID is the ID of a Testaro-integrated tool.
|
|
126
|
-
exports.isToolID = toolID =>
|
|
126
|
+
exports.isToolID = toolID => Object.keys(tools).includes(toolID);
|