testilo 12.1.0 → 12.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "12.1.0",
3
+ "version": "12.2.0",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "aim.js",
6
6
  "scripts": {
@@ -29,9 +29,9 @@
29
29
  </table>
30
30
  </header>
31
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>
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
- query.ts = 'ts24';
38
- query.sp = 'tsp24';
39
- query.dp = 'tdp24';
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 {issueDetails, summary} = score;
47
- const {total, issues} = summary;
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 any special rows of the score-summary table to the query.
52
+ // Add the total and the rows of the score-summary table to the query.
56
53
  const scoreRows = [];
57
- const specialComponentIDs = ['log', 'preventions', 'solos'];
58
- ['total'].concat(specialComponentIDs).forEach(item => {
59
- if (summary[item]) {
60
- scoreRows.push(getScoreRow(item, summary[item]));
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 group rows of the score-summary table to the query.
64
- issues.forEach(issue => {
65
- scoreRows.push(getScoreRow(`${issue.issueName}`, issue.score));
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('./procs/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, '&amp;')
24
+ .replace(/</g, '&lt;');
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
+ };
@@ -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 with valid totals and instances exists:
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 tool totals to the score.
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] += toolWeight * totals[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
- const issueID = issueIndex[which][instance.issueID];
100
- let indexIssueID;
101
- if (issueID) {
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.issueID);
102
+ return patternRE.test(instance.ruleID);
108
103
  });
109
104
  }
110
- if (indexIssueID) {
111
- if (! issueTotals[indexIssueID]) {
112
- issueTotals[indexIssueID] = 0;
105
+ if (ruleID) {
106
+ const issueID = issueIndex[which][ruleID];
107
+ if (! issueTotals[issueID]) {
108
+ issueTotals[issueID] = 0;
113
109
  }
114
- issueTotals[indexIssueID] += instance.count || 1;
110
+ issueTotals[issueID] += instance.count || 1;
115
111
  }
116
112
  else {
117
- console.log(`ERROR: ${instance.issueID} not found in issueClasses`);
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(id => {
122
- issues[id] = Math.max(issues[id] || 0, issueTotals[id]);
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 result with totals exists:
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
- score.preventions[which] = preventionWeight;
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
  );