testilo 12.1.0 → 12.2.1
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
CHANGED
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
</table>
|
|
30
30
|
</header>
|
|
31
31
|
<h2>Introduction</h2>
|
|
32
|
-
<p>This is a digest of results from
|
|
33
|
-
<p>The battery includes 1353 automated accessibility tests drawn from ten different packages: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, QualWeb, Tenon, Testaro, and WAVE.</p>
|
|
32
|
+
<p>This is a digest of results from 1353 automated accessibility tests drawn from ten different tools: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, QualWeb, Tenon, Testaro, and WAVE.</p>
|
|
34
33
|
<p>These tests were run on the web page named above and gave the page a score of __totalScore__, where 0 would be <q>perfect</q>.</p>
|
|
34
|
+
<p>The total score is based mainly on the severities and instance counts of issues discovered. Secondary components include obviousness (how many tools reported issues), incompatibility (how many tools the page interfered with), nonconformity (how much error and notice logging the page provoked), and unresponsiveness (how slowly the page loaded).</p>
|
|
35
35
|
<h2>Score summary</h2>
|
|
36
36
|
<table class="allBorder secondCellRight">
|
|
37
37
|
<caption>Score components</caption>
|
|
@@ -5,14 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
// CONSTANTS
|
|
7
7
|
|
|
8
|
+
const id = 'tdp27';
|
|
8
9
|
// Newlines with indentations.
|
|
9
10
|
const joiner = '\n ';
|
|
10
11
|
const innerJoiner = '\n ';
|
|
11
|
-
const specialMessages = {
|
|
12
|
-
log: 'This is based on the amount of browser error logging and miscellaneous logging during the tests.',
|
|
13
|
-
preventions: 'This is based on tests that the page did not allow to be run. That impedes accessibility progress and risks interfering with tools that users with disabilities need.',
|
|
14
|
-
solos: 'This is based on issues reported by unclassified tests. Details are in the report.'
|
|
15
|
-
};
|
|
16
12
|
|
|
17
13
|
// FUNCTIONS
|
|
18
14
|
|
|
@@ -30,21 +26,22 @@ const getSpecialPStart = (summary, scoreID) =>
|
|
|
30
26
|
exports.makeQuery = (report, query) => {
|
|
31
27
|
// Add an HTML-safe copy of the report to the query to be appended to the digest.
|
|
32
28
|
const {acts, sources, jobData, score} = report;
|
|
33
|
-
const {target, requester} = sources;
|
|
29
|
+
const {script, target, requester} = sources;
|
|
34
30
|
const reportJSON = JSON.stringify(report, null, 2);
|
|
35
31
|
const reportJSONSafe = htmlEscape(reportJSON);
|
|
36
32
|
query.report = reportJSONSafe;
|
|
37
|
-
|
|
38
|
-
query.
|
|
39
|
-
query.
|
|
33
|
+
const {scoreProcID, summary, issues, tools, preventions} = score;
|
|
34
|
+
query.ts = script;
|
|
35
|
+
query.sp = scoreProcID;
|
|
36
|
+
query.dp = id;
|
|
40
37
|
// Add the job data to the query.
|
|
41
38
|
query.dateISO = jobData.endTime.slice(0, 10);
|
|
42
39
|
query.dateSlash = query.dateISO.replace(/-/g, '/');
|
|
40
|
+
query.url = target.which;
|
|
43
41
|
query.org = target.what;
|
|
44
|
-
query.url = acts && acts.length > 1 && acts[1].which;
|
|
45
42
|
query.requester = requester;
|
|
46
|
-
const {
|
|
47
|
-
const
|
|
43
|
+
const {total} = summary;
|
|
44
|
+
const issueTotal = summary.issues;
|
|
48
45
|
if (typeof total === 'number') {
|
|
49
46
|
query.totalScore = total;
|
|
50
47
|
}
|
|
@@ -52,17 +49,17 @@ exports.makeQuery = (report, query) => {
|
|
|
52
49
|
console.log('ERROR: missing or invalid total score');
|
|
53
50
|
return;
|
|
54
51
|
}
|
|
55
|
-
// Add the total and
|
|
52
|
+
// Add the total and the rows of the score-summary table to the query.
|
|
56
53
|
const scoreRows = [];
|
|
57
|
-
const
|
|
58
|
-
['total'].concat(
|
|
59
|
-
if (summary[
|
|
60
|
-
scoreRows.push(getScoreRow(
|
|
54
|
+
const componentIDs = ['issues', 'tools', 'preventions', 'log', 'latency'];
|
|
55
|
+
['total'].concat(componentIDs).forEach(itemID => {
|
|
56
|
+
if (summary[itemID]) {
|
|
57
|
+
scoreRows.push(getScoreRow(itemID, summary[itemID]));
|
|
61
58
|
}
|
|
62
59
|
});
|
|
63
|
-
// Add the
|
|
64
|
-
issues.forEach(
|
|
65
|
-
scoreRows.push(getScoreRow(
|
|
60
|
+
// Add the issue rows of the score-summary table to the query.
|
|
61
|
+
Object.keys(issues).forEach(issueID => {
|
|
62
|
+
scoreRows.push(getScoreRow(issueID, issues[issueID]));
|
|
66
63
|
});
|
|
67
64
|
query.scoreRows = scoreRows.join(innerJoiner);
|
|
68
65
|
// If the score has any special components:
|
|
@@ -0,0 +1,54 @@
|
|
|
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>__totalScore__</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
|
+
</table>
|
|
30
|
+
</header>
|
|
31
|
+
<h2>Introduction</h2>
|
|
32
|
+
<p>This is a digest of results from a battery of accessibility Tests.</p>
|
|
33
|
+
<p>The battery includes 1353 automated accessibility tests drawn from ten different packages: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, QualWeb, Tenon, Testaro, and WAVE.</p>
|
|
34
|
+
<p>These tests were run on the web page named above and gave the page a score of __totalScore__, where 0 would be <q>perfect</q>.</p>
|
|
35
|
+
<h2>Score summary</h2>
|
|
36
|
+
<table class="allBorder secondCellRight">
|
|
37
|
+
<caption>Score components</caption>
|
|
38
|
+
<tbody class="headersLeft">
|
|
39
|
+
__scoreRows__
|
|
40
|
+
</tbody>
|
|
41
|
+
</table>
|
|
42
|
+
<h2>Issue summary</h2>
|
|
43
|
+
<h3>Special issues</h3>
|
|
44
|
+
__specialSummary__
|
|
45
|
+
<h3>Classified issues</h3>
|
|
46
|
+
__issueSummary__
|
|
47
|
+
<h2>Complete report</h2>
|
|
48
|
+
<pre>__report__</pre>
|
|
49
|
+
<footer>
|
|
50
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
51
|
+
</footer>
|
|
52
|
+
</main>
|
|
53
|
+
</body>
|
|
54
|
+
</html>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*
|
|
2
|
+
index: digester for scoring procedure tsp24.
|
|
3
|
+
Creator of parameters for substitution into index.html.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {issueClasses} = require('../../score/tic27');
|
|
9
|
+
|
|
10
|
+
// CONSTANTS
|
|
11
|
+
|
|
12
|
+
// Digester ID.
|
|
13
|
+
const id = 'tdp27';
|
|
14
|
+
// Newlines with indentations.
|
|
15
|
+
const joiner = '\n ';
|
|
16
|
+
const innerJoiner = '\n ';
|
|
17
|
+
|
|
18
|
+
// FUNCTIONS
|
|
19
|
+
|
|
20
|
+
// Makes strings HTML-safe.
|
|
21
|
+
const htmlEscape = textOrNumber => textOrNumber
|
|
22
|
+
.toString()
|
|
23
|
+
.replace(/&/g, '&')
|
|
24
|
+
.replace(/</g, '<');
|
|
25
|
+
// Gets a row of the score-summary table.
|
|
26
|
+
const getScoreRow = (componentName, score) => `<tr><th>${componentName}</th><td>${score}</td></tr>`;
|
|
27
|
+
// Gets the start of a paragraph about a special score.
|
|
28
|
+
const getSpecialPStart = (summary, scoreID) =>
|
|
29
|
+
`<p><span class="componentID">${scoreID}</span>: Score ${summary[scoreID]}.`;
|
|
30
|
+
// Adds parameters to a query for a digest.
|
|
31
|
+
exports.makeQuery = (report, query) => {
|
|
32
|
+
// Add an HTML-safe copy of the report to the query to be appended to the digest.
|
|
33
|
+
const {acts, sources, jobData, score} = report;
|
|
34
|
+
const {script, target, requester} = sources;
|
|
35
|
+
const reportJSON = JSON.stringify(report, null, 2);
|
|
36
|
+
const reportJSONSafe = htmlEscape(reportJSON);
|
|
37
|
+
query.report = reportJSONSafe;
|
|
38
|
+
const {scoreProcID, summary, issues} = score;
|
|
39
|
+
const {total} = summary;
|
|
40
|
+
query.ts = script;
|
|
41
|
+
query.sp = scoreProcID;
|
|
42
|
+
query.dp = id;
|
|
43
|
+
// Add the job data to the query.
|
|
44
|
+
query.dateISO = jobData.endTime.slice(0, 10);
|
|
45
|
+
query.dateSlash = query.dateISO.replace(/-/g, '/');
|
|
46
|
+
query.org = target.what;
|
|
47
|
+
query.url = target.which;
|
|
48
|
+
query.requester = requester;
|
|
49
|
+
// Add the total score to the query.
|
|
50
|
+
if (typeof total === 'number') {
|
|
51
|
+
query.totalScore = total;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log('ERROR: missing or invalid total score');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Get rows for a score-summary table.
|
|
58
|
+
const scoreRows = [];
|
|
59
|
+
const componentIDs = ['issues', 'tools', 'preventions', 'log', 'latency'];
|
|
60
|
+
['total'].concat(componentIDs).forEach(itemID => {
|
|
61
|
+
if (summary[itemID]) {
|
|
62
|
+
scoreRows.push(getScoreRow(itemID, summary[itemID]));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Add the issue rows to them.
|
|
66
|
+
Object.keys(issues).forEach(issueID => {
|
|
67
|
+
scoreRows.push(getScoreRow(issueID, issues[issueID]));
|
|
68
|
+
});
|
|
69
|
+
// Add the rows to the query.
|
|
70
|
+
query.scoreRows = scoreRows.join(innerJoiner);
|
|
71
|
+
// Add paragraphs about them for the issue summary to the query.
|
|
72
|
+
const issueSummaryItems = [];
|
|
73
|
+
Object.keys(issues).forEach(issueID => {
|
|
74
|
+
const issueHeading = `<h4>Issue ${issueID}</h4>`;
|
|
75
|
+
const wcagP = `<p>WCAG: ${issueClasses[issueID].wcag || 'N/A'}</p>`;
|
|
76
|
+
const scoreP = `<p>Score: ${issues[issueID]}</p>`;
|
|
77
|
+
const issueIntroP = '<p>Issue reports in this category:</p>';
|
|
78
|
+
const issueListItems = [];
|
|
79
|
+
const issueData = issueDetails.issues[issueName];
|
|
80
|
+
const toolIDs = Object.keys(issueData.tools);
|
|
81
|
+
toolIDs.forEach(toolID => {
|
|
82
|
+
const testIDs = Object.keys(issueData.tools[toolID]);
|
|
83
|
+
testIDs.forEach(testID => {
|
|
84
|
+
const testData = issueData.tools[toolID][testID];
|
|
85
|
+
const {score, what} = testData;
|
|
86
|
+
const listItem =
|
|
87
|
+
`<li>Package <code>${toolID}</code>, test <code>${testID}</code>, score ${score} (${what})</li>`;
|
|
88
|
+
issueListItems.push(listItem);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
const issueList = [
|
|
92
|
+
'<ul>',
|
|
93
|
+
issueListItems.join('\n '),
|
|
94
|
+
'</ul>'
|
|
95
|
+
].join(joiner);
|
|
96
|
+
issueSummaryItems.push(issueHeading, wcagP, scoreP, issueIntroP, issueList);
|
|
97
|
+
});
|
|
98
|
+
query.issueSummary = issueSummaryItems.join(joiner);
|
|
99
|
+
};
|
package/procs/score/tsp27.js
CHANGED
|
@@ -51,7 +51,7 @@ Object.keys(issueClasses).forEach(issueClassName => {
|
|
|
51
51
|
|
|
52
52
|
// Scores a report.
|
|
53
53
|
exports.scorer = report => {
|
|
54
|
-
console.log(report.id);
|
|
54
|
+
console.log(`Scoring report ${report.id}`);
|
|
55
55
|
// If there are any acts in the report:
|
|
56
56
|
const {acts} = report;
|
|
57
57
|
if (Array.isArray(acts) && acts.length) {
|
|
@@ -77,53 +77,49 @@ exports.scorer = report => {
|
|
|
77
77
|
const {summary, toolTotals, issues, tools, preventions} = score;
|
|
78
78
|
// For each test act:
|
|
79
79
|
testActs.forEach(act => {
|
|
80
|
-
// If a standard result
|
|
80
|
+
// If a successful standard result exists:
|
|
81
81
|
const {which, standardResult} = act;
|
|
82
82
|
if (
|
|
83
83
|
standardResult
|
|
84
84
|
&& standardResult.totals
|
|
85
85
|
&& standardResult.totals.length === 4
|
|
86
86
|
&& standardResult.instances
|
|
87
|
-
&& standardResult.instances.length
|
|
88
87
|
) {
|
|
89
|
-
// Add the
|
|
88
|
+
// Add the severity totals of the tool to the score.
|
|
90
89
|
const {totals} = standardResult;
|
|
91
90
|
tools[which] = totals;
|
|
92
91
|
toolTotals.forEach((total, index) => {
|
|
93
|
-
toolTotals[index] +=
|
|
94
|
-
summary.tools += toolWeight * totals[index] * severityWeights[index];
|
|
92
|
+
toolTotals[index] += totals[index];
|
|
95
93
|
});
|
|
96
94
|
// Update the issue totals for the tool.
|
|
97
95
|
const issueTotals = {};
|
|
96
|
+
let ruleID;
|
|
98
97
|
standardResult.instances.forEach(instance => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
indexIssueID = issueID;
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
indexIssueID = issueMatcher.find(pattern => {
|
|
98
|
+
ruleID = issueIndex[which][instance.ruleID];
|
|
99
|
+
if (! ruleID) {
|
|
100
|
+
ruleID = issueMatcher.find(pattern => {
|
|
106
101
|
const patternRE = new RegExp(pattern);
|
|
107
|
-
return patternRE.test(instance.
|
|
102
|
+
return patternRE.test(instance.ruleID);
|
|
108
103
|
});
|
|
109
104
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
if (ruleID) {
|
|
106
|
+
const issueID = issueIndex[which][ruleID];
|
|
107
|
+
if (! issueTotals[issueID]) {
|
|
108
|
+
issueTotals[issueID] = 0;
|
|
113
109
|
}
|
|
114
|
-
issueTotals[
|
|
110
|
+
issueTotals[issueID] += instance.count || 1;
|
|
115
111
|
}
|
|
116
112
|
else {
|
|
117
|
-
console.log(`ERROR: ${instance.
|
|
113
|
+
console.log(`ERROR: ${instance.ruleID} of ${which} not found in issueClasses`);
|
|
118
114
|
}
|
|
119
115
|
});
|
|
120
116
|
// Update the issue totals in the score.
|
|
121
|
-
Object.keys(issueTotals).forEach(
|
|
122
|
-
issues[
|
|
117
|
+
Object.keys(issueTotals).forEach(issueID => {
|
|
118
|
+
issues[issueID] = Math.max(issues[id] || 0, issueTotals[issueID]);
|
|
123
119
|
});
|
|
124
120
|
summary.issues = Object.values(issues).reduce((total, current) => total + current);
|
|
125
121
|
}
|
|
126
|
-
// Otherwise, i.e. if no
|
|
122
|
+
// Otherwise, i.e. if no no successful result exists:
|
|
127
123
|
else {
|
|
128
124
|
// Add a prevented result to the act if not already there.
|
|
129
125
|
if (! act.result) {
|
|
@@ -133,10 +129,14 @@ exports.scorer = report => {
|
|
|
133
129
|
act.result.prevented = true;
|
|
134
130
|
};
|
|
135
131
|
// Add the tool and the prevention score to the score.
|
|
136
|
-
|
|
132
|
+
preventions[which] = preventionWeight;
|
|
137
133
|
summary.preventions += preventionWeight;
|
|
138
134
|
}
|
|
139
135
|
});
|
|
136
|
+
// Add the weighted tool total to the score.
|
|
137
|
+
summary.tools = toolWeight * toolTotals.reduce(
|
|
138
|
+
(total, current, index) => total + current * severityWeights[index], 0
|
|
139
|
+
);
|
|
140
140
|
// Add the log score to the score.
|
|
141
141
|
const {jobData} = report;
|
|
142
142
|
summary.log = Math.max(0, Math.round(
|
|
@@ -147,6 +147,7 @@ exports.scorer = report => {
|
|
|
147
147
|
+ logWeights.prohibitedCount * jobData.prohibitedCount +
|
|
148
148
|
+ logWeights.visitRejectionCount * jobData.visitRejectionCount
|
|
149
149
|
));
|
|
150
|
+
// Add the latency score to the score.
|
|
150
151
|
summary.latency = Math.round(
|
|
151
152
|
latencyWeight * (Math.max(0, jobData.visitLatency - normalLatency))
|
|
152
153
|
);
|