testilo 7.0.10 → 7.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/merge.js CHANGED
@@ -5,8 +5,9 @@
5
5
  0. base of name of script located in process.env.SCRIPTDIR.
6
6
  1. base of name of batch located in process.env.BATCHDIR.
7
7
  2. email address to be notified of completion.
8
- Usage example:
9
- node merge tp25 weborgs developer@w3.org
8
+ Usage examples:
9
+ node call merge ts25 weborgs developer@w3.org
10
+ node call merge ts25 weborgs
10
11
  Note: The subdirectory for jobs will be created if it does not exist.
11
12
  */
12
13
 
@@ -24,11 +25,12 @@ const {aim} = require('./aim');
24
25
  const scriptDir = process.env.SCRIPTDIR || 'scripts';
25
26
  const batchDir = process.env.BATCHDIR || 'batches';
26
27
  const jobDir = process.env.JOBDIR || 'watch';
28
+ const stdRequester = process.env.REQUESTER;
27
29
 
28
30
  // ########## FUNCTIONS
29
31
 
30
32
  // Merges a batch into a script and writes jobs.
31
- exports.merge = async (scriptName, batchName, requester) => {
33
+ exports.merge = async (scriptName, batchName, requester = stdRequester) => {
32
34
  // Get the script and the batch.
33
35
  const scriptJSON = await fs.readFile(`${scriptDir}/${scriptName}.json`, 'utf8');
34
36
  const batchJSON = await fs.readFile(`${batchDir}/${batchName}.json`, 'utf8');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "7.0.10",
3
+ "version": "7.1.0",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "aim.js",
6
6
  "scripts": {
@@ -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 1230 automated accessibility tests drawn from nine different packages: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, 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
+ __groupSummary__
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,117 @@
1
+ /*
2
+ index: digester for scoring procedure sp20a.
3
+ Creator of parameters for substitution into index.html.
4
+ */
5
+
6
+ // CONSTANTS
7
+
8
+ // Newlines with indentations.
9
+ const joiner = '\n ';
10
+ 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
+
17
+ // FUNCTIONS
18
+
19
+ // Makes strings HTML-safe.
20
+ const htmlEscape = textOrNumber => textOrNumber
21
+ .toString()
22
+ .replace(/&/g, '&amp;')
23
+ .replace(/</g, '&lt;');
24
+ // Gets a row of the score-summary table.
25
+ const getScoreRow = (component, score) => `<tr><th>${component}</th><td>${score}</td></tr>`;
26
+ // Gets the start of a paragraph about a special score.
27
+ const getSpecialPStart = (summary, scoreID) =>
28
+ `<p><span class="componentID">${scoreID}</span>: Score ${summary[scoreID]}.`;
29
+ // Adds parameters to a query for a digest.
30
+ exports.makeQuery = (report, query) => {
31
+ // Add an HTML-safe copy of the report to the query to be appended to the digest.
32
+ const {job, jobData, score} = report;
33
+ const {sources} = job;
34
+ const {host, requester} = sources;
35
+ const reportJSON = JSON.stringify(report, null, 2);
36
+ const reportJSONSafe = htmlEscape(reportJSON);
37
+ query.report = reportJSONSafe;
38
+ query.ts = 'ts20';
39
+ query.sp = 'sp20a';
40
+ query.dp = 'dp20a';
41
+ // Add the job data to the query.
42
+ query.dateISO = jobData.endTime.slice(0, 10);
43
+ query.dateSlash = query.dateISO.replace(/-/g, '/');
44
+ query.org = host.what;
45
+ query.url = host.which;
46
+ query.requester = requester;
47
+ const {groupDetails, summary} = score;
48
+ const {total, groups} = summary;
49
+ if (typeof total === 'number') {
50
+ query.totalScore = total;
51
+ }
52
+ else {
53
+ console.log('ERROR: missing or invalid total score');
54
+ return;
55
+ }
56
+ // Add the total and any special rows of the score-summary table to the query.
57
+ const scoreRows = [];
58
+ const specialComponentIDs = ['log', 'preventions', 'solos'];
59
+ ['total'].concat(specialComponentIDs).forEach(item => {
60
+ if (summary[item]) {
61
+ scoreRows.push(getScoreRow(item, summary[item]));
62
+ }
63
+ });
64
+ // Add the group rows of the score-summary table to the query.
65
+ groups.forEach(group => {
66
+ scoreRows.push(getScoreRow(`${group.groupName}`, group.score));
67
+ });
68
+ query.scoreRows = scoreRows.join(innerJoiner);
69
+ // If the score has any special components:
70
+ const scoredSpecialIDs = specialComponentIDs.filter(item => summary[item]);
71
+ if (scoredSpecialIDs.length) {
72
+ // Add paragraphs about them for the issue summary to the query.
73
+ const specialPs = [];
74
+ scoredSpecialIDs.forEach(id => {
75
+ specialPs.push(`${getSpecialPStart(summary, id)} ${specialMessages[id]}`);
76
+ });
77
+ query.specialSummary = specialPs.join(joiner);
78
+ }
79
+ // Otherwise, i.e. if the score has no special components:
80
+ else {
81
+ // Add a paragraph stating this for the issue summary to the query.
82
+ query.specialSummary = '<p>No special issues contributed to the score.</p>'
83
+ }
84
+ // If the score has any classified issues as components:
85
+ if (groups.length) {
86
+ // Add paragraphs about them for the special summary to the query.
87
+ const groupSummaryItems = [];
88
+ groups.forEach(group => {
89
+ const {groupName, score} = group;
90
+ const groupP = `<p><span class="componentID">${groupName}</span>: Score ${score}. Issues reported by tests in this category:</p>`;
91
+ const groupListItems = [];
92
+ const groupData = groupDetails.groups[groupName];
93
+ const packageIDs = Object.keys(groupData);
94
+ packageIDs.forEach(packageID => {
95
+ const testIDs = Object.keys(groupData[packageID]);
96
+ testIDs.forEach(testID => {
97
+ const testData = groupData[packageID][testID];
98
+ const {score, what} = testData;
99
+ const listItem = `<li>Package <code>${packageID}</code>, test <code>${testID}</code>, score ${score} (${what})</li>`;
100
+ groupListItems.push(listItem);
101
+ });
102
+ });
103
+ const groupList = [
104
+ '<ul>',
105
+ groupListItems.join('\n '),
106
+ '</ul>'
107
+ ].join(joiner);
108
+ groupSummaryItems.push(groupP, groupList);
109
+ });
110
+ query.groupSummary = groupSummaryItems.join(joiner);
111
+ }
112
+ // Otherwise, i.e. if the score has no classified issues as components:
113
+ else {
114
+ // Add a paragraph stating this for the group summary to the query.
115
+ query.groupSummary = '<p>No classified issues contributed to the score.</p>'
116
+ }
117
+ };
@@ -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 1230 automated accessibility tests drawn from nine different packages: Alfa, Axe, Continuum, Equal Access, HTML CodeSniffer, Nu Html Checker, 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
+ __groupSummary__
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,121 @@
1
+ /*
2
+ index: digester for scoring procedure sp20b.
3
+ Creator of parameters for substitution into index.html.
4
+ */
5
+
6
+ // CONSTANTS
7
+
8
+ // Newlines with indentations.
9
+ const joiner = '\n ';
10
+ 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
+
17
+ // FUNCTIONS
18
+
19
+ // Makes strings HTML-safe.
20
+ const htmlEscape = textOrNumber => textOrNumber
21
+ .toString()
22
+ .replace(/&/g, '&amp;')
23
+ .replace(/</g, '&lt;');
24
+ // Gets a row of the score-summary table.
25
+ const getScoreRow = (component, score) => `<tr><th>${component}</th><td>${score}</td></tr>`;
26
+ // Gets the start of a paragraph about a special score.
27
+ const getSpecialPStart = (summary, scoreID) =>
28
+ `<p><span class="componentID">${scoreID}</span>: Score ${summary[scoreID]}.`;
29
+ // Adds parameters to a query for a digest.
30
+ exports.makeQuery = (report, query) => {
31
+ // Add an HTML-safe copy of the report to the query to be appended to the digest.
32
+ const {job, jobData, score} = report;
33
+ const {sources} = job;
34
+ const {host, requester} = sources;
35
+ const reportJSON = JSON.stringify(report, null, 2);
36
+ const reportJSONSafe = htmlEscape(reportJSON);
37
+ query.report = reportJSONSafe;
38
+ query.ts = 'ts20';
39
+ query.sp = 'sp20b';
40
+ query.dp = 'dp20b';
41
+ // Add the job data to the query.
42
+ query.dateISO = jobData.endTime.slice(0, 10);
43
+ query.dateSlash = query.dateISO.replace(/-/g, '/');
44
+ query.org = host.what;
45
+ query.url = host.which;
46
+ query.requester = requester;
47
+ const {groupDetails, summary} = score;
48
+ const {total, groups} = summary;
49
+ if (typeof total === 'number') {
50
+ query.totalScore = total;
51
+ }
52
+ else {
53
+ console.log('ERROR: missing or invalid total score');
54
+ return;
55
+ }
56
+ // Add the total and any special rows of the score-summary table to the query.
57
+ const scoreRows = [];
58
+ const specialComponentIDs = ['log', 'preventions', 'solos'];
59
+ ['total'].concat(specialComponentIDs).forEach(item => {
60
+ if (summary[item]) {
61
+ scoreRows.push(getScoreRow(item, summary[item]));
62
+ }
63
+ });
64
+ // Add the group rows of the score-summary table to the query.
65
+ groups.forEach(group => {
66
+ scoreRows.push(getScoreRow(`${group.groupName}`, group.score));
67
+ });
68
+ query.scoreRows = scoreRows.join(innerJoiner);
69
+ // If the score has any special components:
70
+ const scoredSpecialIDs = specialComponentIDs.filter(item => summary[item]);
71
+ if (scoredSpecialIDs.length) {
72
+ // Add paragraphs about them for the issue summary to the query.
73
+ const specialPs = [];
74
+ scoredSpecialIDs.forEach(id => {
75
+ specialPs.push(`${getSpecialPStart(summary, id)} ${specialMessages[id]}`);
76
+ });
77
+ query.specialSummary = specialPs.join(joiner);
78
+ }
79
+ // Otherwise, i.e. if the score has no special components:
80
+ else {
81
+ // Add a paragraph stating this for the issue summary to the query.
82
+ query.specialSummary = '<p>No special issues contributed to the score.</p>'
83
+ }
84
+ // If the score has any classified issues as components:
85
+ if (groups.length) {
86
+ // Add paragraphs about them for the group summary to the query.
87
+ const groupSummaryItems = [];
88
+ groups.forEach(group => {
89
+ const {groupName, score} = group;
90
+ const groupHeading = `<h4>Issue ${groupName}</h4>`;
91
+ const wcagP = `<p>WCAG: ${groupDetails.groups[groupName].wcag || 'N/A'}</p>`;
92
+ const scoreP = `<p>Score: ${score}</p>`;
93
+ const issueIntroP = '<p>Issue reports in this category:</p>';
94
+ const groupListItems = [];
95
+ const groupData = groupDetails.groups[groupName];
96
+ const packageIDs = Object.keys(groupData);
97
+ packageIDs.forEach(packageID => {
98
+ const testIDs = Object.keys(groupData.packages[packageID]);
99
+ testIDs.forEach(testID => {
100
+ const testData = groupData.packages[packageID][testID];
101
+ const {score, what} = testData;
102
+ const listItem =
103
+ `<li>Package <code>${packageID}</code>, test <code>${testID}</code>, score ${score} (${what})</li>`;
104
+ groupListItems.push(listItem);
105
+ });
106
+ });
107
+ const groupList = [
108
+ '<ul>',
109
+ groupListItems.join('\n '),
110
+ '</ul>'
111
+ ].join(joiner);
112
+ groupSummaryItems.push(groupHeading, wcagP, scoreP, issueIntroP, groupList);
113
+ });
114
+ query.groupSummary = groupSummaryItems.join(joiner);
115
+ }
116
+ // Otherwise, i.e. if the score has no classified issues as components:
117
+ else {
118
+ // Add a paragraph stating this for the group summary to the query.
119
+ query.groupSummary = '<p>No classified issues contributed to the score.</p>'
120
+ }
121
+ };