@jrpool/kilotest 24.0.8 → 24.1.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 +1 -1
- package/reportIssues/api.js +259 -0
- package/reportIssues/index.html +12 -4
- package/reportIssues/index.js +73 -155
- package/reportIssues/util.js +141 -0
- package/tutorial/index.html +313 -393
- package/tutorial/index.js +1 -1
- package/util.js +2 -2
package/package.json
CHANGED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/*
|
|
2
|
+
index.js
|
|
3
|
+
Answers the report-issues question.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
getPageDataStrings,
|
|
10
|
+
getReport,
|
|
11
|
+
getToolNamesString,
|
|
12
|
+
getWCAGLink,
|
|
13
|
+
getWeightName,
|
|
14
|
+
htmlSafe,
|
|
15
|
+
isHidden,
|
|
16
|
+
isValidReport,
|
|
17
|
+
objectSort,
|
|
18
|
+
tools
|
|
19
|
+
} = require('../util');
|
|
20
|
+
const {issues} = require('testilo/procs/score/tic');
|
|
21
|
+
const fs = require('fs/promises');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
|
|
24
|
+
// FUNCTIONS
|
|
25
|
+
|
|
26
|
+
// Gets data on the issues reported in a report.
|
|
27
|
+
const getIssuesData = async (timeStamp, jobID) => {
|
|
28
|
+
// Get the report.
|
|
29
|
+
const report = await getReport(timeStamp, jobID);
|
|
30
|
+
// If it is valid:
|
|
31
|
+
if (typeof report === 'object' && isValidReport(report)) {
|
|
32
|
+
const issuesData = {
|
|
33
|
+
reporters: new Set(),
|
|
34
|
+
reporterCount: 0,
|
|
35
|
+
reportersString: '',
|
|
36
|
+
violators: new Set(),
|
|
37
|
+
violatorCount: 0,
|
|
38
|
+
preventions: {},
|
|
39
|
+
issuesObject: {},
|
|
40
|
+
issueCount: 0,
|
|
41
|
+
issues: []
|
|
42
|
+
};
|
|
43
|
+
const {issuesObject, reporters, violators} = issuesData;
|
|
44
|
+
// For each act in it:
|
|
45
|
+
report.acts.forEach(act => {
|
|
46
|
+
// If it is a test act:
|
|
47
|
+
if (act.type === 'test') {
|
|
48
|
+
const {result, which} = act;
|
|
49
|
+
const instances = result?.standardResult?.instances ?? [];
|
|
50
|
+
// For each of its standard instances:
|
|
51
|
+
instances.forEach(instance => {
|
|
52
|
+
const {issueID} = instance;
|
|
53
|
+
// If the instance has a non-ignorable classified issue:
|
|
54
|
+
if (issueID && issues[issueID] && issueID !== 'ignorable') {
|
|
55
|
+
// Ensure that the issues data include data on the issue.
|
|
56
|
+
issuesObject[issueID] ??= {
|
|
57
|
+
issueID,
|
|
58
|
+
weight: issues[issueID].weight ?? 0,
|
|
59
|
+
reporters: new Set(),
|
|
60
|
+
reporterCount: 0,
|
|
61
|
+
reportersString: '',
|
|
62
|
+
violators: new Set(),
|
|
63
|
+
violatorCount: 0
|
|
64
|
+
};
|
|
65
|
+
// Ensure that the tool is in the issues data.
|
|
66
|
+
reporters.add(which);
|
|
67
|
+
// Ensure that it is in the issue data.
|
|
68
|
+
issuesObject[issueID].reporters.add(which);
|
|
69
|
+
const {catalogIndex} = instance;
|
|
70
|
+
// If the instance has a catalog index:
|
|
71
|
+
if (catalogIndex) {
|
|
72
|
+
// Ensure that the violator is in the issues data.
|
|
73
|
+
violators.add(catalogIndex);
|
|
74
|
+
// Ensure that it is in the issue data.
|
|
75
|
+
issuesObject[issueID].violators.add(catalogIndex);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// Populate the unpopulated subproperties of the issues data.
|
|
82
|
+
issuesData.reporterCount = issuesData.reporters.size;
|
|
83
|
+
issuesData.reportersString = getToolNamesString(issuesData.reporters);
|
|
84
|
+
issuesData.violatorCount = issuesData.violators.size;
|
|
85
|
+
issuesData.preventions = report.jobData.preventions;
|
|
86
|
+
issuesData.issueCount = Object.keys(issuesData.issuesObject).length;
|
|
87
|
+
issuesData.issues = Object.values(issuesData.issuesObject);
|
|
88
|
+
// For each issue in the issues data:
|
|
89
|
+
issuesData.issues.forEach(issue => {
|
|
90
|
+
// Populate its unpopulated properties.
|
|
91
|
+
issue.reporterCount = issue.reporters.size;
|
|
92
|
+
issue.reportersString = getToolNamesString(issue.reporters);
|
|
93
|
+
issue.violatorCount = issue.violators.size;
|
|
94
|
+
});
|
|
95
|
+
// Sort the issues alphabetically by reporters string.
|
|
96
|
+
objectSort(issuesData.issues, 'reportersString', 'alpha');
|
|
97
|
+
// Sort the issues again in descending reporter-count order, making this the primary order.
|
|
98
|
+
objectSort(issuesData.issues, 'reporterCount', 'numericDown');
|
|
99
|
+
// Return the issues data.
|
|
100
|
+
return issuesData;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
// Adds parameters to a query for the answer page.
|
|
104
|
+
const populateQuery = async (timeStamp, jobID, query) => {
|
|
105
|
+
// Get fact descriptions for the report.
|
|
106
|
+
const pageDataStrings = await getPageDataStrings(timeStamp, jobID);
|
|
107
|
+
const {what, urlLink, testInfo} = pageDataStrings;
|
|
108
|
+
const issuesData = await getIssuesData(timeStamp, jobID);
|
|
109
|
+
// If this failed:
|
|
110
|
+
if (typeof issuesData === 'string') {
|
|
111
|
+
// Return this.
|
|
112
|
+
return issuesData;
|
|
113
|
+
}
|
|
114
|
+
const {
|
|
115
|
+
issueCount,
|
|
116
|
+
preventions,
|
|
117
|
+
reporterCount,
|
|
118
|
+
reportersString,
|
|
119
|
+
violatorCount
|
|
120
|
+
} = issuesData;
|
|
121
|
+
// Add an issue count description to the query.
|
|
122
|
+
query.issueCount = issueCount === 1 ? '1 issue was' : `${issueCount} issues were`;
|
|
123
|
+
query.reporterCount = reporterCount === 1 ? '1 tool' : `${reporterCount} tools`;
|
|
124
|
+
// Add a reporter count and list to the query.
|
|
125
|
+
query.reporters = reportersString;
|
|
126
|
+
// Add a violator count to the query.
|
|
127
|
+
query.violatorCount = violatorCount === 1 ? '1 violator was' : `${violatorCount} violators were`;
|
|
128
|
+
// Add page data to the query.
|
|
129
|
+
query.target = what;
|
|
130
|
+
query.urlLink = urlLink;
|
|
131
|
+
query.testInfo = testInfo;
|
|
132
|
+
query.timeStamp = timeStamp;
|
|
133
|
+
query.jobID = jobID;
|
|
134
|
+
const preventionStrings = [];
|
|
135
|
+
const margin = ' '.repeat(6);
|
|
136
|
+
Object.keys(preventions).forEach(preventedToolID => {
|
|
137
|
+
const toolName = tools[preventedToolID];
|
|
138
|
+
const toolNameString = `${toolName[0]} (${toolName[1]})`;
|
|
139
|
+
const causeString = htmlSafe(preventions[preventedToolID]);
|
|
140
|
+
const preventionString = `${margin}<li>Page not testable by ${toolNameString}: ${causeString}</li>`;
|
|
141
|
+
preventionStrings.push(preventionString);
|
|
142
|
+
});
|
|
143
|
+
query.preventions = preventionStrings.join('\n');
|
|
144
|
+
// For each weight:
|
|
145
|
+
[4, 3, 2, 1].forEach(weight => {
|
|
146
|
+
// Initialize data on issues having the weight.
|
|
147
|
+
const weightData = [];
|
|
148
|
+
// Initialize the lines for the weight.
|
|
149
|
+
const weightLines = [];
|
|
150
|
+
// For each issue:
|
|
151
|
+
issuesData.issues.forEach(issueData => {
|
|
152
|
+
const {
|
|
153
|
+
issueID, reporterCount, reportersString, violatorCount, weight: issueWeight
|
|
154
|
+
} = issueData;
|
|
155
|
+
// If it has the weight:
|
|
156
|
+
if (issueWeight === weight) {
|
|
157
|
+
const issue = issues[issueID];
|
|
158
|
+
const {wcag, why} = issue;
|
|
159
|
+
const wcagLink = `<a href="${getWCAGLink(wcag)}">${wcag}</a>`;
|
|
160
|
+
// Add data on it to the weight data.
|
|
161
|
+
weightData.push({
|
|
162
|
+
issueID,
|
|
163
|
+
summary: issue.summary,
|
|
164
|
+
why,
|
|
165
|
+
wcag: wcagLink,
|
|
166
|
+
reporterCount,
|
|
167
|
+
reportersString,
|
|
168
|
+
violatorCount
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const weightName = getWeightName(weight);
|
|
173
|
+
// Add the issue count to the query.
|
|
174
|
+
query[`${weightName}Count`] = weightData.length;
|
|
175
|
+
// If any reported issues have the weight:
|
|
176
|
+
if (weightData.length) {
|
|
177
|
+
// Add the start of a list of the issues with the weight to the lines.
|
|
178
|
+
weightLines.push(`${margin}<ul class="headed">`);
|
|
179
|
+
// For each issue with the weight:
|
|
180
|
+
weightData.forEach(weightIssue => {
|
|
181
|
+
const {issueID, reporterCount, reportersString, violatorCount, wcag, why} = weightIssue;
|
|
182
|
+
// Add the start of a list item to the lines.
|
|
183
|
+
weightLines.push(`${margin} <li>`);
|
|
184
|
+
// Add a heading summarizing the issue to the lines.
|
|
185
|
+
weightLines.push(`${margin} <h5>${weightIssue.summary}</h5>`);
|
|
186
|
+
// Add the start of alist of facts about the issue to the lines.
|
|
187
|
+
weightLines.push(`${margin} <ul class="pseudoTopLevel">`);
|
|
188
|
+
// Add the issue facts to the lines.
|
|
189
|
+
weightLines.push(`${margin} <li>Why it matters: ${why}`);
|
|
190
|
+
weightLines.push(`${margin} <li>Related WCAG standard: ${wcag}`);
|
|
191
|
+
const reporterCountString = reporterCount === 1 ? '1 tool' : `${reporterCount} tools`;
|
|
192
|
+
weightLines.push(
|
|
193
|
+
`${margin} <li>Reported by ${reporterCountString} (${reportersString})</li>`
|
|
194
|
+
);
|
|
195
|
+
const violatorCountString = violatorCount === 1
|
|
196
|
+
? '1 violator was'
|
|
197
|
+
: `${violatorCount} violators were`;
|
|
198
|
+
weightLines.push(`${margin} <li>${violatorCountString} reported</li>`);
|
|
199
|
+
// Add the end of the fact list to the lines.
|
|
200
|
+
weightLines.push(`${margin} </ul>`);
|
|
201
|
+
// Add the start of a link list to the lines.
|
|
202
|
+
weightLines.push(`${margin} <ul class="nav">`);
|
|
203
|
+
const whereQuestionString = 'Where was the issue found?';
|
|
204
|
+
const labelString = `Where was the ${weightIssue.summary} issue found on the ${what} page?`;
|
|
205
|
+
const href = `href="/reportIssue.html/${issueID}/${timeStamp}/${jobID}"`;
|
|
206
|
+
const label = `aria-label="${labelString}"`;
|
|
207
|
+
const whereLink = `<a ${href} ${label}>${whereQuestionString}</a>`;
|
|
208
|
+
// Add a violations link to the lines.
|
|
209
|
+
weightLines.push(`${margin} <li>${whereLink}</li>`);
|
|
210
|
+
// Add the end of the link list to the lines.
|
|
211
|
+
weightLines.push(`${margin} </ul>`);
|
|
212
|
+
// Add the end of the list item to the lines.
|
|
213
|
+
weightLines.push(`${margin} </li>`);
|
|
214
|
+
});
|
|
215
|
+
// Add the end of the list of issues with the weight to the lines.
|
|
216
|
+
weightLines.push(`${margin}</ul>`);
|
|
217
|
+
// Add the lines documenting the issues with the weight to the query.
|
|
218
|
+
query[`${weightName}Details`] = weightLines.join('\n');
|
|
219
|
+
}
|
|
220
|
+
// Otherwise, i.e. if no reported issues have the weight:
|
|
221
|
+
else {
|
|
222
|
+
query[`${weightName}Details`] = `${margin} <p>None</p>`;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
// Returns a page answering the target-issues question.
|
|
227
|
+
exports.answer = async pageArgs => {
|
|
228
|
+
const [timeStamp, jobID] = pageArgs.split('/');
|
|
229
|
+
const reportIsHidden = await isHidden(timeStamp, jobID);
|
|
230
|
+
// If the report is not available:
|
|
231
|
+
if (reportIsHidden) {
|
|
232
|
+
return {
|
|
233
|
+
status: 'error',
|
|
234
|
+
message: 'Report not available'
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const query = {};
|
|
238
|
+
// Create a query to replace the placeholders.
|
|
239
|
+
await populateQuery(timeStamp, jobID, query);
|
|
240
|
+
// If the report facts were obtained:
|
|
241
|
+
if (query.testInfo) {
|
|
242
|
+
// Get the template.
|
|
243
|
+
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
244
|
+
// Replace its placeholders.
|
|
245
|
+
Object.keys(query).forEach(param => {
|
|
246
|
+
answerPage = answerPage.replace(new RegExp(`__${param}__`, 'g'), query[param]);
|
|
247
|
+
});
|
|
248
|
+
// Return the populated page.
|
|
249
|
+
return {
|
|
250
|
+
status: 'ok',
|
|
251
|
+
answerPage
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// Otherwise, i.e. if they were not obtained, report this.
|
|
255
|
+
return {
|
|
256
|
+
status: 'error',
|
|
257
|
+
error: 'Report processing failed'
|
|
258
|
+
};
|
|
259
|
+
};
|
package/reportIssues/index.html
CHANGED
|
@@ -29,19 +29,27 @@
|
|
|
29
29
|
<h3>Details</h3>
|
|
30
30
|
<details>
|
|
31
31
|
<summary>Highest priority: __highestCount__</summary>
|
|
32
|
-
|
|
32
|
+
<ul class="headed">
|
|
33
|
+
__highestDetails__
|
|
34
|
+
</ul>
|
|
33
35
|
</details>
|
|
34
36
|
<details>
|
|
35
37
|
<summary>High priority: __highCount__</summary>
|
|
36
|
-
|
|
38
|
+
<ul class="headed">
|
|
39
|
+
__highDetails__
|
|
40
|
+
</ul>
|
|
37
41
|
</details>
|
|
38
42
|
<details>
|
|
39
43
|
<summary>Low priority: __lowCount__</summary>
|
|
40
|
-
|
|
44
|
+
<ul class="headed">
|
|
45
|
+
__lowDetails__
|
|
46
|
+
</ul>
|
|
41
47
|
</details>
|
|
42
48
|
<details>
|
|
43
49
|
<summary>Lowest priority: __lowestCount__</summary>
|
|
44
|
-
|
|
50
|
+
<ul class="headed">
|
|
51
|
+
__lowestDetails__
|
|
52
|
+
</ul>
|
|
45
53
|
</details>
|
|
46
54
|
</main>
|
|
47
55
|
</body>
|
package/reportIssues/index.js
CHANGED
|
@@ -5,16 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
// IMPORTS
|
|
7
7
|
|
|
8
|
+
const {getData} = require('./util');
|
|
8
9
|
const {
|
|
9
10
|
getPageDataStrings,
|
|
10
|
-
getReport,
|
|
11
|
-
getToolNamesString,
|
|
12
11
|
getWCAGLink,
|
|
13
12
|
getWeightName,
|
|
14
13
|
htmlSafe,
|
|
15
14
|
isHidden,
|
|
16
|
-
isValidReport,
|
|
17
|
-
objectSort,
|
|
18
15
|
tools
|
|
19
16
|
} = require('../util');
|
|
20
17
|
const {issues} = require('testilo/procs/score/tic');
|
|
@@ -23,114 +20,37 @@ const path = require('path');
|
|
|
23
20
|
|
|
24
21
|
// FUNCTIONS
|
|
25
22
|
|
|
26
|
-
// Gets data on the issues reported in a report.
|
|
27
|
-
const getIssuesData = async (timeStamp, jobID) => {
|
|
28
|
-
// Get the report.
|
|
29
|
-
const report = await getReport(timeStamp, jobID);
|
|
30
|
-
// If it is valid:
|
|
31
|
-
if (typeof report === 'object' && isValidReport(report)) {
|
|
32
|
-
const issuesData = {
|
|
33
|
-
reporters: new Set(),
|
|
34
|
-
reporterCount: 0,
|
|
35
|
-
reportersString: '',
|
|
36
|
-
violators: new Set(),
|
|
37
|
-
violatorCount: 0,
|
|
38
|
-
preventions: {},
|
|
39
|
-
issuesObject: {},
|
|
40
|
-
issueCount: 0,
|
|
41
|
-
issues: []
|
|
42
|
-
};
|
|
43
|
-
const {issuesObject, reporters, violators} = issuesData;
|
|
44
|
-
// For each act in it:
|
|
45
|
-
report.acts.forEach(act => {
|
|
46
|
-
// If it is a test act:
|
|
47
|
-
if (act.type === 'test') {
|
|
48
|
-
const {result, which} = act;
|
|
49
|
-
const instances = result?.standardResult?.instances ?? [];
|
|
50
|
-
// For each of its standard instances:
|
|
51
|
-
instances.forEach(instance => {
|
|
52
|
-
const {issueID} = instance;
|
|
53
|
-
// If the instance has a non-ignorable classified issue:
|
|
54
|
-
if (issueID && issues[issueID] && issueID !== 'ignorable') {
|
|
55
|
-
// Ensure that the issues data include data on the issue.
|
|
56
|
-
issuesObject[issueID] ??= {
|
|
57
|
-
issueID,
|
|
58
|
-
weight: issues[issueID].weight ?? 0,
|
|
59
|
-
reporters: new Set(),
|
|
60
|
-
reporterCount: 0,
|
|
61
|
-
reportersString: '',
|
|
62
|
-
violators: new Set(),
|
|
63
|
-
violatorCount: 0
|
|
64
|
-
};
|
|
65
|
-
// Ensure that the tool is in the issues data.
|
|
66
|
-
reporters.add(which);
|
|
67
|
-
// Ensure that it is in the issue data.
|
|
68
|
-
issuesObject[issueID].reporters.add(which);
|
|
69
|
-
const {catalogIndex} = instance;
|
|
70
|
-
// If the instance has a catalog index:
|
|
71
|
-
if (catalogIndex) {
|
|
72
|
-
// Ensure that the violator is in the issues data.
|
|
73
|
-
violators.add(catalogIndex);
|
|
74
|
-
// Ensure that it is in the issue data.
|
|
75
|
-
issuesObject[issueID].violators.add(catalogIndex);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
// Populate the unpopulated subproperties of the issues data.
|
|
82
|
-
issuesData.reporterCount = issuesData.reporters.size;
|
|
83
|
-
issuesData.reportersString = getToolNamesString(issuesData.reporters);
|
|
84
|
-
issuesData.violatorCount = issuesData.violators.size;
|
|
85
|
-
issuesData.preventions = report.jobData.preventions;
|
|
86
|
-
issuesData.issueCount = Object.keys(issuesData.issuesObject).length;
|
|
87
|
-
issuesData.issues = Object.values(issuesData.issuesObject);
|
|
88
|
-
// For each issue in the issues data:
|
|
89
|
-
issuesData.issues.forEach(issue => {
|
|
90
|
-
// Populate its unpopulated properties.
|
|
91
|
-
issue.reporterCount = issue.reporters.size;
|
|
92
|
-
issue.reportersString = getToolNamesString(issue.reporters);
|
|
93
|
-
issue.violatorCount = issue.violators.size;
|
|
94
|
-
});
|
|
95
|
-
// Sort the issues alphabetically by reporters string.
|
|
96
|
-
objectSort(issuesData.issues, 'reportersString', 'alpha');
|
|
97
|
-
// Sort the issues again in descending reporter-count order, making this the primary order.
|
|
98
|
-
objectSort(issuesData.issues, 'reporterCount', 'numericDown');
|
|
99
|
-
// Return the issues data.
|
|
100
|
-
return issuesData;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
23
|
// Adds parameters to a query for the answer page.
|
|
104
24
|
const populateQuery = async (timeStamp, jobID, query) => {
|
|
105
|
-
// Get
|
|
106
|
-
const
|
|
107
|
-
const {
|
|
108
|
-
|
|
109
|
-
|
|
25
|
+
// Get data on the page and its issues according to the report.
|
|
26
|
+
const data = await getData(timeStamp, jobID);
|
|
27
|
+
const {pageData, issuesData} = data;
|
|
28
|
+
// If the page data are invalid:
|
|
29
|
+
if (typeof pageData === 'string') {
|
|
30
|
+
// Return this.
|
|
31
|
+
return pageData;
|
|
32
|
+
}
|
|
33
|
+
// Otherwise, if the issues data are invalid:
|
|
110
34
|
if (typeof issuesData === 'string') {
|
|
111
35
|
// Return this.
|
|
112
36
|
return issuesData;
|
|
113
37
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
reporterCount,
|
|
118
|
-
reportersString,
|
|
119
|
-
violatorCount
|
|
120
|
-
} = issuesData;
|
|
121
|
-
// Add an issue count description to the query.
|
|
122
|
-
query.issueCount = issueCount === 1 ? '1 issue was' : `${issueCount} issues were`;
|
|
123
|
-
query.reporterCount = reporterCount === 1 ? '1 tool' : `${reporterCount} tools`;
|
|
124
|
-
// Add a reporter count and list to the query.
|
|
125
|
-
query.reporters = reportersString;
|
|
126
|
-
// Add a violator count to the query.
|
|
127
|
-
query.violatorCount = violatorCount === 1 ? '1 violator was' : `${violatorCount} violators were`;
|
|
38
|
+
// Otherwise, get fact descriptions for the page.
|
|
39
|
+
const pageInfo = await getPageDataStrings(timeStamp, jobID, pageData);
|
|
40
|
+
const {what, urlLink, testInfo} = pageInfo;
|
|
128
41
|
// Add page data to the query.
|
|
129
42
|
query.target = what;
|
|
130
43
|
query.urlLink = urlLink;
|
|
131
44
|
query.testInfo = testInfo;
|
|
132
|
-
|
|
133
|
-
|
|
45
|
+
const {
|
|
46
|
+
reporterList,
|
|
47
|
+
reporterCount,
|
|
48
|
+
violatorCount,
|
|
49
|
+
issueCount,
|
|
50
|
+
preventions,
|
|
51
|
+
issues
|
|
52
|
+
} = issuesData;
|
|
53
|
+
// Initialize strings for the prevention notices query property.
|
|
134
54
|
const preventionStrings = [];
|
|
135
55
|
const margin = ' '.repeat(6);
|
|
136
56
|
Object.keys(preventions).forEach(preventedToolID => {
|
|
@@ -140,86 +60,84 @@ const populateQuery = async (timeStamp, jobID, query) => {
|
|
|
140
60
|
const preventionString = `${margin}<li>Page not testable by ${toolNameString}: ${causeString}</li>`;
|
|
141
61
|
preventionStrings.push(preventionString);
|
|
142
62
|
});
|
|
63
|
+
// Add prevention notices to the query.
|
|
143
64
|
query.preventions = preventionStrings.join('\n');
|
|
65
|
+
// Add report data to the query.
|
|
66
|
+
query.timeStamp = timeStamp;
|
|
67
|
+
query.jobID = jobID;
|
|
68
|
+
// Add reporter information to the query.
|
|
69
|
+
query.reporterCount = reporterCount === 1 ? '1 tool' : `${reporterCount} tools`;
|
|
70
|
+
query.reporters = reporterList;
|
|
71
|
+
// Add a summary of the issues to the query.
|
|
72
|
+
query.issueCount = issueCount === 1 ? '1 issue was' : `${issueCount} issues were`;
|
|
73
|
+
query.highestCount = issues[4].length;
|
|
74
|
+
query.highCount = issues[3].length;
|
|
75
|
+
query.lowCount = issues[2].length;
|
|
76
|
+
query.lowestCount = issues[1].length;
|
|
77
|
+
// Add a violator count to the query.
|
|
78
|
+
query.violatorCount = violatorCount === 1 ? '1 violator was' : `${violatorCount} violators were`;
|
|
144
79
|
// For each weight:
|
|
145
80
|
[4, 3, 2, 1].forEach(weight => {
|
|
146
|
-
// Initialize data on issues having the weight.
|
|
147
|
-
const weightData = [];
|
|
148
|
-
// Initialize the lines for the weight.
|
|
149
|
-
const weightLines = [];
|
|
150
|
-
// For each issue:
|
|
151
|
-
issuesData.issues.forEach(issueData => {
|
|
152
|
-
const {
|
|
153
|
-
issueID, reporterCount, reportersString, violatorCount, weight: issueWeight
|
|
154
|
-
} = issueData;
|
|
155
|
-
// If it has the weight:
|
|
156
|
-
if (issueWeight === weight) {
|
|
157
|
-
const issue = issues[issueID];
|
|
158
|
-
const {wcag, why} = issue;
|
|
159
|
-
const wcagLink = `<a href="${getWCAGLink(wcag)}">${wcag}</a>`;
|
|
160
|
-
// Add data on it to the weight data.
|
|
161
|
-
weightData.push({
|
|
162
|
-
issueID,
|
|
163
|
-
summary: issue.summary,
|
|
164
|
-
why,
|
|
165
|
-
wcag: wcagLink,
|
|
166
|
-
reporterCount,
|
|
167
|
-
reportersString,
|
|
168
|
-
violatorCount
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
81
|
const weightName = getWeightName(weight);
|
|
173
|
-
|
|
174
|
-
query[`${weightName}Count`] = weightData.length;
|
|
82
|
+
const weightIssues = issues[weight];
|
|
175
83
|
// If any reported issues have the weight:
|
|
176
|
-
if (
|
|
177
|
-
//
|
|
178
|
-
|
|
84
|
+
if (weightIssues.length) {
|
|
85
|
+
// Initialize lines for the weight details query property.
|
|
86
|
+
const detailsLines = [];
|
|
179
87
|
// For each issue with the weight:
|
|
180
|
-
|
|
181
|
-
const
|
|
88
|
+
weightIssues.forEach(issueData => {
|
|
89
|
+
const weightIssueCount = weightIssues.length;
|
|
90
|
+
// Add the issue count to the query.
|
|
91
|
+
query[`${weightName}Count`] = weightIssueCount;
|
|
92
|
+
const {
|
|
93
|
+
issueID,
|
|
94
|
+
reporterCount,
|
|
95
|
+
reporterList,
|
|
96
|
+
summary,
|
|
97
|
+
violatorCount,
|
|
98
|
+
wcag,
|
|
99
|
+
why
|
|
100
|
+
} = issueData;
|
|
101
|
+
const wcagLink = `<a href="${getWCAGLink(wcag)}">${wcag}</a>`;
|
|
182
102
|
// Add the start of a list item to the lines.
|
|
183
|
-
|
|
103
|
+
detailsLines.push(`${margin} <li>`);
|
|
184
104
|
// Add a heading summarizing the issue to the lines.
|
|
185
|
-
|
|
186
|
-
// Add the start of
|
|
187
|
-
|
|
105
|
+
detailsLines.push(`${margin} <h5>${summary}</h5>`);
|
|
106
|
+
// Add the start of a fact list about the issue to the lines.
|
|
107
|
+
detailsLines.push(`${margin} <ul class="pseudoTopLevel">`);
|
|
188
108
|
// Add the issue facts to the lines.
|
|
189
|
-
|
|
190
|
-
|
|
109
|
+
detailsLines.push(`${margin} <li>Why it matters: ${why}`);
|
|
110
|
+
detailsLines.push(`${margin} <li>Related WCAG standard: ${wcagLink}`);
|
|
191
111
|
const reporterCountString = reporterCount === 1 ? '1 tool' : `${reporterCount} tools`;
|
|
192
|
-
|
|
193
|
-
`${margin} <li>Reported by ${reporterCountString} (${
|
|
112
|
+
detailsLines.push(
|
|
113
|
+
`${margin} <li>Reported by ${reporterCountString} (${reporterList})</li>`
|
|
194
114
|
);
|
|
195
115
|
const violatorCountString = violatorCount === 1
|
|
196
116
|
? '1 violator was'
|
|
197
117
|
: `${violatorCount} violators were`;
|
|
198
|
-
|
|
118
|
+
detailsLines.push(`${margin} <li>${violatorCountString} reported</li>`);
|
|
199
119
|
// Add the end of the fact list to the lines.
|
|
200
|
-
|
|
120
|
+
detailsLines.push(`${margin} </ul>`);
|
|
201
121
|
// Add the start of a link list to the lines.
|
|
202
|
-
|
|
122
|
+
detailsLines.push(`${margin} <ul class="nav">`);
|
|
203
123
|
const whereQuestionString = 'Where was the issue found?';
|
|
204
|
-
const labelString = `Where was the ${
|
|
124
|
+
const labelString = `Where was the ${summary} issue found on the ${what} page?`;
|
|
205
125
|
const href = `href="/reportIssue.html/${issueID}/${timeStamp}/${jobID}"`;
|
|
206
126
|
const label = `aria-label="${labelString}"`;
|
|
207
127
|
const whereLink = `<a ${href} ${label}>${whereQuestionString}</a>`;
|
|
208
128
|
// Add a violations link to the lines.
|
|
209
|
-
|
|
129
|
+
detailsLines.push(`${margin} <li>${whereLink}</li>`);
|
|
210
130
|
// Add the end of the link list to the lines.
|
|
211
|
-
|
|
131
|
+
detailsLines.push(`${margin} </ul>`);
|
|
212
132
|
// Add the end of the list item to the lines.
|
|
213
|
-
|
|
133
|
+
detailsLines.push(`${margin} </li>`);
|
|
214
134
|
});
|
|
215
|
-
// Add the
|
|
216
|
-
|
|
217
|
-
// Add the lines documenting the issues with the weight to the query.
|
|
218
|
-
query[`${weightName}Details`] = weightLines.join('\n');
|
|
135
|
+
// Add the weight details lines to the query.
|
|
136
|
+
query[`${weightName}Details`] = detailsLines.join('\n');
|
|
219
137
|
}
|
|
220
138
|
// Otherwise, i.e. if no reported issues have the weight:
|
|
221
139
|
else {
|
|
222
|
-
query[`${weightName}Details`] = `${margin} <
|
|
140
|
+
query[`${weightName}Details`] = `${margin} <li>None</li>`;
|
|
223
141
|
}
|
|
224
142
|
});
|
|
225
143
|
};
|