testilo 13.1.1 → 13.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/call.js CHANGED
@@ -117,7 +117,8 @@ const callScore = async (scorerID, selector = '') => {
117
117
  // Save it.
118
118
  await fs.writeFile(`${scoredReportDir}/${report.id}.json`, JSON.stringify(report, null, 2));
119
119
  };
120
- }
120
+ console.log(`Reports scored and saved in ${scoredReportDir}`);
121
+ }
121
122
  // Otherwise, i.e. if no raw reports are to be scored:
122
123
  else {
123
124
  // Report this.
@@ -132,17 +133,16 @@ const callDigest = async (digesterID, selector = '') => {
132
133
  if (reports.length) {
133
134
  const digesterDir = `${functionDir}/digest/${digesterID}`;
134
135
  // Get the digester.
135
- const digester = require(`${digesterDir}/index`).makeQuery;
136
- // Get the template.
137
- const template = await fs.readFile(`${digesterDir}/index.html`, 'utf8');
136
+ const {digester} = require(`${digesterDir}/index`);
138
137
  // Digest the reports.
139
- const digestedReports = digest(template, digester, reports);
138
+ const digestedReports = await digest(digester, reports);
140
139
  const digestedReportDir = `${reportDir}/digested`;
141
140
  // For each digested report:
142
141
  for (const reportID of Object.keys(digestedReports)) {
143
142
  // Save it.
144
143
  await fs.writeFile(`${digestedReportDir}/${reportID}.html`, digestedReports[reportID]);
145
144
  };
145
+ console.log(`Reports digested and saved in ${digestedReportDir}`);
146
146
  }
147
147
  // Otherwise, i.e. if no scored reports are to be digested:
148
148
  else {
package/digest.js CHANGED
@@ -9,16 +9,16 @@
9
9
  // ########## FUNCTIONS
10
10
 
11
11
  // Digests the scored reports and returns them, digested.
12
- exports.digest = (digester, reports) => {
12
+ exports.digest = async (digester, reports) => {
13
13
  const digests = {};
14
14
  // For each report:
15
- reports.forEach(report => {
15
+ for (const report of reports) {
16
16
  // Use it to create a digest.
17
- const digestedReport = digester(report);
17
+ const digestedReport = await digester(report);
18
18
  // Add the digest to the array of digests.
19
19
  digests[report.id] = digestedReport;
20
20
  console.log(`Report ${report.id} digested`);
21
- });
21
+ };
22
22
  // Return the digests.
23
23
  console.log(`Digesting complete. Report count: ${reports.length}`);
24
24
  return digests;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "13.1.1",
3
+ "version": "13.2.0",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "aim.js",
6
6
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  <tr><th>URL</th><td>__url__</td></tr>
23
23
  <tr><th>Requester</th><td>__requester__</td></tr>
24
24
  <tr><th>Test date</th><td>__dateSlash__</td></tr>
25
- <tr><th>Score</th><td>__totalScore__</td></tr>
25
+ <tr><th>Score</th><td>__total__</td></tr>
26
26
  <tr><th>Tested by</th><td>Testaro, procedure <code>__ts__</code></td></tr>
27
27
  <tr><th>Scored by</th><td>Testilo, procedure <code>__sp__</code></td></tr>
28
28
  <tr><th>Digested by</th><td>Testilo, procedure <code>__dp__</code></td></tr>
@@ -31,18 +31,22 @@
31
31
  <h2>Introduction</h2>
32
32
  <p>This is a digest of results from a battery of accessibility tests.</p>
33
33
  <p>The battery includes about 1350 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>
34
+ <p>These tests were run on the web page named above and gave the page a score of __total__, where 0 would be <q>perfect</q>.</p>
35
+ <h2>Scores</h2>
36
36
  <table class="allBorder secondCellRight">
37
37
  <caption>Score summary</caption>
38
38
  <thead>
39
39
  <tr><th>Component</th><th>Score</th></tr>
40
40
  </thead>
41
41
  <tbody class="headersLeft">
42
- __summaryRows__
42
+ <tr><th>total</th><td>__total__</td></tr>
43
+ <tr><th>issue</th><td>__issue__</td></tr>
44
+ <tr><th>tool</th><td>__tool__</td></tr>
45
+ <tr><th>prevention</th><td>__prevention__</td></tr>
46
+ <tr><th>log</th><td>__log__</td></tr>
47
+ <tr><th>latency</th><td>__latency__</td></tr>
43
48
  </tbody>
44
49
  </table>
45
- <h2>Issue scores</h2>
46
50
  <table class="allBorder secondCellRight">
47
51
  <caption>Issue scores</caption>
48
52
  <thead>
@@ -2,7 +2,10 @@
2
2
 
3
3
  // IMPORTS
4
4
 
5
+ // Issue classification
5
6
  const {issueClasses} = require('../../score/tic27');
7
+ // Function to process files.
8
+ const fs = require('fs/promises');
6
9
 
7
10
  // CONSTANTS
8
11
 
@@ -23,10 +26,10 @@ const htmlEscape = textOrNumber => textOrNumber
23
26
  // Gets a row of the score-summary table.
24
27
  const getScoreRow = (componentName, score) => `<tr><th>${componentName}</th><td>${score}</td></tr>`;
25
28
  // Adds parameters to a query for a digest.
26
- const makeQuery = (report, query) => {
29
+ const populateQuery = (report, query) => {
27
30
  const {sources, jobData, score} = report;
28
31
  const {script, target, requester} = sources;
29
- const {scoreProcID, summary, issues} = score;
32
+ const {scoreProcID, summary, details} = score;
30
33
  const {total} = summary;
31
34
  query.ts = script;
32
35
  query.sp = scoreProcID;
@@ -37,15 +40,10 @@ const makeQuery = (report, query) => {
37
40
  query.org = target.what;
38
41
  query.url = target.which;
39
42
  query.requester = requester;
40
- // Add the total score to the query.
41
- if (typeof total === 'number') {
42
- query.totalScore = total;
43
- }
44
- else {
45
- console.log('ERROR: missing or invalid total score');
46
- return;
47
- }
48
- // Get rows for a score-summary table.
43
+ // Add values for the score-summary table to the query.
44
+ ['total', 'issue', 'tool', 'prevention', 'log', 'latency'].forEach(sumItem => {
45
+ query[sumItem] = summary[sumItem];
46
+ });
49
47
  const rows = {
50
48
  summaryRows: [],
51
49
  issueRows: []
@@ -57,8 +55,8 @@ const makeQuery = (report, query) => {
57
55
  }
58
56
  });
59
57
  // Get rows for an issue-score table.
60
- Object.keys(issues).forEach(issueID => {
61
- rows.issueRows.push(getScoreRow(issueID, issues[issueID]));
58
+ Object.keys(details.issue).forEach(issueID => {
59
+ rows.issueRows.push(getScoreRow(issueID, details.issue[issueID].score));
62
60
  });
63
61
  // Add the rows to the query.
64
62
  ['summaryRows', 'issueRows'].forEach(rowType => {
@@ -66,13 +64,13 @@ const makeQuery = (report, query) => {
66
64
  });
67
65
  // Add paragraphs about the issues to the query.
68
66
  const issueSummaryItems = [];
69
- Object.keys(issues).forEach(issueID => {
67
+ Object.keys(details.issue).forEach(issueID => {
70
68
  const issueHeading = `<h4>Issue ${issueID}</h4>`;
71
69
  const wcagP = `<p>WCAG: ${issueClasses[issueID].wcag || 'N/A'}</p>`;
72
- const scoreP = `<p>Score: ${issues[issueID]}</p>`;
70
+ const scoreP = `<p>Score: ${details.issue[issueID]}</p>`;
73
71
  const issueIntroP = '<p>Issue reports in this category:</p>';
74
72
  const issueListItems = [];
75
- const issueData = issueDetails.issues[issueName];
73
+ const issueData = details.issue[issueID];
76
74
  const toolIDs = Object.keys(issueData.tools);
77
75
  toolIDs.forEach(toolID => {
78
76
  const testIDs = Object.keys(issueData.tools[toolID]);
@@ -100,7 +98,8 @@ const makeQuery = (report, query) => {
100
98
  // Returns a digested report.
101
99
  exports.digester = async report => {
102
100
  // Create a query to replace plateholders.
103
- const query = makeQuery(report, {});
101
+ const query = {};
102
+ populateQuery(report, query);
104
103
  // Get the template.
105
104
  let template = await fs.readFile(`${__dirname}/index.html`, 'utf8');
106
105
  // Replace its placeholders.
@@ -81,9 +81,14 @@ exports.scorer = report => {
81
81
  const {summary, details} = score;
82
82
  // For each test act:
83
83
  testActs.forEach(act => {
84
- // If a successful standard result exists:
84
+ // If the page prevented the tool from operating:
85
85
  const {which, standardResult} = act;
86
- if (
86
+ if (standardResult.prevented) {
87
+ // Add this to the score.
88
+ details.prevention[which] = preventionWeight;
89
+ }
90
+ // Otherwise, if a successful standard result exists:
91
+ else if (
87
92
  standardResult
88
93
  && standardResult.totals
89
94
  && standardResult.totals.length === 4
@@ -105,6 +110,8 @@ exports.scorer = report => {
105
110
  const issueID = issueIndex[which][ruleID];
106
111
  if (! details.issue[issueID]) {
107
112
  details.issue[issueID] = {
113
+ score: 0,
114
+ maxCount: 0,
108
115
  weight: issueClasses[issueID].weight,
109
116
  tools: {}
110
117
  };
@@ -144,17 +151,29 @@ exports.scorer = report => {
144
151
  }
145
152
  // Otherwise, i.e. if no successful standard result exists:
146
153
  else {
147
- // Add a prevented result to the act if not already there.
148
- if (! act.result) {
149
- act.result = {};
150
- }
151
- if (! act.result.prevented) {
152
- act.result.prevented = true;
153
- };
154
- // Add the tool and the prevention score to the score.
154
+ // Add an inferred prevention to the score.
155
155
  details.prevention[which] = preventionWeight;
156
156
  }
157
157
  });
158
+ // For each issue with any complaints:
159
+ Object.keys(details.issue).forEach(issueID => {
160
+ const issueData = details.issue[issueID];
161
+ // For each tool with any complaints for the issue:
162
+ Object.keys(issueData.tools).forEach(toolID => {
163
+ // Get the sum of the weighted counts of its issue rules.
164
+ let weightedCount = 0;
165
+ Object.values(issueData.tools[toolID]).forEach(ruleData => {
166
+ weightedCount += ruleData.quality * ruleData.complaints.countTotal;
167
+ });
168
+ // If the sum exceeds the existing maximum weighted count for the issue:
169
+ if (weightedCount > issueData.maxCount) {
170
+ // Change the maximum count for the issue to the sum.
171
+ issueData.maxCount = weightedCount;
172
+ }
173
+ });
174
+ // Get the score for the issue.
175
+ issueData.score = issueData.weight * issueData.maxCount;
176
+ });
158
177
  // Add the severity detail totals to the score.
159
178
  details.severity.total = Object.keys(details.severity.byTool).reduce((severityTotals, toolID) => {
160
179
  details.severity.byTool[toolID].forEach((severityScore, index) => {
@@ -163,15 +182,9 @@ exports.scorer = report => {
163
182
  return severityTotals;
164
183
  }, details.severity.total);
165
184
  // Add the summary issue total to the score.
166
- Object.keys(details.issue).forEach(issueID => {
167
- Object.keys(details.issue[issueID].tools).forEach(toolID => {
168
- Object.keys(details.issue[issueID].tools[toolID]).forEach(ruleID => {
169
- summary.issue += details.issue[issueID].weight
170
- * details.issue[issueID].tools[toolID][ruleID].quality
171
- * details.issue[issueID].tools[toolID][ruleID].complaints.countTotal;
172
- });
173
- });
174
- });
185
+ summary.issue = Object
186
+ .values(details.issue)
187
+ .reduce((total, current) => total + current.score, 0);
175
188
  // Add the summary tool total to the score.
176
189
  summary.tool = toolWeight * details.severity.total.reduce(
177
190
  (total, current, index) => total + severityWeights[index] * current, 0