@jrpool/kilotest 37.0.0 → 38.0.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/alerts.js +1 -1
- package/diagnoses/index.js +39 -5
- package/eslint.config.mjs +4 -1
- package/index.js +27 -26
- package/issues/index.js +31 -10
- package/llms-full.txt +15 -15
- package/llms.txt +2 -2
- package/mcp.js +24 -18
- package/openapi.yaml +125 -70
- package/package.json +1 -1
- package/reannotate/index.js +10 -2
- package/reannotateForm/index.js +19 -4
- package/reportHideForm/index.js +20 -1
- package/reportIssue/api.js +28 -9
- package/reportIssue/index.js +39 -7
- package/reportIssues/index.js +26 -14
- package/reportIssues/util.js +27 -8
- package/reportList/api.js +36 -28
- package/reportSummary/api.js +181 -0
- package/reportUnhideForm/index.js +20 -2
- package/reportsExpungeForm/index.js +9 -1
- package/reportsPruneForm/index.js +11 -1
- package/reportsRewindForm/index.js +9 -1
- package/researchAgent.js +38 -29
- package/retestRec/index.js +11 -2
- package/retestRecForm/index.js +5 -0
- package/target/api.js +46 -35
- package/targets/index.js +20 -1
- package/testRecForm/api.js +2 -2
- package/tutorial/index.js +15 -5
- package/util.js +63 -48
- package/reportIssues/api.js +0 -129
package/openapi.yaml
CHANGED
|
@@ -35,9 +35,9 @@ paths:
|
|
|
35
35
|
|
|
36
36
|
/api/reportList:
|
|
37
37
|
get:
|
|
38
|
-
operationId:
|
|
39
|
-
summary:
|
|
40
|
-
description:
|
|
38
|
+
operationId: listAllAvailableReports
|
|
39
|
+
summary: List all available reports
|
|
40
|
+
description: List all available reports. Each report describes the results of a job that tested a web page for front-end quality (i.e. accessibility, usability, and standards conformity). For each report, the list identifies which page was tested and when and provides URLs to begin incremental retrieval of the test results.
|
|
41
41
|
responses:
|
|
42
42
|
'200':
|
|
43
43
|
description: List of all available reports
|
|
@@ -50,7 +50,7 @@ paths:
|
|
|
50
50
|
post:
|
|
51
51
|
operationId: recommendQualityTestingOfOneWebPage
|
|
52
52
|
summary: Recommend quality testing of one web page
|
|
53
|
-
description: Submit a recommendation for Kilotest to test, for the first time, a particular web page for front-end quality (i.e. accessibility, usability, and standards conformity). Recommendations are typically approved and the testing completed within a day, whereupon the results can be found with the
|
|
53
|
+
description: Submit a recommendation for Kilotest to test, for the first time, a particular web page for front-end quality (i.e. accessibility, usability, and standards conformity). Recommendations are typically approved and the testing completed within a day, whereupon the results can be found with the listAllAvailableReports operation. Before submitting a recommendation, use the listAllAvailableReports operation to ensure that no report about the page is available, and also to see the stylistic rules for the naming of pages. An attempt to recommend a page for testing will fail if a report about the page is already available.
|
|
54
54
|
requestBody:
|
|
55
55
|
description: Test recommendation specifications
|
|
56
56
|
required: true
|
|
@@ -66,11 +66,11 @@ paths:
|
|
|
66
66
|
schema:
|
|
67
67
|
$ref: '#/components/schemas/TestRecFormResponse'
|
|
68
68
|
|
|
69
|
-
/api/
|
|
69
|
+
/api/reportSummary/{timeStamp}/{jobID}:
|
|
70
70
|
get:
|
|
71
|
-
operationId:
|
|
72
|
-
summary:
|
|
73
|
-
description:
|
|
71
|
+
operationId: summarizeOneReport
|
|
72
|
+
summary: Summarize one report
|
|
73
|
+
description: Summarize one report. The summary should briefly describe the testing job and the results, including the rule engines that tested the web page and the issues that were revealed by the reported rule violations, and provide URLs for getting details about issues. The timeStamp and jobID parameters identify the report and were obtained from the response to a listAllAvailableReports operation.
|
|
74
74
|
parameters:
|
|
75
75
|
- name: timeStamp
|
|
76
76
|
in: path
|
|
@@ -91,11 +91,11 @@ paths:
|
|
|
91
91
|
- xx0
|
|
92
92
|
responses:
|
|
93
93
|
'200':
|
|
94
|
-
description:
|
|
94
|
+
description: Summary of the specified report
|
|
95
95
|
content:
|
|
96
96
|
application/json:
|
|
97
97
|
schema:
|
|
98
|
-
$ref: '#/components/schemas/
|
|
98
|
+
$ref: '#/components/schemas/ReportSummaryResponse'
|
|
99
99
|
'404':
|
|
100
100
|
description: No report with the specified identifier is available
|
|
101
101
|
|
|
@@ -108,7 +108,7 @@ paths:
|
|
|
108
108
|
- name: issueID
|
|
109
109
|
in: path
|
|
110
110
|
required: true
|
|
111
|
-
description: Issue identifier (e.g., imageNoText). Available under "
|
|
111
|
+
description: Issue identifier (e.g., imageNoText). Available under "response content" > "issues revealed" > [item] > "identifier" in the summarizeOneReport response.
|
|
112
112
|
schema:
|
|
113
113
|
type: string
|
|
114
114
|
examples:
|
|
@@ -153,7 +153,7 @@ components:
|
|
|
153
153
|
tool name:
|
|
154
154
|
type: string
|
|
155
155
|
examples:
|
|
156
|
-
-
|
|
156
|
+
- listAllAvailableReports
|
|
157
157
|
request:
|
|
158
158
|
type: object
|
|
159
159
|
properties:
|
|
@@ -177,15 +177,78 @@ components:
|
|
|
177
177
|
URLs:
|
|
178
178
|
type: object
|
|
179
179
|
properties:
|
|
180
|
-
'
|
|
180
|
+
'for you':
|
|
181
181
|
type: string
|
|
182
|
-
'
|
|
182
|
+
'for humans':
|
|
183
183
|
type: string
|
|
184
184
|
closest ancestor request:
|
|
185
185
|
oneOf:
|
|
186
186
|
- type: 'null'
|
|
187
187
|
- type: object
|
|
188
188
|
properties:
|
|
189
|
+
identifier:
|
|
190
|
+
type: string
|
|
191
|
+
description:
|
|
192
|
+
type: string
|
|
193
|
+
URLs:
|
|
194
|
+
type: object
|
|
195
|
+
properties:
|
|
196
|
+
'for you':
|
|
197
|
+
type: string
|
|
198
|
+
'for humans':
|
|
199
|
+
type: string
|
|
200
|
+
response metadata:
|
|
201
|
+
type: object
|
|
202
|
+
properties:
|
|
203
|
+
identifier:
|
|
204
|
+
type: string
|
|
205
|
+
description: Unique identifier for this response instance.
|
|
206
|
+
date and time:
|
|
207
|
+
type: string
|
|
208
|
+
description: UTC date and time when the response was generated, in ISO 8601 format.
|
|
209
|
+
format: date-time
|
|
210
|
+
|
|
211
|
+
SharedFacts:
|
|
212
|
+
type: object
|
|
213
|
+
properties:
|
|
214
|
+
summary:
|
|
215
|
+
type: string
|
|
216
|
+
description: Natural-language facts about the request, the response, and Kilotest.
|
|
217
|
+
tool collection name:
|
|
218
|
+
type: string
|
|
219
|
+
examples:
|
|
220
|
+
- Kilotest
|
|
221
|
+
tool name:
|
|
222
|
+
type: string
|
|
223
|
+
examples:
|
|
224
|
+
- listAllAvailableReports
|
|
225
|
+
request:
|
|
226
|
+
type: object
|
|
227
|
+
properties:
|
|
228
|
+
description:
|
|
229
|
+
type: string
|
|
230
|
+
method:
|
|
231
|
+
type: string
|
|
232
|
+
enum:
|
|
233
|
+
- GET
|
|
234
|
+
- POST
|
|
235
|
+
payload:
|
|
236
|
+
type: object
|
|
237
|
+
description: The request payload, if method is POST, or otherwise omitted.
|
|
238
|
+
URLs:
|
|
239
|
+
type: object
|
|
240
|
+
properties:
|
|
241
|
+
'for you':
|
|
242
|
+
type: string
|
|
243
|
+
'for humans':
|
|
244
|
+
type: string
|
|
245
|
+
closest ancestor request:
|
|
246
|
+
oneOf:
|
|
247
|
+
- type: 'null'
|
|
248
|
+
- type: object
|
|
249
|
+
properties:
|
|
250
|
+
'tool name':
|
|
251
|
+
type: string
|
|
189
252
|
description:
|
|
190
253
|
type: string
|
|
191
254
|
URLs:
|
|
@@ -209,13 +272,13 @@ components:
|
|
|
209
272
|
TestRecForm:
|
|
210
273
|
type: object
|
|
211
274
|
properties:
|
|
212
|
-
|
|
275
|
+
description of the web page:
|
|
213
276
|
type: string
|
|
214
277
|
description: Description of the web page to be tested.
|
|
215
|
-
|
|
278
|
+
URL of the web page:
|
|
216
279
|
type: string
|
|
217
280
|
description: URL of the web page to be tested.
|
|
218
|
-
|
|
281
|
+
reason for testing the web page:
|
|
219
282
|
type: string
|
|
220
283
|
description: Reason for testing the page.
|
|
221
284
|
|
|
@@ -273,7 +336,7 @@ components:
|
|
|
273
336
|
for you:
|
|
274
337
|
type: string
|
|
275
338
|
format: uri
|
|
276
|
-
description: URL for an
|
|
339
|
+
description: URL for an LLM to request the next tier of detail.
|
|
277
340
|
for humans:
|
|
278
341
|
type: string
|
|
279
342
|
format: uri
|
|
@@ -343,7 +406,7 @@ components:
|
|
|
343
406
|
whether a later report about the same page exists:
|
|
344
407
|
type: boolean
|
|
345
408
|
description: If true, a more recent report about this page is available. If you want the latest results, use that report instead.
|
|
346
|
-
URLs for
|
|
409
|
+
URLs for more details:
|
|
347
410
|
$ref: '#/components/schemas/NextTierURLs'
|
|
348
411
|
size of the report in bytes:
|
|
349
412
|
type: integer
|
|
@@ -354,7 +417,7 @@ components:
|
|
|
354
417
|
Target:
|
|
355
418
|
type: object
|
|
356
419
|
properties:
|
|
357
|
-
|
|
420
|
+
description:
|
|
358
421
|
type: string
|
|
359
422
|
description: All or part of a description of the web page. If the page is the home page of an organization, the description is the name of the organization (e.g., “Earthjustice”). Otherwise, the description appends minimal differentiating words to the name of the organization (e.g., “Earthjustice Donate”), without the word “page”.
|
|
360
423
|
hostname:
|
|
@@ -363,12 +426,12 @@ components:
|
|
|
363
426
|
|
|
364
427
|
ReportListResponse:
|
|
365
428
|
allOf:
|
|
366
|
-
- $ref: '#/components/schemas/
|
|
429
|
+
- $ref: '#/components/schemas/SharedFacts'
|
|
367
430
|
- type: object
|
|
368
431
|
properties:
|
|
369
|
-
|
|
432
|
+
response content:
|
|
370
433
|
type: array
|
|
371
|
-
description: One entry per available Kilotest report, in alphabetical order by page description and, in case of multiple reports per page, in order of creation date and time.
|
|
434
|
+
description: One entry per available Kilotest report, in alphabetical order by page description and, in case of multiple reports per page, in order of creation date and time. Whether two reports are about the same page is determined by the page descriptions, not page URLs.
|
|
372
435
|
items:
|
|
373
436
|
$ref: '#/components/schemas/ReportListItem'
|
|
374
437
|
|
|
@@ -440,59 +503,51 @@ components:
|
|
|
440
503
|
items:
|
|
441
504
|
$ref: '#/components/schemas/IssueEntry'
|
|
442
505
|
|
|
443
|
-
|
|
506
|
+
IssueSummary:
|
|
507
|
+
type: object
|
|
508
|
+
properties:
|
|
509
|
+
identifier:
|
|
510
|
+
type: string
|
|
511
|
+
summary:
|
|
512
|
+
type: string
|
|
513
|
+
impact on a user:
|
|
514
|
+
type: string
|
|
515
|
+
priority:
|
|
516
|
+
type: string
|
|
517
|
+
enum:
|
|
518
|
+
- lowest
|
|
519
|
+
- low
|
|
520
|
+
- high
|
|
521
|
+
- highest
|
|
522
|
+
URLs for more details:
|
|
523
|
+
$ref: '#/components/schemas/NextTierURLs'
|
|
524
|
+
|
|
525
|
+
ReportSummaryResponse:
|
|
444
526
|
allOf:
|
|
445
|
-
- $ref: '#/components/schemas/
|
|
527
|
+
- $ref: '#/components/schemas/SharedFacts'
|
|
446
528
|
- type: object
|
|
447
529
|
properties:
|
|
448
|
-
|
|
449
|
-
type: object
|
|
450
|
-
properties:
|
|
451
|
-
identifier:
|
|
452
|
-
type: string
|
|
453
|
-
creation date:
|
|
454
|
-
type: string
|
|
455
|
-
format: date-time
|
|
456
|
-
days since the creation date:
|
|
457
|
-
type: integer
|
|
458
|
-
tested web page:
|
|
530
|
+
response content:
|
|
459
531
|
type: object
|
|
460
532
|
properties:
|
|
461
|
-
|
|
462
|
-
type:
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
rule engines that reported issues:
|
|
475
|
-
$ref: '#/components/schemas/RuleEnginesSummary'
|
|
476
|
-
number of issues reported:
|
|
477
|
-
type: object
|
|
478
|
-
properties:
|
|
479
|
-
total:
|
|
533
|
+
rule engines that tried to test the page:
|
|
534
|
+
type: array
|
|
535
|
+
items:
|
|
536
|
+
$ref: '#/components/schemas/RuleEngineInfo'
|
|
537
|
+
rule engines that could not test the page:
|
|
538
|
+
type: array
|
|
539
|
+
items:
|
|
540
|
+
$ref: '#/components/schemas/RuleEngineFailure'
|
|
541
|
+
names of rule engines that reported rule violations:
|
|
542
|
+
type: array
|
|
543
|
+
items:
|
|
544
|
+
type: string
|
|
545
|
+
number of elements reported as violators:
|
|
480
546
|
type: integer
|
|
481
|
-
|
|
482
|
-
type:
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
type: integer
|
|
486
|
-
high priority:
|
|
487
|
-
type: integer
|
|
488
|
-
low priority:
|
|
489
|
-
type: integer
|
|
490
|
-
lowest priority:
|
|
491
|
-
type: integer
|
|
492
|
-
number of HTML elements reported as exhibiting issues:
|
|
493
|
-
type: integer
|
|
494
|
-
issues reported:
|
|
495
|
-
$ref: '#/components/schemas/IssuesByPriority'
|
|
547
|
+
issues revealed:
|
|
548
|
+
type: array
|
|
549
|
+
items:
|
|
550
|
+
$ref: '#/components/schemas/IssueSummary'
|
|
496
551
|
|
|
497
552
|
HTMLElementDetail:
|
|
498
553
|
type: object
|
package/package.json
CHANGED
package/reannotate/index.js
CHANGED
|
@@ -21,9 +21,17 @@ exports.answer = async authCode => {
|
|
|
21
21
|
for (const targetData of targetsData) {
|
|
22
22
|
const [timeStamp, jobID] = targetData.jobName.split('-');
|
|
23
23
|
// Reannotate it.
|
|
24
|
-
await annotateReport(ruleIDs, timeStamp, jobID);
|
|
24
|
+
const annotationError = await annotateReport(ruleIDs, timeStamp, jobID);
|
|
25
|
+
// If this failed:
|
|
26
|
+
if (annotationError) {
|
|
27
|
+
// Return an error page.
|
|
28
|
+
return {
|
|
29
|
+
status: 'error',
|
|
30
|
+
message: annotationError
|
|
31
|
+
};
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
|
-
//
|
|
34
|
+
// If every annotation succeeded, get the answer page.
|
|
27
35
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
28
36
|
// Return it.
|
|
29
37
|
return {
|
package/reannotateForm/index.js
CHANGED
|
@@ -18,11 +18,18 @@ const populateQuery = async query => {
|
|
|
18
18
|
const reClassified = {};
|
|
19
19
|
// For each target:
|
|
20
20
|
for (const targetLog of targetLogs) {
|
|
21
|
-
const {jobName} = targetLog;
|
|
21
|
+
const {jobName = '-'} = targetLog;
|
|
22
22
|
// Get the latest report on it.
|
|
23
23
|
const report = await getReport(... jobName.split('-'));
|
|
24
|
-
const {acts} = report;
|
|
25
|
-
//
|
|
24
|
+
const {acts = [], error} = report;
|
|
25
|
+
// If this failed:
|
|
26
|
+
if (error) {
|
|
27
|
+
// Populate the query with the reason.
|
|
28
|
+
query.error = error;
|
|
29
|
+
// Stop populating the query.
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Otherwise, i.e. if it succeeded, for each act in the report:
|
|
26
33
|
acts.forEach(act => {
|
|
27
34
|
const {result, type, which} = act;
|
|
28
35
|
// If it is a test act with standard instances:
|
|
@@ -100,7 +107,15 @@ exports.answer = async () => {
|
|
|
100
107
|
const query = {};
|
|
101
108
|
// Create a query to replace placeholders.
|
|
102
109
|
await populateQuery(query);
|
|
103
|
-
//
|
|
110
|
+
// If the query reports an error:
|
|
111
|
+
if (query.error) {
|
|
112
|
+
// Return the error.
|
|
113
|
+
return {
|
|
114
|
+
status: 'error',
|
|
115
|
+
message: query.error
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Otherwise, i.e. if the query does not report an error, get the template.
|
|
104
119
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
105
120
|
// Replace its placeholders.
|
|
106
121
|
Object.keys(query).forEach(param => {
|
package/reportHideForm/index.js
CHANGED
|
@@ -22,7 +22,15 @@ exports.answer = async (_, search) => {
|
|
|
22
22
|
if (authCode === process.env.AUTH_CODE) {
|
|
23
23
|
// Get the log of the report.
|
|
24
24
|
const log = await getLog(... jobName.split('-'));
|
|
25
|
-
//
|
|
25
|
+
// If this failed:
|
|
26
|
+
if (log.error) {
|
|
27
|
+
// Return why.
|
|
28
|
+
return {
|
|
29
|
+
status: 'error',
|
|
30
|
+
message: log.error
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Otherwise, i.e. if it succeeded, add a hiddenness property to the log.
|
|
26
34
|
log.hidden = true;
|
|
27
35
|
// Save the updated log.
|
|
28
36
|
await fs.writeFile(path.join(logsPath, `${jobName}.json`), getJSON(log));
|
|
@@ -37,13 +45,24 @@ exports.answer = async (_, search) => {
|
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
const reportFileNames = await fs.readdir(reportsPath);
|
|
48
|
+
// Initialize an array of report specifications.
|
|
40
49
|
const reportSpecs = [];
|
|
41
50
|
// For each report:
|
|
42
51
|
for (const reportFileName of reportFileNames) {
|
|
43
52
|
const [timeStamp, jobID] = reportFileName.slice(0, -5).split('-');
|
|
44
53
|
// Get its log.
|
|
45
54
|
const log = await getLog(timeStamp, jobID);
|
|
55
|
+
// If this failed:
|
|
56
|
+
if (log.error) {
|
|
57
|
+
// Return why.
|
|
58
|
+
return {
|
|
59
|
+
status: 'error',
|
|
60
|
+
message: log.error
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Otherwise, i.e. if it succeeded:
|
|
46
64
|
const {what, hidden} = log;
|
|
65
|
+
// Add the report to the array.
|
|
47
66
|
reportSpecs.push({
|
|
48
67
|
what,
|
|
49
68
|
timeStamp,
|
package/reportIssue/api.js
CHANGED
|
@@ -24,8 +24,16 @@ const getIssueFacts = async (timeStamp, jobID, issue) => {
|
|
|
24
24
|
const wcagType = wcag.length === 3 ? 'guideline' : 'success criterion';
|
|
25
25
|
// Get the report.
|
|
26
26
|
const report = await getReport(timeStamp, jobID);
|
|
27
|
+
const {acts, catalog, error} = report;
|
|
28
|
+
// If this failed:
|
|
29
|
+
if (error) {
|
|
30
|
+
// Return why.
|
|
31
|
+
return {
|
|
32
|
+
status: 'error',
|
|
33
|
+
message: error
|
|
34
|
+
};
|
|
35
|
+
}
|
|
27
36
|
const violatorIndexSet = new Set();
|
|
28
|
-
const {acts, catalog} = report;
|
|
29
37
|
// For each act of the report:
|
|
30
38
|
acts.forEach(act => {
|
|
31
39
|
// If it is a test act:
|
|
@@ -56,7 +64,10 @@ const getIssueFacts = async (timeStamp, jobID, issue) => {
|
|
|
56
64
|
'names': reporters.map(tool => tool.toolName)
|
|
57
65
|
},
|
|
58
66
|
'number of HTML elements reported as exhibiting the issue': violatorCount,
|
|
59
|
-
'HTML elements reported as exhibiting the issue': Array
|
|
67
|
+
'HTML elements reported as exhibiting the issue': Array
|
|
68
|
+
.from(violatorIndexSet)
|
|
69
|
+
.filter(index => catalog[index])
|
|
70
|
+
.map(index => ({
|
|
60
71
|
identifier: String(index),
|
|
61
72
|
'tag name': catalog[index].tagName,
|
|
62
73
|
'id attribute': catalog[index].id,
|
|
@@ -82,11 +93,19 @@ exports.response = async args => {
|
|
|
82
93
|
}
|
|
83
94
|
// Otherwise, i.e. if the report is available, get data on the report and its issues.
|
|
84
95
|
const data = await getData(timeStamp, jobID);
|
|
85
|
-
const {
|
|
96
|
+
const {error, issuesData, pageData} = data;
|
|
97
|
+
// If this failed:
|
|
98
|
+
if (error) {
|
|
99
|
+
// Return why.
|
|
100
|
+
return {
|
|
101
|
+
status: 'error',
|
|
102
|
+
message: error
|
|
103
|
+
};
|
|
104
|
+
}
|
|
86
105
|
const {what, url, daysAgo} = pageData;
|
|
87
106
|
const {issueCount, issues, preventions, reporterCount, reporters, violatorCount} = issuesData;
|
|
88
107
|
let issue;
|
|
89
|
-
//
|
|
108
|
+
// Otherwise, i.e. if it succeeded, get the level of and the data on the issue.
|
|
90
109
|
const issueLevel = [4, 3, 2, 1].find(level => {
|
|
91
110
|
issue = issues[level].find(issue => issue.issueID === issueID);
|
|
92
111
|
return issue;
|
|
@@ -116,14 +135,14 @@ exports.response = async args => {
|
|
|
116
135
|
},
|
|
117
136
|
method: 'GET',
|
|
118
137
|
URLs: {
|
|
119
|
-
'
|
|
120
|
-
'
|
|
138
|
+
'for you': `${thisHost}/api/reportIssue/${issueID}/${timeStamp}/${jobID}`,
|
|
139
|
+
'for humans': `${thisHost}/reportIssue.html/${issueID}/${timeStamp}/${jobID}`
|
|
121
140
|
},
|
|
122
141
|
'closest ancestor request': {
|
|
123
|
-
identifier: '
|
|
124
|
-
description: '
|
|
142
|
+
identifier: 'summarizeOneReport',
|
|
143
|
+
description: 'Summarize one report.',
|
|
125
144
|
URLs: {
|
|
126
|
-
'for you': `${thisHost}/api/
|
|
145
|
+
'for you': `${thisHost}/api/reportSummary/${timeStamp}/${jobID}`,
|
|
127
146
|
'for humans': `${thisHost}/reportIssues.html/${timeStamp}/${jobID}`
|
|
128
147
|
}
|
|
129
148
|
}
|
package/reportIssue/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
index.js
|
|
3
|
-
Answers the
|
|
3
|
+
Answers the reportIssue question.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// IMPORTS
|
|
@@ -25,10 +25,26 @@ const path = require('path');
|
|
|
25
25
|
|
|
26
26
|
// Adds parameters to a query for the answer page.
|
|
27
27
|
const populateQuery = async (issueID, timeStamp, jobID, query) => {
|
|
28
|
-
//
|
|
29
|
-
query.issue = issues[issueID].summary;
|
|
28
|
+
// Get descriptions of the page facts.
|
|
30
29
|
const pageDataStrings = await getPageDataStrings(timeStamp, jobID);
|
|
31
|
-
|
|
30
|
+
// If this failed:
|
|
31
|
+
if (pageDataStrings.error) {
|
|
32
|
+
// Populate the query with the reason.
|
|
33
|
+
query.error = pageDataStrings.error;
|
|
34
|
+
// Stop populating the query.
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Otherwise, i.e. if it succeeded, add the issue summary to the query.
|
|
38
|
+
query.issue = issues[issueID]?.summary;
|
|
39
|
+
// If adding the issue summary failed:
|
|
40
|
+
if (! query.issue) {
|
|
41
|
+
// Populate the query with the reason.
|
|
42
|
+
query.error = 'Issue not found';
|
|
43
|
+
// Stop populating the query.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const {testInfo, url, urlLink, what} = pageDataStrings;
|
|
47
|
+
// Add page facts to the query.
|
|
32
48
|
query.target = what;
|
|
33
49
|
query.urlLink = urlLink;
|
|
34
50
|
query.testInfo = testInfo;
|
|
@@ -44,6 +60,14 @@ const populateQuery = async (issueID, timeStamp, jobID, query) => {
|
|
|
44
60
|
// Get the report.
|
|
45
61
|
const report = await getReport(timeStamp, jobID);
|
|
46
62
|
const {acts, catalog} = report;
|
|
63
|
+
// If this failed:
|
|
64
|
+
if (report.error) {
|
|
65
|
+
// Populate the query with the reason.
|
|
66
|
+
query.error = report.error;
|
|
67
|
+
// Stop populating the query.
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Otherwise, i.e. if it succeeded, get the test acts of the report.
|
|
47
71
|
const testActs = acts.filter(act => act.type === 'test');
|
|
48
72
|
// For each test act:
|
|
49
73
|
testActs.forEach(act => {
|
|
@@ -159,7 +183,15 @@ exports.answer = async pageArgs => {
|
|
|
159
183
|
const query = {};
|
|
160
184
|
// Create a query to replace the placeholders.
|
|
161
185
|
await populateQuery(issueID, timeStamp, jobID, query);
|
|
162
|
-
// If
|
|
186
|
+
// If this failed:
|
|
187
|
+
if (query.error) {
|
|
188
|
+
// Return the error.
|
|
189
|
+
return {
|
|
190
|
+
status: 'error',
|
|
191
|
+
message: query.error
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Otherwise, if it succeeded and the report facts were obtained:
|
|
163
195
|
if (query.testInfo) {
|
|
164
196
|
// Get the template.
|
|
165
197
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
@@ -173,9 +205,9 @@ exports.answer = async pageArgs => {
|
|
|
173
205
|
answerPage
|
|
174
206
|
};
|
|
175
207
|
}
|
|
176
|
-
// Otherwise, report this.
|
|
208
|
+
// Otherwise, i.e. if the report facts were not obtained, report this.
|
|
177
209
|
return {
|
|
178
210
|
status: 'error',
|
|
179
|
-
message: '
|
|
211
|
+
message: 'Report facts not obtained'
|
|
180
212
|
};
|
|
181
213
|
};
|
package/reportIssues/index.js
CHANGED
|
@@ -24,20 +24,24 @@ const populateQuery = async (timeStamp, jobID, query) => {
|
|
|
24
24
|
// Get data on the target and its issues according to the report.
|
|
25
25
|
const data = await getData(timeStamp, jobID);
|
|
26
26
|
const {pageData, issuesData} = data;
|
|
27
|
-
// If
|
|
28
|
-
if (
|
|
29
|
-
//
|
|
30
|
-
|
|
27
|
+
// If this failed:
|
|
28
|
+
if (data.error) {
|
|
29
|
+
// Populate the query with the reason.
|
|
30
|
+
query.error = data.error;
|
|
31
|
+
// Stop populating the query.
|
|
32
|
+
return;
|
|
31
33
|
}
|
|
32
|
-
// Otherwise, if
|
|
33
|
-
if (typeof issuesData === 'string') {
|
|
34
|
-
// Return this.
|
|
35
|
-
return issuesData;
|
|
36
|
-
}
|
|
37
|
-
// Otherwise, get fact descriptions for the target.
|
|
34
|
+
// Otherwise, i.e. if it succeeded, get fact descriptions for the target.
|
|
38
35
|
const pageInfo = await getPageDataStrings(timeStamp, jobID, pageData);
|
|
39
|
-
const {
|
|
40
|
-
//
|
|
36
|
+
const {testInfo, urlLink, what} = pageInfo;
|
|
37
|
+
// If this failed:
|
|
38
|
+
if (pageInfo.error) {
|
|
39
|
+
// Populate the query with the reason.
|
|
40
|
+
query.error = pageInfo.error;
|
|
41
|
+
// Stop populating the query.
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Otherwise, i.e. if it succeeded, add target data to the query.
|
|
41
45
|
query.target = what;
|
|
42
46
|
query.urlLink = urlLink;
|
|
43
47
|
query.testInfo = testInfo;
|
|
@@ -154,7 +158,15 @@ exports.answer = async pageArgs => {
|
|
|
154
158
|
const query = {};
|
|
155
159
|
// Create a query to replace the placeholders.
|
|
156
160
|
await populateQuery(timeStamp, jobID, query);
|
|
157
|
-
// If
|
|
161
|
+
// If this failed:
|
|
162
|
+
if (query.error) {
|
|
163
|
+
// Return the error.
|
|
164
|
+
return {
|
|
165
|
+
status: 'error',
|
|
166
|
+
message: query.error
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// Otherwise, if it succeeded and the report facts were obtained:
|
|
158
170
|
if (query.testInfo) {
|
|
159
171
|
// Get the template.
|
|
160
172
|
let answerPage = await fs.readFile(path.join(__dirname, 'index.html'), 'utf8');
|
|
@@ -171,6 +183,6 @@ exports.answer = async pageArgs => {
|
|
|
171
183
|
// Otherwise, i.e. if they were not obtained, report this.
|
|
172
184
|
return {
|
|
173
185
|
status: 'error',
|
|
174
|
-
message: 'Report
|
|
186
|
+
message: 'Report facts not obtained'
|
|
175
187
|
};
|
|
176
188
|
};
|