@jrpool/kilotest 30.0.3 → 31.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/index.js CHANGED
@@ -14,6 +14,7 @@ const {
14
14
  getJobNames,
15
15
  getJSON,
16
16
  getLogPath,
17
+ getLogs,
17
18
  getObject,
18
19
  getPOSTData,
19
20
  getReport,
@@ -22,6 +23,7 @@ const {
22
23
  isHidden,
23
24
  isTimeStamp,
24
25
  isJobID,
26
+ isURL,
25
27
  jobsPath,
26
28
  logsPath,
27
29
  reportsPath,
@@ -198,7 +200,7 @@ const requestHandler = async (request, response) => {
198
200
  // Serve response headers, including one allowing requests from other applications.
199
201
  response.setHeader('Access-Control-Allow-Origin', '*');
200
202
  response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
201
- response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
203
+ response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
202
204
  response.statusCode = 204;
203
205
  response.end();
204
206
  }
@@ -568,10 +570,10 @@ const requestHandler = async (request, response) => {
568
570
  // Get the segments of the path after api.
569
571
  const segments = pathTail.split('/');
570
572
  // If the first segment is the ID of the Testaro agent and the agent is authenticated:
571
- if (specs[0] === testaroAgent && postData.agentPW === testaroAgentPW) {
572
- const agentID = specs[0];
573
+ if (segments[0] === testaroAgent && postData.agentPW === testaroAgentPW) {
574
+ const agentID = segments[0];
573
575
  // Get the requested service from the path.
574
- const service = specs[1];
576
+ const service = segments[1];
575
577
  // If the service is job assignment:
576
578
  if (service === 'job') {
577
579
  let clean = true;
@@ -678,6 +680,41 @@ const requestHandler = async (request, response) => {
678
680
  );
679
681
  }
680
682
  }
683
+ // Otherwise, if the first segment is the test recommendation service:
684
+ else if (segments[0] === 'testRecForm') {
685
+ const {what, url, why} = postData;
686
+ const logs = await getLogs();
687
+ const whats = logs.map(log => log.what);
688
+ const urls = logs.map(log => log.url);
689
+ // If the payload is a valid test recommendation:
690
+ if (what && isURL(url) && why) {
691
+ // If an available report has the same URL or the same page description:
692
+ if (whats.includes(what) || urls.includes(url)) {
693
+ // Report this.
694
+ await serveError(
695
+ 'ERROR: A report with the same page description or URL is already available',
696
+ response,
697
+ false
698
+ );
699
+ }
700
+ // Otherwise, i.e. if no report on the page is available:
701
+ else {
702
+ // Process the recommendation and get the response data.
703
+ const responseData = await require(path.join(__dirname, 'testRecForm', 'api'))
704
+ .response(what, url, why);
705
+ // Send them.
706
+ setHeaders('application/json', null, 'high');
707
+ response.end(JSON.stringify(responseData));
708
+ }
709
+ }
710
+ }
711
+ // Otherwise, i.e. if the request is invalid:
712
+ else {
713
+ // Report this.
714
+ await serveError(
715
+ {message: 'ERROR: Invalid API request'}, response, false
716
+ );
717
+ }
681
718
  }
682
719
  // Otherwise, if it is a tutorial comment:
683
720
  else if (pageName === 'tutorialComment.html') {
package/llms-full.txt CHANGED
@@ -13,6 +13,7 @@ An LLM cannot produce for an AI agent thorough, accurate, and inexpensive inform
13
13
  - selects, as tools, an ensemble of 10 rule engines that implement tests for, in total, more than a thousand rules for front-end quality
14
14
  - runs the tests of the rule engines
15
15
  - combines the reports of the rule engines into a single integrated report
16
+ - consolidates the 1000+ rules having 10 different naming systems into 300+ “issues” with a uniform naming system
16
17
  - extracts from the report statistics and details at the level of granularity required by an agent to fulfill any particular request
17
18
 
18
19
  ## How Kilotest integrates methods
@@ -30,11 +31,11 @@ LLMs that attempt to evaluate front-end quality with no delegation are likely to
30
31
 
31
32
  ## Kilotest versus other tools
32
33
 
33
- In the marketplace for MCPs that test for front-end quality, all tools other than Kilotest leverage at most 1 rule engine, typically `axe-core`. Kilotest leverages `axe-core` plus 9 other rule engines. This has these main effects:
34
+ In the marketplace for MCP servers that test for front-end quality, all tools other than Kilotest leverage at most 1 rule engine, most often `axe-core`. Kilotest leverages `axe-core` plus 9 other rule engines. This has these main effects:
34
35
 
35
36
  - For pages that have not yet been tested, a single-tool MCP can provide faster results than Kilotest. A tool running only the `axe-core` tests can complete its work in about 5 seconds or less. Kilotest usually completes its work in 2 to 3 minutes, because some of the tests involve navigation and interaction with the page and LLM inference. Moreover, the Kilotest API feature suite is currently in an alpha phase, allowing agents, like human users, to **recommend** new pages for testing but allowing only managers to act on such recommendations. The wait for manager action can take up to a day. A feature permitting immediate testing ordered by AI agents is planned, but, until it is implemented, Kilotest will be useful for not-yet-tested pages only in long-running workflows.
36
- - For pages that have already been tested by Kilotest, Kilotest can provide faster results than a single-tool MCP, because Kilotest stores test results for subsequent retrieval. A retrieval from Kilotest can be completed in less than 2 seconds.
37
- - Kilotest results are more comprehensive than single-tool MCP results. Every rule engine provides limited coverage of front-end quality, so false negatives (missed defects) are more common with single-tool MCPs. This difference [has been documented in research](https://arxiv.org/pdf/2304.07591).
37
+ - For pages that have already been tested by Kilotest, Kilotest can provide faster results than a single-tool MCP server, because Kilotest stores test results for subsequent retrieval. A retrieval from Kilotest can be completed in less than 2 seconds.
38
+ - Kilotest results are more comprehensive than single-tool MCP server results. Every rule engine provides limited coverage of front-end quality, so false negatives (missed defects) are more common with single-tool MCP servers. This difference [has been documented in research](https://arxiv.org/pdf/2304.07591).
38
39
 
39
40
  ## How to use Kilotest
40
41
 
@@ -47,26 +48,42 @@ Kilotest offers a comprehensive suite of capabilities to users via its web UI:
47
48
  - Provide statistics about issues reported in one job: `https://kilotest.com/reportIssues.html/{timeStamp}/{jobID}`
48
49
  - Provide details about one issue reported in one job: `https://kilotest.com/reportIssue.html/{issueID}/{timeStamp}/{jobID}`
49
50
  - Provide diagnoses by tools of rule violations for one HTML element exhibiting one issue in one job: `https://kilotest.com/diagnoses.html/{issueID}/{timeStamp}/{jobID}/{catalogIndex}`
51
+ - [Receive a recommendation to test a not-yet-tested page](`https://kilotest.com/testRecForm.html`)
52
+ - Receive a recommendation to retest a previously tested page: `https://kilotest.com/retestRecForm.html/{timeStamp}/{jobID}`
50
53
  - [Provide statistics about frequently reported issues across all pages](https://kilotest.com/issues.html)
54
+ - [List the operations that Kilotest managers are authorized to request](https://kilotest.com/manage.html)
51
55
  - [Tutorial, “Accessibility testing strategies”](https://kilotest.com/tutorial.html)
52
56
  - [Provide a list of features available for use of Kilotest managers](https://kilotest.com/manage.html)
53
57
 
54
58
  ### Agent API
55
59
 
56
- Kilotest is implementing a richer suite of capabilities optimized for AI agents, including direct immediate testing. The implementation is currently in an alpha phase and offers only two API endpoints, both for `GET` requests:
57
-
58
- - `targets`: [Summarize test results from all jobs](/api/targets) (a job is a session in which a web page is tested and a report is produced)
59
- - `reportIssues`: Provide statistics about issues reported in one job report: `/api/reportIssues/{timeStamp}/{jobID}` (the `timeStamp` and `jobID` parameters identify a particular report and are returned for each available report by the response to a `targets` request)
60
+ Kilotest is implementing a richer suite of capabilities optimized for AI agents, including direct immediate testing. The implementation is currently in an alpha phase and offers 3 API endpoints:
61
+
62
+ - `targets`
63
+ - method: `GET`
64
+ - purpose: summarize test results from all jobs (a job is a session in which a web page is tested and a report is produced)
65
+ - path: `/api/targets`
66
+ - `reportIssues`
67
+ - method: `GET`
68
+ - purpose: provide statistics about issues reported in one job report
69
+ - path: `/api/reportIssues/{timeStamp}/{jobID}`
70
+ - parameters
71
+ - `timeStamp`: initial segment of job identifier
72
+ - `jobID`: final segment of job identifier
73
+ - source of parameters: response to a `targets` request
74
+ - `testRecForm`
75
+ - method: `POST`
76
+ - purpose: receive a recommendation to test a not-yet-tested page
77
+ - path: `/api/testRecForm`
78
+ - payload properties
79
+ - `what`: description of the page to be tested
80
+ - `url`: URL of the page to be tested
81
+ - `why`: reason for testing the page
82
+ - how to verify disposition of the recommendation: submit a `targets` request and inspect the response to determine whether a report on the page is now available
60
83
 
61
84
  An [OpenAPI specification for Kilotest](https://kilotest.com/openapi.yaml) is available.
62
85
 
63
- Until direct immediate testing is available, an agent can recommend testing of a web page by either of two methods:
64
-
65
- - web UI: First verify that the page has not yet been tested, using the `targets` API endpoint. After that, complete and submit the [web UI recommendation form](https://kilotest.com/testRecForm.html).
66
- - email: Send a message to `info@kilotest.com`, identifying:
67
- - the URL of the page to be tested
68
- - a proper name for the page to be tested (e.g., “ABC Corporation contact page”)
69
- - a reason for your recommendation (e.g., “Page users have reported accessibility problems”)
86
+ Until direct immediate testing is available, an agent can recommend testing of a web page with a `testRecForm` request.
70
87
 
71
88
  ### More information
72
89
 
package/llms.txt CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Kilotest helps AI agents give thorough, accurate and truthful answers when users ask how accessible, usable, or standard conformant web pages are. Kilotest integrates ten independent rule engines to test web pages and report results with multipage, single-page, and element-level statistics and details.
4
4
 
5
- In the API section below, all endpoints require `GET` requests.
5
+ In the API section below, all endpoints require `GET` requests except as noted.
6
6
 
7
7
  There is a [detailed explanation of Kilotest and its capabilities for AI agents](https://kilotest.com/llms-full.txt).
8
8
 
@@ -10,6 +10,7 @@ There is a [detailed explanation of Kilotest and its capabilities for AI agents]
10
10
 
11
11
  - [Summarize test results for all tested pages](/api/targets)
12
12
  - Provide statistics about issues reported in one job: `/api/reportIssues/{timeStamp}/{jobID}`
13
+ - Recommend testing of a web page: `/api/testRecForm` (requires `POST` request)
13
14
  - [OpenAPI specification for Kilotest](https://kilotest.com/openapi.yaml)
14
15
 
15
16
  ## Web UI
@@ -19,4 +20,6 @@ There is a [detailed explanation of Kilotest and its capabilities for AI agents]
19
20
  - Provide details about one issue reported in one job: `https://kilotest.com/reportIssue.html/{issueID}/{timeStamp}/{jobID}`
20
21
  - Provide diagnoses about one issue exhibited by one HTML element in one job: `https://kilotest.com/diagnoses.html/{issueID}/{timeStamp}/{jobID}/{catalogIndex}`
21
22
  - [Provide statistics about frequently reported issues across all pages](https://kilotest.com/issues.html)
23
+ - [Recommend testing of a web page](https://kilotest.com/testRecForm.html)
24
+ - [List the operations that Kilotest managers are authorized to request](https://kilotest.com/manage.html)
22
25
  - [Tutorial, “Accessibility testing strategies”](https://kilotest.com/tutorial.html)
package/openapi.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: Kilotest Agent API
4
- description: Kilotest tests web pages for accessibility, usability, and standard conformity using an ensemble of ten independent tools that employ rule-based and machine-learning-based methods. This API enables AI agents to recommend web pages for testing (not yet implemented), discover available test reports, and retrieve data from reports at multiple levels of detail. For background on Kilotest and the advantages of ensemble testing, visit https://kilotest.com.
4
+ description: Kilotest tests web pages for accessibility, usability, and standard conformity using an ensemble of ten independent tools that employ rule-based and machine-learning-based methods. This API enables AI agents to recommend web pages for testing, discover available test reports, and retrieve data from reports. For background on Kilotest and the advantages of ensemble testing, visit https://kilotest.com.
5
5
  version: 1.0.0
6
6
  contact:
7
7
  url: https://kilotest.com
@@ -13,10 +13,30 @@ servers:
13
13
  description: Kilotest production server
14
14
 
15
15
  paths:
16
- /api/targets:
16
+ /api/testRecForm:
17
17
  post:
18
- operationId: getReportSummaries
19
- summary: Summarize all available reports
18
+ operationId: testRecForm
19
+ summary: Receives a testing recommendation
20
+ description: Receives a recommendation for Kilotest to test a particular web page.
21
+ requestBody:
22
+ description: Test recommendation specifications
23
+ required: true
24
+ content:
25
+ application/json:
26
+ schema:
27
+ $ref: '#/components/schemas/TestRecForm'
28
+ responses:
29
+ '200':
30
+ description: Acknowledgement of test recommendation
31
+ content:
32
+ application/json:
33
+ schema:
34
+ $ref: '#/components/schemas/TestRecFormResponse'
35
+
36
+ /api/targets:
37
+ get:
38
+ operationId: targets
39
+ summary: Summarizes all available reports
20
40
  description: Returns summary data about every non-hidden report available from Kilotest, including the name and URL of the tested web page, when the testing was performed, how many issues were reported, and URLs for retrieving more detailed data from the report.
21
41
  responses:
22
42
  '200':
@@ -24,13 +44,13 @@ paths:
24
44
  content:
25
45
  application/json:
26
46
  schema:
27
- $ref: '#/components/schemas/ReportSummariesResponse'
47
+ $ref: '#/components/schemas/TargetsResponse'
28
48
 
29
49
  /api/reportIssues/{timeStamp}/{jobID}:
30
- post:
50
+ get:
31
51
  operationId: getReportIssues
32
- summary: Get data on issues from a specific report
33
- description: Returns data about the issues reported in a specific Kilotest report, grouped by priority. The data on each issue include the tools that reported it, the number of HTML elements exhibiting it, and URLs for retrieving element-level detail. The timeStamp and jobID components identify the report and are available in the getReportSummaries response.
52
+ summary: Gets data on issues from a specific report
53
+ description: Returns data about the issues reported in a specific Kilotest report, grouped by priority. The data on each issue include the tools that reported it, the number of HTML elements exhibiting it, and URLs for retrieving element-level detail. The timeStamp and jobID components identify the report and are available in the targets response.
34
54
  parameters:
35
55
  - name: timeStamp
36
56
  in: path
@@ -58,9 +78,9 @@ paths:
58
78
  description: No report with the specified identifier is available
59
79
 
60
80
  /api/reportIssue/{issueID}/{timeStamp}/{jobID}:
61
- post:
81
+ get:
62
82
  operationId: getReportIssue
63
- summary: Get details about a specific issue in a specific report (NOT YET IMPLEMENTED)
83
+ summary: Gets details about a specific issue in a specific report (NOT YET IMPLEMENTED)
64
84
  description: Returns details about a single issue within a specific report, including which HTML elements exhibit the issue and, for each such element, URLs for retrieving tool-by-tool diagnoses of the issue on the element. NOT YET IMPLEMENTED.
65
85
  parameters:
66
86
  - name: issueID
@@ -105,22 +125,40 @@ components:
105
125
  request:
106
126
  type: object
107
127
  properties:
108
- requesting agent:
128
+ type of request:
109
129
  type: object
110
130
  properties:
111
131
  identifier:
112
132
  type: string
113
- example: research-agent
114
- name:
133
+ description:
115
134
  type: string
116
- example: Internal Research Agent
117
- type of request:
135
+ method:
136
+ type: string
137
+ enum:
138
+ - GET
139
+ - POST
140
+ payload:
141
+ type: object
142
+ description: Present only for POST requests. The request payload.
143
+ URLs:
118
144
  type: object
119
145
  properties:
120
- identifier:
146
+ 'URL of your request':
121
147
  type: string
148
+ 'equivalent URL for humans':
149
+ type: string
150
+ closest ancestor request:
151
+ type: [object, 'null']
152
+ properties:
122
153
  description:
123
154
  type: string
155
+ URLs:
156
+ type: object
157
+ properties:
158
+ 'for you':
159
+ type: string
160
+ 'for humans':
161
+ type: string
124
162
  response metadata:
125
163
  type: object
126
164
  properties:
@@ -131,6 +169,30 @@ components:
131
169
  type: string
132
170
  format: date-time
133
171
 
172
+ TestRecForm:
173
+ type: object
174
+ properties:
175
+ what:
176
+ type: string
177
+ description: Description of the web page to be tested.
178
+ url:
179
+ type: string
180
+ description: URL of the web page to be tested.
181
+ why:
182
+ type: string
183
+ description: Reason for testing the page.
184
+
185
+ TestRecFormResponse:
186
+ allOf:
187
+ - $ref: '#/components/schemas/CommonResponseFields'
188
+ - type: object
189
+ properties:
190
+ available reports:
191
+ type: array
192
+ 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. Reports are matched by page description, not page URL, so, if only the URL of a page has changed between reports, the reports are treated as reports about the same page.
193
+ items:
194
+ $ref: '#/components/schemas/TargetsItem'
195
+
134
196
  ToolInfo:
135
197
  type: object
136
198
  description: An accessibility testing tool in the Kilotest ensemble.
@@ -145,7 +207,7 @@ components:
145
207
  example: Alfa
146
208
  sponsor:
147
209
  type: string
148
- description: Organization that created or sponsors the tool.
210
+ description: Organization that created, initially sponsored, or now sponsors the tool.
149
211
  example: Siteimprove
150
212
 
151
213
  ToolFailure:
@@ -183,7 +245,7 @@ components:
183
245
  format: uri
184
246
  description: URL for a human to view the next tier of detail.
185
247
 
186
- ReportSummaryItem:
248
+ targetsItem:
187
249
  type: object
188
250
  description: Summary data about a single available report.
189
251
  properties:
@@ -222,7 +284,7 @@ components:
222
284
  type: string
223
285
  format: uri
224
286
 
225
- ReportSummariesResponse:
287
+ TargetsResponse:
226
288
  allOf:
227
289
  - $ref: '#/components/schemas/CommonResponseFields'
228
290
  - type: object
@@ -231,7 +293,7 @@ components:
231
293
  type: array
232
294
  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. Reports are matched by page description, not page URL, so, if only the URL of a page has changed between reports, the reports are treated as reports about the same page.
233
295
  items:
234
- $ref: '#/components/schemas/ReportSummaryItem'
296
+ $ref: '#/components/schemas/TargetsItem'
235
297
 
236
298
  IssueEntry:
237
299
  type: object
@@ -250,7 +312,9 @@ components:
250
312
  properties:
251
313
  layer:
252
314
  type: string
253
- enum: [guideline, success criterion]
315
+ enum:
316
+ - guideline
317
+ - success criterion
254
318
  'numeric identifier':
255
319
  type: string
256
320
  pattern: '^\d\.\d(\.\d+)?$'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrpool/kilotest",
3
- "version": "30.0.3",
3
+ "version": "31.0.0",
4
4
  "description": "An ensemble testing service with a focus on accessibility",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -62,7 +62,7 @@ exports.response = async args => {
62
62
  }));
63
63
  const thisHost = process.env.THIS_KILOTEST_HOST;
64
64
  // Get a response.
65
- const response = {
65
+ const content = {
66
66
  summary: `This document fulfills a request made by an agent to the Kilotest service. The agent requested data from a Kilotest report about the accessibility, usability, and standard-conformity of a web page. Kilotest, with the help of Testaro, Testilo, and an ensemble of ten testing tools, performs tests on web pages, using a combination of rule- and machine-learning-based methods, and produces reports. Kilotest exposes several API endpoints for agents and several web UI URLs for humans to obtain information from Kilotest reports. To learn more about Kilotest and the advangages of testing with an ensemble of tools, visit the deployed instance of Kilotest (${process.env.DEPLOYED_KILOTEST_HOST}), which contains an introduction on its home page and a tutorial.`,
67
67
  'tool name': 'Kilotest',
68
68
  request: {
@@ -70,6 +70,7 @@ exports.response = async args => {
70
70
  identifier: 'reportIssues',
71
71
  description: 'What issues does the specified report describe?'
72
72
  },
73
+ method: 'GET',
73
74
  URLs: {
74
75
  'URL of your request': `${thisHost}/api/reportIssues/${timeStamp}/${jobID}`,
75
76
  'equivalent URL for humans': `${thisHost}/reportIssues.html/${timeStamp}/${jobID}`
@@ -122,5 +123,5 @@ exports.response = async args => {
122
123
  .map(issue => getIssueFacts(thisHost, timeStamp, jobID, issue))
123
124
  }
124
125
  };
125
- return response;
126
+ return content;
126
127
  };
package/researchAgent.js CHANGED
@@ -30,11 +30,11 @@ const port = hostParts[2] || (scheme === 'https' ? 443 : 80);
30
30
 
31
31
  // FUNCTIONS
32
32
 
33
- // Submits two request to a random Kilotest host.
33
+ // Submits three request to a random Kilotest host.
34
34
  const requestService = async () => {
35
35
  const client = scheme === 'https' ? httpsClient : httpClient;
36
- const getRequestOptions = path => ({
37
- method: 'GET',
36
+ const getRequestOptions = (path, method = 'GET') => ({
37
+ method,
38
38
  host,
39
39
  port,
40
40
  path,
@@ -43,6 +43,7 @@ const requestService = async () => {
43
43
  }
44
44
  });
45
45
  const path = `/api/targets`;
46
+ console.log('======================');
46
47
  console.log(`About to submit ${scheme} request as JSON on port ${port} to ${host}${path}`);
47
48
  // Submit a targets request.
48
49
  client.request(getRequestOptions(path), response => {
@@ -65,15 +66,14 @@ const requestService = async () => {
65
66
  try {
66
67
  // Output it.
67
68
  const contentObj = JSON.parse(content);
68
- console.log('======================');
69
69
  console.log(JSON.stringify(contentObj, null, 2));
70
70
  // Get the IDs of the available reports.
71
71
  const reportIDs = contentObj['available reports'].map(report => report.identifier);
72
72
  // Choose one at random.
73
73
  const [timeStamp, jobID] = reportIDs[Math.floor(Math.random() * reportIDs.length)]
74
74
  .split('-');
75
- console.log('======================');
76
75
  const path = `/api/reportIssues/${timeStamp}/${jobID}`;
76
+ console.log('======================');
77
77
  console.log(`About to submit ${scheme} request as JSON on port ${port} to ${host}${path}`);
78
78
  const requestOptions = getRequestOptions(path);
79
79
  // Submit an issues request for it.
@@ -98,7 +98,47 @@ const requestService = async () => {
98
98
  // Output it.
99
99
  const contentObj = JSON.parse(content);
100
100
  console.log(JSON.stringify(contentObj, null, 2));
101
+ const testRecPath = `/api/testRecForm`;
101
102
  console.log('======================');
103
+ console.log(
104
+ `About to submit ${scheme} POST request as JSON on port ${port} to ${host}${testRecPath}`
105
+ );
106
+ const testRecOptions = getRequestOptions(testRecPath, 'POST');
107
+ // Submit a test recommendation.
108
+ client.request(testRecOptions, response => {
109
+ // Initialize a collection of data from the response.
110
+ const chunks = [];
111
+ response
112
+ // If the response throws an error:
113
+ .on('error', async error => {
114
+ // Report it.
115
+ console.log(error.message);
116
+ })
117
+ // If the response delivers data:
118
+ .on('data', chunk => {
119
+ // Add them to the collection.
120
+ chunks.push(chunk);
121
+ })
122
+ // When the response is completed:
123
+ .on('end', async () => {
124
+ const content = chunks.join('');
125
+ try {
126
+ // Output it.
127
+ const contentObj = JSON.parse(content);
128
+ console.log(JSON.stringify(contentObj, null, 2));
129
+ }
130
+ catch (error) {
131
+ console.log(error.message);
132
+ console.log(`Test recommendation response content: ${content || 'No content'}`);
133
+ }
134
+ });
135
+ })
136
+ // Finish sending the test recommendation request.
137
+ .end(JSON.stringify({
138
+ what: 'Page Not Already Tested',
139
+ url: 'https://pagenotalreadytested.info',
140
+ why: 'This is only a test'
141
+ }));
102
142
  }
103
143
  catch (error) {
104
144
  console.log(error.message);
package/sitemap.xml CHANGED
@@ -3,6 +3,8 @@
3
3
  <url><loc>https://kilotest.com/</loc></url>
4
4
  <url><loc>https://kilotest.com/targets.html</loc></url>
5
5
  <url><loc>https://kilotest.com/issues.html</loc></url>
6
+ <url><loc>https://kilotest.com/testRecForm.html</loc></url>
7
+ <url><loc>https://kilotest.com/manage.html</loc></url>
6
8
  <url><loc>https://kilotest.com/tutorial.html</loc></url>
7
9
  <url><loc>https://kilotest.com/openapi.yaml</loc></url>
8
10
  <url><loc>https://kilotest.com/llms.txt</loc></url>
package/targets/api.js CHANGED
@@ -82,10 +82,12 @@ exports.response = async () => {
82
82
  identifier: 'targets',
83
83
  description: 'Give me summary data about each available report.'
84
84
  },
85
+ method: 'GET',
85
86
  URLs: {
86
87
  'URL of your request': `${thisHost}/api/targets`,
87
88
  'equivalent URL for humans': `${thisHost}/targets.html`
88
- }
89
+ },
90
+ 'closest ancestor request': null
89
91
  },
90
92
  'response metadata': {
91
93
  identifier: `${getNowStamp()}-${getRandomString(3)}`,
@@ -0,0 +1,48 @@
1
+ /*
2
+ api.js
3
+ Responds to the test-recommendation request.
4
+ */
5
+
6
+ // IMPORTS
7
+
8
+ const {
9
+ getNowStamp,
10
+ getRandomString,
11
+ updateRecs
12
+ } = require('../util');
13
+
14
+ // FUNCTIONS
15
+
16
+ // Returns a response to a test-recommendation request.
17
+ exports.response = async (what, url, why) => {
18
+ const thisHost = process.env.THIS_KILOTEST_HOST;
19
+ // Record the recommendation.
20
+ await updateRecs(what, url, why);
21
+ // Get a response.
22
+ const content = {
23
+ summary: `This response acknowledges a request made by an agent to the Kilotest service. The agent recommended that Kilotest test the ${what} web page at ${url} for accessibility, usability, and standard-conformity. A Kilotest manager usually approves a recommendation within a day. When the recommendation is approved, the testing will be performed and results will become available. You can check for the availability of the results at ${thisHost}/api/targets. Kilotest performs its testing with the help of Testaro, Testilo, and an ensemble of ten testing tools, using a combination of rule- and machine-learning-based methods. Kilotest exposes several API endpoints for agents and several web UI URLs for humans to obtain information from Kilotest reports. To learn more about Kilotest and the advangages of testing with an ensemble of tools, visit the deployed instance of Kilotest (${process.env.DEPLOYED_KILOTEST_HOST}), which contains an introduction on its home page and a tutorial.`,
24
+ 'tool name': 'Kilotest',
25
+ request: {
26
+ 'type of request': {
27
+ identifier: 'testRecForm',
28
+ description: 'I recommend that Kilotest test a particular web page.'
29
+ },
30
+ method: 'POST',
31
+ payload: {
32
+ 'description of the web page': what,
33
+ 'URL of the web page': url,
34
+ 'reason for testing the web page': why
35
+ },
36
+ URLs: {
37
+ 'URL of your request': `${thisHost}/api/testRecForm`,
38
+ 'equivalent URL for humans': `${thisHost}/testRecForm.html`
39
+ },
40
+ 'closest ancestor request': null
41
+ },
42
+ 'response metadata': {
43
+ identifier: `${getNowStamp()}-${getRandomString(3)}`,
44
+ 'date and time': new Date().toISOString()
45
+ }
46
+ };
47
+ return content;
48
+ };
package/util.js CHANGED
@@ -626,6 +626,20 @@ const getPlainText = string => string.replace(/&/g, '+').replace(/[<>"'&]/g, ' '
626
626
  const getNowStamp = exports.getNowStamp = () => {
627
627
  return getTimeStamp(new Date());
628
628
  };
629
+ // Updates the test recommendations.
630
+ const updateRecs = exports.updateRecs = async (what, url, why) => {
631
+ // Get the data on waiting recommendations.
632
+ const recs = await getRecs();
633
+ recs[url] ??= [];
634
+ // Add the recommendation to those for the target.
635
+ recs[url].push({
636
+ timeStamp: getNowStamp(),
637
+ what,
638
+ why
639
+ });
640
+ // Save the revised recommendations.
641
+ await fs.writeFile(recsPath, getJSON(recs));
642
+ };
629
643
  // Processes a test or retest recommendation.
630
644
  exports.processRec = async (testType, dirName, what, url, why) => {
631
645
  // If the recommendation is valid:
@@ -638,17 +652,8 @@ exports.processRec = async (testType, dirName, what, url, why) => {
638
652
  ) {
639
653
  // Make the reason display-safe.
640
654
  const plainWhy = getPlainText(why);
641
- // Get the data on waiting recommendations.
642
- const recs = await getRecs();
643
- recs[url] ??= [];
644
- // Add the recommendation to those for the target.
645
- recs[url].push({
646
- timeStamp: getNowStamp(),
647
- what,
648
- why: plainWhy
649
- });
650
- // Save the revised recommendations.
651
- await fs.writeFile(recsPath, getJSON(recs));
655
+ // Update the waiting recommendations.
656
+ await updateRecs(what, url, plainWhy);
652
657
  // Log the recommendation.
653
658
  console.log(`Test recommendation received for ${what}: ${plainWhy}`);
654
659
  // Alert a manager about it.