@jrpool/kilotest 57.2.3 → 57.3.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": "@jrpool/kilotest",
3
- "version": "57.2.3",
3
+ "version": "57.3.0",
4
4
  "description": "Ensemble testing for front-end web quality",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -119,6 +119,7 @@ const populateQuery = async (query: Record<string, any>) => {
119
119
  preventedEngineNames,
120
120
  reporterNames,
121
121
  reporterCount,
122
+ violationCount,
122
123
  violatorCount
123
124
  } = reportData;
124
125
  // Otherwise, i.e. if it succeeded, add lines about the report.
@@ -147,20 +148,22 @@ const populateQuery = async (query: Record<string, any>) => {
147
148
  const reporterNamesString = reporterNames.join(' + ');
148
149
  reporterString = `${reporterString} (${reporterNamesString})`;
149
150
  }
150
- const issueCountString = getCountString(issueCount, 'issue was', 'issues were');
151
- const violatorString = getCountString(violatorCount, 'violator was', 'violators were');
152
151
  lines.tested.push(`${margin} <li>${reporterString}</li>`);
153
- lines.tested.push(`${margin} <li>${issueCountString} reported</li>`);
154
- lines.tested.push(`${margin} <li>${violatorString} reported</li>`);
152
+ lines.tested.push(`${margin} <li>Summary of results:`);
153
+ lines.tested.push(`${margin} <ul>`);
154
+ lines.tested.push(`${margin} <li>Violations: ${violationCount}</li>`);
155
+ lines.tested.push(`${margin} <li>Violators: ${violatorCount}</li>`);
156
+ lines.tested.push(`${margin} <li>Issues: ${issueCount}</li>`);
157
+ lines.tested.push(`${margin} </ul>`);
158
+ lines.tested.push(`${margin} </li>`);
155
159
  lines.tested.push(`${margin} </ul>`);
156
160
  lines.tested.push(`${margin}<ul class="nav">`);
157
161
  // If any issues were reported:
158
162
  if (issueCount) {
159
- // Add a question link about the reported issues to the lines.
163
+ // Add a link to issue details to the lines.
160
164
  const href = `href="listIssues.html/${timeStamp}/${jobID}"`;
161
- const label = `aria-label="What ${issueCountString} reported for the ${description} page?"`;
162
- const questionString = issueCount === 1 ? 'was the issue' : 'were the issues';
163
- const link = `<a ${href} ${label}>What ${questionString}?</a>`;
165
+ const label = `aria-label="issue details for the ${description} page"`;
166
+ const link = `<a ${href} ${label}>Issue details</a>`;
164
167
  lines.tested.push(`${margin} <li>${link}</li>`);
165
168
  }
166
169
  let retestString: string = '';
@@ -216,3 +216,76 @@ test('listReports shows no-reports message when the database is empty', async ()
216
216
  await fs.rm(tmpDir, {recursive: true}).catch(() => {});
217
217
  }
218
218
  });
219
+
220
+ // Returns the details element of the report whose summary starts with a description and whose issue link, if required, contains a fragment.
221
+ const getReportDetails = (html: any, description: string, hrefFragment?: string) => {
222
+ const matches = html.querySelectorAll('details').filter((d: any) => {
223
+ const summary = d.querySelector('summary')?.text ?? '';
224
+ if (!summary.startsWith(description)) {
225
+ return false;
226
+ }
227
+ return hrefFragment === undefined
228
+ || d.querySelectorAll('a').some((a: any) => a.getAttribute('href')?.includes(hrefFragment));
229
+ });
230
+ assert.equal(matches.length, 1, `exactly one report matches ${description} ${hrefFragment ?? ''}`);
231
+ return matches[0];
232
+ };
233
+
234
+ // Returns the rule-engine line, the prevention line, and the 3 summary amounts of a details element.
235
+ const getResultFacts = (details: any) => {
236
+ const items = details.querySelectorAll('li');
237
+ const itemTexts: string[] = items.map((li: any) => li.text.trim());
238
+ const getAmount = (label: string) => {
239
+ const text = itemTexts.find(t => t.startsWith(`${label}: `));
240
+ assert.ok(text, `${label} item exists`);
241
+ return Number(text.slice(label.length + 2));
242
+ };
243
+ // The summary item is the parent of the 3 amount items.
244
+ const summaryItem = items.find((li: any) => li.text.trim().startsWith('Summary of results:'));
245
+ assert.ok(summaryItem, 'Summary of results item exists');
246
+ const amountLabels = summaryItem.querySelectorAll('ul > li').map((li: any) => li.text.trim().split(':')[0]);
247
+ return {
248
+ reporterLine: itemTexts.find(t => t.endsWith('reported issues') || t.includes('reported issues (')),
249
+ preventionLine: itemTexts.find(t => t.startsWith('Page not testable by')),
250
+ amountLabels,
251
+ violations: getAmount('Violations'),
252
+ violators: getAmount('Violators'),
253
+ issues: getAmount('Issues')
254
+ };
255
+ };
256
+
257
+ // Expected facts, hand-computed from the fixtures.
258
+ const expectedFacts: [string, string | undefined, string, number, number, number][] = [
259
+ // Description, issue-link fragment, reporter line, violations, violators, issues.
260
+ ['Mixed Outcomes Page', '260101T0000/mix', '2 rule engines reported issues (Alfa + Axe)', 3, 2, 2],
261
+ ['Mixed Outcomes Page', '260202T0000/new', '1 rule engine reported issues (Axe)', 1, 1, 1],
262
+ ['All CantTell Page', undefined, '0 rule engines reported issues', 0, 0, 0],
263
+ ['No Outcomes Page', undefined, '1 rule engine reported issues (Accessibility Checker)', 1, 1, 1],
264
+ ['Empty Results Page', undefined, '0 rule engines reported issues', 0, 0, 0],
265
+ ['Prevented Page', undefined, '1 rule engine reported issues (Axe)', 1, 1, 1],
266
+ ['Multi Violator Page', undefined, '2 rule engines reported issues (Alfa + Axe)', 4, 3, 1],
267
+ ['Branch Coverage Page', undefined, '1 rule engine reported issues (Axe)', 4, 4, 1]
268
+ ];
269
+
270
+ for (const [description, fragment, reporterLine, violations, violators, issues] of expectedFacts) {
271
+ test(`listReports gives correct rule-engine count and names and summary amounts for ${description}${fragment ? ` (${fragment})` : ''}`, async () => {
272
+ const result: any = await answer();
273
+ const html = parse(result.answerPage);
274
+ const facts = getResultFacts(getReportDetails(html, description, fragment));
275
+ assert.equal(facts.reporterLine, reporterLine);
276
+ assert.deepEqual(facts.amountLabels, ['Violations', 'Violators', 'Issues']);
277
+ assert.equal(facts.violations, violations);
278
+ assert.equal(facts.violators, violators);
279
+ assert.equal(facts.issues, issues);
280
+ });
281
+ }
282
+
283
+ test('listReports reports the prevented rule engine only for the report with a prevention', async () => {
284
+ const result: any = await answer();
285
+ const html = parse(result.answerPage);
286
+ const prevented = getResultFacts(getReportDetails(html, 'Prevented Page'));
287
+ assert.equal(prevented.preventionLine, 'Page not testable by 1 rule engine (Alfa)');
288
+ const others = html.querySelectorAll('details').filter((d: any) => !d.text.includes('Prevented Page'));
289
+ assert.equal(others.length, 7);
290
+ assert.ok(others.every((d: any) => !d.text.includes('Page not testable by')));
291
+ });
package/web/util.ts CHANGED
@@ -54,6 +54,7 @@ export type ReportData = {
54
54
  engineCount: number;
55
55
  reporterNames: string[];
56
56
  reporterCount: number;
57
+ violationCount: number;
57
58
  violatorCount: number;
58
59
  preventedEngineNames: string[];
59
60
  preventedEngineCount: number;
@@ -160,6 +161,7 @@ export const getReportData = async (timeStamp: string, jobID: string): Promise<R
160
161
  engineCount: 0,
161
162
  reporterNames: [] as string[],
162
163
  reporterCount: 0,
164
+ violationCount: 0,
163
165
  violatorCount: 0,
164
166
  preventedEngineNames: [] as string[],
165
167
  preventedEngineCount: 0
@@ -182,6 +184,8 @@ export const getReportData = async (timeStamp: string, jobID: string): Promise<R
182
184
  reporterIDSet.add(act.which!);
183
185
  // Ensure that the issue is in the temporary data.
184
186
  issueIDSet.add(issueID);
187
+ // Increment the violation count.
188
+ data.violationCount++;
185
189
  // If the violator has a catalog index:
186
190
  if (catalogIndex) {
187
191
  // Ensure that the violator is in the temporary data.