testilo 3.9.10 → 3.9.14
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
|
@@ -0,0 +1,39 @@
|
|
|
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>Transactional accessibility comparison</h1>
|
|
19
|
+
</header>
|
|
20
|
+
<h2>Introduction</h2>
|
|
21
|
+
<p>This report compares __pageCount__ web pages, rating each page on <dfn>transactional accessibility</dfn>. The score given to each page estimates the <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessibility</a> of one particular transaction, in which the user discovers how to report an accessibility issue with the page to those who are responsible for the page.</p>
|
|
22
|
+
<p>You can find a more detailed explanation of transactional accessibility and how the accessibility of this particular transaction is scored in each of the reports. The scores in the table below are links to those reports.</p>
|
|
23
|
+
<p>This report was produced by the <code>cpA11yMessage</code> procedure of <a href="https://www.npmjs.com/package/testilo">Testilo</a>.
|
|
24
|
+
<h2>Comparison</h2>
|
|
25
|
+
<table class="allBorder">
|
|
26
|
+
<caption>Accessibility scores of accessibility-reporting transactions</caption>
|
|
27
|
+
<thead>
|
|
28
|
+
<tr><th scope="col">Page</th><th scope="col" colspan="2">Score (higher is better)</tr>
|
|
29
|
+
</thead>
|
|
30
|
+
<tbody class="linkSmaller secondCellRight">
|
|
31
|
+
__tableBody__
|
|
32
|
+
</tbody>
|
|
33
|
+
</table>
|
|
34
|
+
<footer>
|
|
35
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
36
|
+
</footer>
|
|
37
|
+
</main>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
cpA11yMessage.js
|
|
3
|
+
Returns a query for an HTML page including a bar-graph table.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ########## IMPORTS
|
|
7
|
+
|
|
8
|
+
// Module to keep secrets local.
|
|
9
|
+
require('dotenv').config();
|
|
10
|
+
// Module to access files.
|
|
11
|
+
const fs = require('fs/promises');
|
|
12
|
+
|
|
13
|
+
// ########## CONSTANTS
|
|
14
|
+
|
|
15
|
+
const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
|
|
16
|
+
const query = {};
|
|
17
|
+
|
|
18
|
+
// ########## FUNCTIONS
|
|
19
|
+
|
|
20
|
+
// Returns data on the hosts in the report directory.
|
|
21
|
+
const getData = async () => {
|
|
22
|
+
const reportDirAbs = `${__dirname}/../../../${reportDirScored}`;
|
|
23
|
+
const reportFileNamesAll = await fs.readdir(reportDirAbs);
|
|
24
|
+
const reportFileNamesSource = reportFileNamesAll.filter(fileName => fileName.endsWith('.json'));
|
|
25
|
+
const pageCount = reportFileNamesSource.length;
|
|
26
|
+
const bodyData = [];
|
|
27
|
+
for (const fileName of reportFileNamesSource) {
|
|
28
|
+
const fileJSON = await fs.readFile(`${reportDirAbs}/${fileName}`, 'utf8');
|
|
29
|
+
const file = JSON.parse(fileJSON);
|
|
30
|
+
const {id, host, score} = file;
|
|
31
|
+
bodyData.push({
|
|
32
|
+
id,
|
|
33
|
+
org: host.what,
|
|
34
|
+
url: host.which,
|
|
35
|
+
score: score.total
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
pageCount,
|
|
40
|
+
bodyData
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
// Returns the maximum score.
|
|
44
|
+
const getMaxScore = tableData => tableData.reduce((max, item) => Math.max(max, item.score), 0);
|
|
45
|
+
// Converts report data to a table body.
|
|
46
|
+
const getTableBody = async bodyData => {
|
|
47
|
+
const maxScore = getMaxScore(bodyData);
|
|
48
|
+
const rows = bodyData
|
|
49
|
+
.sort((a, b) => a.score - b.score)
|
|
50
|
+
.map(item => {
|
|
51
|
+
const {id, org, url, score} = item;
|
|
52
|
+
const pageCell = `<th scope="row"><a href="${url}">${org}</a></th>`;
|
|
53
|
+
const numCell = `<td><a href="digests/${id}.html">${score}</a></td>`;
|
|
54
|
+
const barWidth = 100 * score / maxScore;
|
|
55
|
+
const bar = `<rect height="100%" width="${barWidth}%" fill="red"></rect>`;
|
|
56
|
+
const barCell = `<td aria-hidden="true"><svg width="100%" height="0.7em">${bar}</svg></td>`;
|
|
57
|
+
const row = `<tr>${pageCell}${numCell}${barCell}</tr>`;
|
|
58
|
+
return row;
|
|
59
|
+
});
|
|
60
|
+
return rows.join('\n ');
|
|
61
|
+
};
|
|
62
|
+
// Returns a query for a comparative table.
|
|
63
|
+
exports.getQuery = async () => {
|
|
64
|
+
const data = await getData();
|
|
65
|
+
query.pageCount = data.pageCount;
|
|
66
|
+
query.tableBody = await getTableBody(data.bodyData);
|
|
67
|
+
const date = new Date();
|
|
68
|
+
query.dateISO = date.toISOString().slice(0, 10);
|
|
69
|
+
query.dateSlash = query.dateISO.replace(/-/g, '/');
|
|
70
|
+
return query;
|
|
71
|
+
};
|
|
@@ -27,8 +27,18 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
</header>
|
|
29
29
|
<h2>Introduction</h2>
|
|
30
|
-
<p>
|
|
31
|
-
<p
|
|
30
|
+
<p>This is a report on transactional <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessibility</a>. Suppose a person is visiting a website and wants to engage in some transaction with it. Is the transaction easy, predictable, and safe? If so, the website is <dfn>transactionally accessible</dfn>. Some disabilities make it difficult to discover how to do things on a website. Everybody, but especially any person with such a disability, benefits from transactions being designed to conform to the most common and standard conventions.</p>
|
|
31
|
+
<p>This report deals with an issue-reporting transaction. Specifically, the transaction begins when a person notices an accessibility issue on a page or view of a website or web application and wants to report that issue to whoever is responsible for the website. The simple, standard, and thus predictable transaction is assumed to look like this:</p>
|
|
32
|
+
<ol>
|
|
33
|
+
<li>The person finds an accessibility link on the page.</li>
|
|
34
|
+
<li>The person clicks that link.</li>
|
|
35
|
+
<li>That link takes the person to an accessibility page.</li>
|
|
36
|
+
<li>On the accessibility page, there is a link for sending an email message about accessibility, and there is another link for making a telephone call about accessibility.</li>
|
|
37
|
+
</ol>
|
|
38
|
+
<p>Thus, instead of the person needing to figure out how this particular website accepts issue reports, the person is assumed already to know how websites normally accept issue reports. So, instead of exploring the site to find its method, the person uses the standard method.</p>
|
|
39
|
+
<h2>Procedures</h2>
|
|
40
|
+
<p>The <a href="https://www.npmjs.com/package/testaro">Testaro</a> application used its <code>tpA11yMessage</code> testing procedure to evaluate the accessibility of this transaction on the __org__ web page at <a href="__url__">__url__</a> on __dateSlash__. Testaro produced a report.</p>
|
|
41
|
+
<p>The <a href="https://www.npmjs.com/package/testilo">Testilo</a> application processed the report and used the <code>spA11yMessage</code> scoring procedure to compute a score for the transaction. The total score is __totalScore__ (where 0 is the worst and 16 is the best possible score). The scored report is appended below.</p>
|
|
32
42
|
<p>Finally, Testilo used procedure <code>dpA11yMessage</code> to produce this digest, briefly explaining how <code>spA11yMessage</code> computed the scores.</p>
|
|
33
43
|
<h2>Score summary</h2>
|
|
34
44
|
<table class="allBorder secondCellRight">
|
|
@@ -37,23 +47,15 @@
|
|
|
37
47
|
__scoreRows__
|
|
38
48
|
</tbody>
|
|
39
49
|
</table>
|
|
40
|
-
<h2>Score components</h2>
|
|
41
|
-
__scoreComponents__
|
|
42
50
|
<h2>Discussion</h2>
|
|
43
|
-
<p>The
|
|
44
|
-
<p>Here, in brief, is how <code>spA11yMessage</code> computes a score for a page.</p>
|
|
45
|
-
<p>Each score component begins as 0.</p>
|
|
51
|
+
<p>The components of the total score are:</p>
|
|
46
52
|
<ul>
|
|
47
|
-
<li
|
|
48
|
-
<li
|
|
49
|
-
<li
|
|
50
|
-
<li
|
|
51
|
-
<li
|
|
52
|
-
<li
|
|
53
|
-
<li>The <code>mailLink</code> score increases by 2 more if one of the email links has text content that includes <q>accessibility</q> (case-insensitively).</li>
|
|
54
|
-
<li>If none of the email links has text content including <q>accessibility</q> but <q>accessibility</q> appears in the text content of the parent of any of the email links, the <code>mailLink</code> score increases by 1 more.</li>
|
|
55
|
-
<li>The same computations as for the <code>mailLink</code> score are performed on links with telephone destinations (i.e. an <code>href</code> with a value starting with <code>tel:</code>), to determine the <code>telLink</code> score.</li>
|
|
56
|
-
<li>The total score is the sum of the above scores.</li>
|
|
53
|
+
<li><code>page</code>: Can the page be visited?</li>
|
|
54
|
+
<li><code>a11yLink</code>: Does the page have a functioning <q>accessibility</q> link?</li>
|
|
55
|
+
<li><code>title</code>: Is the page to which the link goes titled to show it is about accessibility?</li>
|
|
56
|
+
<li><code>heading</code>: Does that page (the accessibility page) have a top heading indicating the page is about accessibility?</li>
|
|
57
|
+
<li><code>mailLink</code>: Does the accessibility page have a link to send email about accessibility?.</li>
|
|
58
|
+
<li><code>telLink</code>: Does the accessibility page have a link to make a telephone call about accessibility?</li>
|
|
57
59
|
</ul>
|
|
58
60
|
<p>The precise rules of <code>spA11yMessage</code> are found in the <a href="https://github.com/jrpool/testilo/blob/main/procs/score/spA11yMessage.js">code itself</a>.</p>
|
|
59
61
|
<h2>Report</h2>
|
|
@@ -45,68 +45,11 @@ exports.makeQuery = (report, query) => {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
console.log('ERROR: missing or invalid total score');
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
// Add the total to the query.
|
|
58
|
-
const scoreRows = [getScoreRow('total', summary(['total']))];
|
|
59
|
-
// Add the group rows of the score-summary table to the query.
|
|
60
|
-
groups.forEach(group => {
|
|
61
|
-
scoreRows.push(getScoreRow(`${group.groupName}`, group.score));
|
|
48
|
+
// Add the score data to the query.
|
|
49
|
+
const scoreRows = [];
|
|
50
|
+
Object.keys(score).forEach(scoreName => {
|
|
51
|
+
scoreRows.push(getScoreRow(scoreName, score[scoreName]));
|
|
62
52
|
});
|
|
53
|
+
query.totalScore = score.total;
|
|
63
54
|
query.scoreRows = scoreRows.join(innerJoiner);
|
|
64
|
-
// If the score has any special components:
|
|
65
|
-
const scoredSpecialIDs = specialComponentIDs.filter(item => summary[item]);
|
|
66
|
-
if (scoredSpecialIDs.length) {
|
|
67
|
-
// Add paragraphs about them for the issue summary to the query.
|
|
68
|
-
const specialPs = [];
|
|
69
|
-
scoredSpecialIDs.forEach(id => {
|
|
70
|
-
specialPs.push(`${getSpecialPStart(summary, id)} ${specialMessages[id]}`);
|
|
71
|
-
});
|
|
72
|
-
query.specialSummary = specialPs.join(joiner);
|
|
73
|
-
}
|
|
74
|
-
// Otherwise, i.e. if the score has no special components:
|
|
75
|
-
else {
|
|
76
|
-
// Add a paragraph stating this for the issue summary to the query.
|
|
77
|
-
query.specialSummary = '<p>No special issues contributed to the score.</p>'
|
|
78
|
-
}
|
|
79
|
-
// If the score has any classified issues as components:
|
|
80
|
-
if (groups.length) {
|
|
81
|
-
// Add paragraphs about them for the special summary to the query.
|
|
82
|
-
const groupSummaryItems = [];
|
|
83
|
-
groups.forEach(group => {
|
|
84
|
-
const {groupName, score} = group;
|
|
85
|
-
const groupP = `<p><span class="componentID">${groupName}</span>: Score ${score}. Issues reported by tests in this category:</p>`;
|
|
86
|
-
const groupListItems = [];
|
|
87
|
-
const groupData = groupDetails.groups[groupName];
|
|
88
|
-
const packageIDs = Object.keys(groupData);
|
|
89
|
-
packageIDs.forEach(packageID => {
|
|
90
|
-
const testIDs = Object.keys(groupData[packageID]);
|
|
91
|
-
testIDs.forEach(testID => {
|
|
92
|
-
const testData = groupData[packageID][testID];
|
|
93
|
-
const {score, what} = testData;
|
|
94
|
-
const listItem = `<li>Package <code>${packageID}</code>, test <code>${testID}</code>, score ${score} (${what})</li>`;
|
|
95
|
-
groupListItems.push(listItem);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
const groupList = [
|
|
99
|
-
'<ul>',
|
|
100
|
-
groupListItems.join('\n '),
|
|
101
|
-
'</ul>'
|
|
102
|
-
].join(joiner);
|
|
103
|
-
groupSummaryItems.push(groupP, groupList);
|
|
104
|
-
});
|
|
105
|
-
query.groupSummary = groupSummaryItems.join(joiner);
|
|
106
|
-
}
|
|
107
|
-
// Otherwise, i.e. if the score has no classified issues as components:
|
|
108
|
-
else {
|
|
109
|
-
// Add a paragraph stating this for the group summary to the query.
|
|
110
|
-
query.groupSummary = '<p>No classified issues contributed to the score.</p>'
|
|
111
|
-
}
|
|
112
55
|
};
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
This proc computes a score that is intended to represent how accessibly a web page offers
|
|
11
11
|
a user an opportunity to report an accessibility issue about that page. Scores can range
|
|
12
|
-
from 0 to 16.
|
|
12
|
+
from perfect 0 to 16.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
// CONSTANTS
|
|
@@ -22,69 +22,75 @@ const scoreProcID = 'a11ymessage';
|
|
|
22
22
|
// Scores the contact links of a type.
|
|
23
23
|
const contactScorer = (result, score, type) => {
|
|
24
24
|
const links = result.items;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
) {
|
|
31
|
-
score[type] += 2;
|
|
25
|
+
if (links.some(
|
|
26
|
+
link => link.textContent.toLowerCase().includes('accessibility')
|
|
27
|
+
)) {
|
|
28
|
+
score[type] -= 3;
|
|
32
29
|
}
|
|
33
|
-
else if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
) {
|
|
38
|
-
score[type] += 1;
|
|
30
|
+
else if (links.some(
|
|
31
|
+
link => link.parentTextContent.toLowerCase().includes('accessibility')
|
|
32
|
+
)) {
|
|
33
|
+
score[type] -= 2;
|
|
39
34
|
}
|
|
40
35
|
};
|
|
41
36
|
// Scores a report.
|
|
42
37
|
exports.scorer = async report => {
|
|
43
38
|
const {acts} = report;
|
|
39
|
+
report.scoreProcID = scoreProcID;
|
|
44
40
|
report.score = {
|
|
45
|
-
page:
|
|
46
|
-
a11yLink:
|
|
47
|
-
title:
|
|
48
|
-
heading:
|
|
49
|
-
mailLink:
|
|
50
|
-
telLink:
|
|
51
|
-
total: 0
|
|
41
|
+
page: 3,
|
|
42
|
+
a11yLink: 4,
|
|
43
|
+
title: 3,
|
|
44
|
+
heading: 3,
|
|
45
|
+
mailLink: 3,
|
|
46
|
+
telLink: 3
|
|
52
47
|
};
|
|
53
48
|
const {score} = report;
|
|
54
49
|
if (Array.isArray(acts)) {
|
|
55
50
|
// Act 1: page loads.
|
|
56
51
|
if (acts[1].result.startsWith('http')) {
|
|
57
|
-
score.page
|
|
52
|
+
score.page -= 2;
|
|
53
|
+
if (acts[1].endTime - acts[1].startTime < 2500) {
|
|
54
|
+
score.page -= 1;
|
|
55
|
+
}
|
|
58
56
|
// Act 2: accessibility link exists and loads promptly.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
score.
|
|
57
|
+
const {result} = acts[2];
|
|
58
|
+
// If a link with text content including accessibility was found:
|
|
59
|
+
if (result.found) {
|
|
60
|
+
score.a11yLink -= 2;
|
|
61
|
+
// If it was clickable and the resulting load finished:
|
|
62
|
+
if (result.success) {
|
|
63
|
+
score.a11yLink -= 1;
|
|
64
|
+
// If the navigation and load took less than 1.5 seconds:
|
|
65
|
+
if (acts[2].endTime - acts[2].startTime < 1500) {
|
|
66
|
+
score.a11yLink -= 1;
|
|
67
|
+
}
|
|
68
|
+
// Act 3: next page has an accessibility title.
|
|
69
|
+
let {result} = acts[3];
|
|
70
|
+
if (result && result.success) {
|
|
71
|
+
score.title -= 1;
|
|
72
|
+
if (result.title.toLowerCase().includes('accessibility')) {
|
|
73
|
+
score.title -= 2;
|
|
76
74
|
}
|
|
77
75
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
76
|
+
// Act 4: page has 1 h1 heading, and it is about accessibility.
|
|
77
|
+
result = acts[4].result;
|
|
78
|
+
if (result && result.total === 1) {
|
|
79
|
+
score.heading -= 1;
|
|
80
|
+
if (result.items[0].textContent.toLowerCase().includes('accessibility')) {
|
|
81
|
+
score.heading -= 2;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Act 5: page has an accessibility email link.
|
|
85
|
+
result = acts[5].result;
|
|
86
|
+
if (result.total) {
|
|
87
|
+
contactScorer(result, score, 'mailLink');
|
|
88
|
+
}
|
|
89
|
+
// Act 6: page has accessibility telephone link.
|
|
90
|
+
result = acts[6].result;
|
|
91
|
+
if (result.total) {
|
|
92
|
+
contactScorer(result, score, 'telLink');
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
}
|