@jrpool/kilotest 59.0.0 → 59.0.2
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/api/getReport.test.ts +1 -1
- package/api/listPages.test.ts +2 -2
- package/api/orderNewTest.test.ts +1 -1
- package/api/orderRetest.test.ts +1 -1
- package/api/requestNewTest.test.ts +1 -1
- package/api/requestRetest.test.ts +3 -3
- package/docs/AI-TOOLS.md +1 -1
- package/index.test.ts +1 -1
- package/index.ts +3 -2
- package/mcp.test.ts +1 -1
- package/package.json +1 -1
- package/test/fixtures/buildFixtures.ts +2 -2
- package/test/fixtures/db/reports/260101T0000-mix.json +2 -2
- package/test/fixtures/db/reports/260202T0000-new.json +2 -2
- package/util.test.ts +11 -11
- package/web/home/home.test.ts +19 -0
- package/{index.html → web/home/index.html} +1 -1
- package/web/home/index.ts +20 -0
- package/web/listDiagnoses/listDiagnoses.test.ts +1 -1
- package/web/listIssues/index.html +7 -9
- package/web/listIssues/listIssues.test.ts +6 -6
- package/web/listPages/listPages.test.ts +3 -3
- package/web/listViolators/listViolators.test.ts +1 -1
- package/web/requestNewTest/requestNewTest.test.ts +1 -1
- package/web/requestRetest/requestRetest.test.ts +1 -2
- package/web/requestRetestForm/requestRetestForm.test.ts +1 -1
- package/web/util.test.ts +2 -2
package/api/getReport.test.ts
CHANGED
|
@@ -35,7 +35,7 @@ test('getReport returns the full report for a valid report', async () => {
|
|
|
35
35
|
assert.ok((content['size of the report in bytes'] as number) > 0);
|
|
36
36
|
const report = content['full report'] as any;
|
|
37
37
|
assert.equal(report.id, '260101T0000-mix');
|
|
38
|
-
assert.equal(report.target.what, 'Mixed Outcomes
|
|
38
|
+
assert.equal(report.target.what, 'Mixed Outcomes');
|
|
39
39
|
assert.equal(report.target.url, 'https://example.com/mixed');
|
|
40
40
|
assert.equal(report.acts.length, 2);
|
|
41
41
|
});
|
package/api/listPages.test.ts
CHANGED
|
@@ -38,7 +38,7 @@ test('listPages returns one entry per tested page, sorted by page description',
|
|
|
38
38
|
'All CantTell Page',
|
|
39
39
|
'Branch Coverage Page',
|
|
40
40
|
'Empty Results Page',
|
|
41
|
-
'Mixed Outcomes
|
|
41
|
+
'Mixed Outcomes',
|
|
42
42
|
'Multi Violator Page',
|
|
43
43
|
'No Outcomes Page',
|
|
44
44
|
'Prevented Page'
|
|
@@ -56,7 +56,7 @@ test('listPages does not include the page of the hidden report', async () => {
|
|
|
56
56
|
test('listPages describes a multi-report page by its latest report and its report count', async () => {
|
|
57
57
|
const body = await response();
|
|
58
58
|
const pagesBasics = body['response content']['basics about all tested pages'];
|
|
59
|
-
const mixed = pagesBasics.find(b => b['tested web page'].description === 'Mixed Outcomes
|
|
59
|
+
const mixed = pagesBasics.find(b => b['tested web page'].description === 'Mixed Outcomes')!;
|
|
60
60
|
assert.equal(mixed['number of reports about the page'], 2);
|
|
61
61
|
const latest = mixed['basics about the latest report'];
|
|
62
62
|
assert.equal(latest.identifier, '260202T0000-new');
|
package/api/orderNewTest.test.ts
CHANGED
|
@@ -115,7 +115,7 @@ test('orderNewTest rejects a URL that redirects to a disallowed target, and aler
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
test('orderNewTest rejects an already-tested page', async () => {
|
|
118
|
-
const body = await response(['Mixed Outcomes
|
|
118
|
+
const body = await response(['Mixed Outcomes', 'https://example.com/mixed', 'A reason that is long enough.']);
|
|
119
119
|
const details = body['response content']['details about your order'] as any;
|
|
120
120
|
assert.equal(details.error, undefined);
|
|
121
121
|
const disposition = body['response content']['disposition of your order'] as any;
|
package/api/orderRetest.test.ts
CHANGED
|
@@ -87,7 +87,7 @@ test('orderRetest rejects a reason longer than 100 characters', async () => {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
test('orderRetest rejects a superseded report', async () => {
|
|
90
|
-
// 260101T0000-mix is an earlier report of "Mixed Outcomes
|
|
90
|
+
// 260101T0000-mix is an earlier report of "Mixed Outcomes" than 260202T0000-new,
|
|
91
91
|
// so it is superseded.
|
|
92
92
|
const body = await response(['260101T0000', 'mix', 'A reason that is long enough.']);
|
|
93
93
|
const details = body['response content']['details about your order'] as any;
|
|
@@ -110,7 +110,7 @@ test('requestNewTest rejects a URL that redirects to a disallowed target, and al
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
test('requestNewTest rejects an already-tested page', async () => {
|
|
113
|
-
const body = await response(['Mixed Outcomes
|
|
113
|
+
const body = await response(['Mixed Outcomes', 'https://example.com/mixed', 'A reason that is long enough.']);
|
|
114
114
|
const details = body['response content']['details about your request'] as any;
|
|
115
115
|
// A report for this description and URL already exists, so processTestRequest
|
|
116
116
|
// returns 'reportExists' and the failure is reported via the disposition, not details.error.
|
|
@@ -85,7 +85,7 @@ test('requestRetest rejects a malformed timestamp or job identifier', async () =
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
test('requestRetest rejects a superseded report', async () => {
|
|
88
|
-
// 260101T0000-mix is an earlier report of "Mixed Outcomes
|
|
88
|
+
// 260101T0000-mix is an earlier report of "Mixed Outcomes" than 260202T0000-new,
|
|
89
89
|
// so it is superseded and processTestRequest returns 'superseded', reported via the
|
|
90
90
|
// disposition rather than details.error.
|
|
91
91
|
const body = await response(['260101T0000', 'mix', 'A reason that is long enough.']);
|
|
@@ -168,10 +168,10 @@ test('requestRetest accepts a valid retest request for the latest report of a pa
|
|
|
168
168
|
const body = await response(['260202T0000', 'new', 'A reason that is long enough.']);
|
|
169
169
|
const details = body['response content']['details about your request'] as any;
|
|
170
170
|
assert.equal(details.error, undefined);
|
|
171
|
-
assert.equal(details['page to be retested'].description, 'Mixed Outcomes
|
|
171
|
+
assert.equal(details['page to be retested'].description, 'Mixed Outcomes');
|
|
172
172
|
assert.ok(logged.some(line =>
|
|
173
173
|
line.startsWith('WARNING (Kilotest: request for a retest awaits approval)')
|
|
174
|
-
&& line.includes('Mixed Outcomes
|
|
174
|
+
&& line.includes('Mixed Outcomes')
|
|
175
175
|
&& line.includes('https://example.com/mixed')
|
|
176
176
|
// The alert reports the resulting queue size, so a maintainer who has been away can
|
|
177
177
|
// see at a glance how close the queue is to full.
|
package/docs/AI-TOOLS.md
CHANGED
|
@@ -21,7 +21,7 @@ The internal features that make Kilotest a collection of tools for language mode
|
|
|
21
21
|
|
|
22
22
|
- An API, with specific functional and utility modules in the `api` directory.
|
|
23
23
|
- Tests of the functionalities of the API.
|
|
24
|
-
- A [`JSON-LD`](https://json-ld.org/) script in the `index.html` file, providing structured data about the Kilotest API.
|
|
24
|
+
- A [`JSON-LD`](https://json-ld.org/) script in the `web/home/index.html` file, providing structured data about the Kilotest API.
|
|
25
25
|
- Environment variables in the `env.example` file.
|
|
26
26
|
- An `llms.txt` file and an `llms-full.txt` file, documenting the use of Kilotest by language models, conforming to the [llms-txt](https://llmstxt.org/) specification.
|
|
27
27
|
- A generated `openapi.yaml` file, documenting the Kilotest API, conforming to the [OpenAPI specification](https://spec.openapis.org/oas/v3.1.0).
|
package/index.test.ts
CHANGED
|
@@ -471,7 +471,7 @@ test('POST /requestNewTest.html with valid data returns an HTML page', async ()
|
|
|
471
471
|
|
|
472
472
|
test('POST /requestNewTest.html with an already-tested URL returns an error', async () => {
|
|
473
473
|
const res = await formRequest('POST', '/requestNewTest.html', {
|
|
474
|
-
description: 'Mixed Outcomes
|
|
474
|
+
description: 'Mixed Outcomes',
|
|
475
475
|
url: 'https://example.com/mixed',
|
|
476
476
|
why: 'Because accessibility matters'
|
|
477
477
|
});
|
package/index.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {handleMCP, mcpPath} from './mcp.ts';
|
|
|
40
40
|
import fs from 'node:fs/promises';
|
|
41
41
|
import {handleComment as handleTutorialWebComment} from './web/tutorialWeb/index.ts';
|
|
42
42
|
import {answer as tutorialWeb} from './web/tutorialWeb/index.ts';
|
|
43
|
+
import {answer as home} from './web/home/index.ts';
|
|
43
44
|
import {answer as privacy} from './web/privacy/index.ts';
|
|
44
45
|
import {answer as tutorialAI, handleComment as handleTutorialAIComment} from './web/tutorialAI/index.ts';
|
|
45
46
|
import http, {type IncomingMessage, type ServerResponse} from 'node:http';
|
|
@@ -642,10 +643,10 @@ const handleRequest = async (request: IncomingMessage, response: ServerResponse)
|
|
|
642
643
|
else if (['/', '/index.html'].includes(pathname)) {
|
|
643
644
|
await recordPageMetric('pageViews', 'index');
|
|
644
645
|
// Get the home page.
|
|
645
|
-
const
|
|
646
|
+
const {answerPage} = await home();
|
|
646
647
|
// Serve it.
|
|
647
648
|
setHeaders('text/html', '/index.html', 'medium');
|
|
648
|
-
response.end(
|
|
649
|
+
response.end(answerPage);
|
|
649
650
|
}
|
|
650
651
|
// Otherwise, if it is for the crawler specification:
|
|
651
652
|
else if (pageName === 'robots.txt') {
|
package/mcp.test.ts
CHANGED
|
@@ -225,7 +225,7 @@ test('orderRetest handler returns content and structuredContent, and enqueues a
|
|
|
225
225
|
const {jobsPath} = await import('./util.ts');
|
|
226
226
|
const server = createMCPServer();
|
|
227
227
|
const countBefore = getToolCallCount('orderRetest');
|
|
228
|
-
// 260202T0000-new is the latest report of "Mixed Outcomes
|
|
228
|
+
// 260202T0000-new is the latest report of "Mixed Outcomes" (260101T0000-mix is an
|
|
229
229
|
// earlier, superseded report of the same page), so this order is accepted.
|
|
230
230
|
const result = await (server as any)._registeredTools.orderRetest.handler({
|
|
231
231
|
timeStamp: '260202T0000',
|
package/package.json
CHANGED
|
@@ -136,7 +136,7 @@ const main = async () => {
|
|
|
136
136
|
];
|
|
137
137
|
await writeJSON(
|
|
138
138
|
path.join(reportsDir, '260101T0000-mix.json'),
|
|
139
|
-
report('260101T0000-mix', 'Mixed Outcomes
|
|
139
|
+
report('260101T0000-mix', 'Mixed Outcomes',
|
|
140
140
|
'https://example.com/mixed', mixedActs, mixedCatalog)
|
|
141
141
|
);
|
|
142
142
|
|
|
@@ -188,7 +188,7 @@ const main = async () => {
|
|
|
188
188
|
];
|
|
189
189
|
await writeJSON(
|
|
190
190
|
path.join(reportsDir, '260202T0000-new.json'),
|
|
191
|
-
report('260202T0000-new', 'Mixed Outcomes
|
|
191
|
+
report('260202T0000-new', 'Mixed Outcomes',
|
|
192
192
|
'https://example.com/mixed', newerActs, mixedCatalog, '26-02-02T00:10')
|
|
193
193
|
);
|
|
194
194
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "260101T0000-mix",
|
|
3
|
-
"what": "Mixed Outcomes
|
|
3
|
+
"what": "Mixed Outcomes",
|
|
4
4
|
"strict": false,
|
|
5
5
|
"standard": "only",
|
|
6
6
|
"device": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"creationTimeStamp": "260101T0000",
|
|
11
11
|
"executionTimeStamp": "260101T0000",
|
|
12
12
|
"target": {
|
|
13
|
-
"what": "Mixed Outcomes
|
|
13
|
+
"what": "Mixed Outcomes",
|
|
14
14
|
"url": "https://example.com/mixed"
|
|
15
15
|
},
|
|
16
16
|
"sources": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "260202T0000-new",
|
|
3
|
-
"what": "Mixed Outcomes
|
|
3
|
+
"what": "Mixed Outcomes",
|
|
4
4
|
"strict": false,
|
|
5
5
|
"standard": "only",
|
|
6
6
|
"device": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"creationTimeStamp": "260202T0000",
|
|
11
11
|
"executionTimeStamp": "260202T0000",
|
|
12
12
|
"target": {
|
|
13
|
-
"what": "Mixed Outcomes
|
|
13
|
+
"what": "Mixed Outcomes",
|
|
14
14
|
"url": "https://example.com/mixed"
|
|
15
15
|
},
|
|
16
16
|
"sources": {
|
package/util.test.ts
CHANGED
|
@@ -769,14 +769,14 @@ test('processTestRequest returns a duplicate error for a repeated request', {tim
|
|
|
769
769
|
test('processTestRequest returns a reportExists error when a report already exists for the page', async () => {
|
|
770
770
|
// The fixture database already has a report for this description and URL.
|
|
771
771
|
const {result} = await processTestRequest(
|
|
772
|
-
'because accessibility', {description: 'Mixed Outcomes
|
|
772
|
+
'because accessibility', {description: 'Mixed Outcomes', url: 'https://example.com/mixed'}
|
|
773
773
|
);
|
|
774
774
|
assert.equal(result, 'reportExists');
|
|
775
775
|
});
|
|
776
776
|
|
|
777
777
|
test('processTestRequest returns a reportExists error when a report exists about a page with the same description', async () => {
|
|
778
778
|
const {result} = await processTestRequest(
|
|
779
|
-
'because accessibility', {description: 'Mixed Outcomes
|
|
779
|
+
'because accessibility', {description: 'Mixed Outcomes', url: 'https://example.com/drifted'}
|
|
780
780
|
);
|
|
781
781
|
assert.equal(result, 'reportExists');
|
|
782
782
|
});
|
|
@@ -908,7 +908,7 @@ test('annotateReportObject handles a test act with no standardResult', async ()
|
|
|
908
908
|
});
|
|
909
909
|
|
|
910
910
|
test('isReportAvailable returns true for a known page description', async () => {
|
|
911
|
-
const result = await isReportAvailable('Mixed Outcomes
|
|
911
|
+
const result = await isReportAvailable('Mixed Outcomes', 'https://example.com/nonexistent');
|
|
912
912
|
assert.equal(result, true);
|
|
913
913
|
});
|
|
914
914
|
|
|
@@ -1435,7 +1435,7 @@ test('getReportExtract returns an extract for a valid report', async () => {
|
|
|
1435
1435
|
const extract = await getReportExtract('260101T0000', 'mix') as any;
|
|
1436
1436
|
assert.equal(extract.timeStamp, '260101T0000');
|
|
1437
1437
|
assert.equal(extract.jobID, 'mix');
|
|
1438
|
-
assert.equal(extract.description, 'Mixed Outcomes
|
|
1438
|
+
assert.equal(extract.description, 'Mixed Outcomes');
|
|
1439
1439
|
assert.equal(extract.url, 'https://example.com/mixed');
|
|
1440
1440
|
assert.ok(extract.reportTime);
|
|
1441
1441
|
});
|
|
@@ -1455,7 +1455,7 @@ test('getReportExtracts returns extracts of all available reports', async () =>
|
|
|
1455
1455
|
|
|
1456
1456
|
test('getReportExtracts with onlyLatest returns only the latest report for each page', async () => {
|
|
1457
1457
|
const latest = await getReportExtracts(true);
|
|
1458
|
-
const mixReports = latest.filter(e => e.description === 'Mixed Outcomes
|
|
1458
|
+
const mixReports = latest.filter(e => e.description === 'Mixed Outcomes');
|
|
1459
1459
|
assert.equal(mixReports.length, 1);
|
|
1460
1460
|
assert.equal(mixReports[0]!.timeStamp, '260202T0000');
|
|
1461
1461
|
});
|
|
@@ -1473,7 +1473,7 @@ test('getReportExtracts reflects reports added, modified, and removed after a pr
|
|
|
1473
1473
|
const firstPath = path.join(tmpReportsDir, '260101T0000-aaa.json');
|
|
1474
1474
|
await fs.writeFile(firstPath, JSON.stringify(report));
|
|
1475
1475
|
let extracts = await getReportExtracts();
|
|
1476
|
-
assert.deepEqual(extracts.map(e => e.description), ['Mixed Outcomes
|
|
1476
|
+
assert.deepEqual(extracts.map(e => e.description), ['Mixed Outcomes']);
|
|
1477
1477
|
// Modify the report and give it a later modification time, as reannotation would.
|
|
1478
1478
|
report.target.what = 'Revised Page';
|
|
1479
1479
|
await fs.writeFile(firstPath, JSON.stringify(report));
|
|
@@ -1768,14 +1768,14 @@ test('orderJob enqueues a new-page order directly into the job queue', async ()
|
|
|
1768
1768
|
|
|
1769
1769
|
test('orderJob returns a reportExists error when a report already exists for the ordered page', async () => {
|
|
1770
1770
|
const {result} = await orderJob(
|
|
1771
|
-
{description: 'Mixed Outcomes
|
|
1771
|
+
{description: 'Mixed Outcomes', url: 'https://example.com/mixed'}, 'because accessibility matters here'
|
|
1772
1772
|
);
|
|
1773
1773
|
assert.equal(result, 'reportExists');
|
|
1774
1774
|
});
|
|
1775
1775
|
|
|
1776
1776
|
test('orderJob returns a reportExists error when a report exists about a page with the same description', async () => {
|
|
1777
1777
|
const {result} = await orderJob(
|
|
1778
|
-
{description: 'Mixed Outcomes
|
|
1778
|
+
{description: 'Mixed Outcomes', url: 'https://example.com/drifted'}, 'because accessibility matters here'
|
|
1779
1779
|
);
|
|
1780
1780
|
assert.equal(result, 'reportExists');
|
|
1781
1781
|
});
|
|
@@ -1841,7 +1841,7 @@ test('orderJob returns "nonreport" when a retest order cites a report that does
|
|
|
1841
1841
|
});
|
|
1842
1842
|
|
|
1843
1843
|
test('orderJob returns "superseded" when a retest order cites a superseded report', async () => {
|
|
1844
|
-
// 260101T0000-mix is an earlier report of "Mixed Outcomes
|
|
1844
|
+
// 260101T0000-mix is an earlier report of "Mixed Outcomes" than 260202T0000-new,
|
|
1845
1845
|
// so it is superseded.
|
|
1846
1846
|
const {result} = await orderJob(
|
|
1847
1847
|
{timeStamp: '260101T0000', jobID: 'mix'}, 'because accessibility matters here'
|
|
@@ -1854,12 +1854,12 @@ test('orderJob enqueues a retest order for the latest report of a page', async (
|
|
|
1854
1854
|
{timeStamp: '260202T0000', jobID: 'new'}, 'because accessibility matters here'
|
|
1855
1855
|
) as any;
|
|
1856
1856
|
assert.equal(result, 'ok');
|
|
1857
|
-
assert.equal(description, 'Mixed Outcomes
|
|
1857
|
+
assert.equal(description, 'Mixed Outcomes');
|
|
1858
1858
|
assert.equal(url, 'https://example.com/mixed');
|
|
1859
1859
|
const queuedPath = path.join(jobsPath(), 'queue', `${jobID}.json`);
|
|
1860
1860
|
try {
|
|
1861
1861
|
const job = JSON.parse(await fs.readFile(queuedPath, 'utf8'));
|
|
1862
|
-
assert.equal(job.target.what, 'Mixed Outcomes
|
|
1862
|
+
assert.equal(job.target.what, 'Mixed Outcomes');
|
|
1863
1863
|
}
|
|
1864
1864
|
finally {
|
|
1865
1865
|
await fs.unlink(queuedPath);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
home.test.ts
|
|
3
|
+
Unit tests for web/home/index.ts, covering the answer export.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
import {test} from 'node:test';
|
|
9
|
+
import assert from 'node:assert/strict';
|
|
10
|
+
import {answer} from './index.ts';
|
|
11
|
+
|
|
12
|
+
// TESTS
|
|
13
|
+
|
|
14
|
+
test('answer returns the home page', async () => {
|
|
15
|
+
const result = await answer();
|
|
16
|
+
assert.equal(result.status, 'ok');
|
|
17
|
+
assert.ok(result.answerPage.includes('<h1>Kilotest</h1>'));
|
|
18
|
+
assert.ok(result.answerPage.includes('application/ld+json'));
|
|
19
|
+
});
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
<li><a href="listPages.html">Which web pages have been tested?</a></li>
|
|
91
91
|
<li><a href="listTopIssues.html">Which issues have been reported?</a></li>
|
|
92
92
|
<li><a href="manage.html">What can Kilotest managers do?</a></li>
|
|
93
|
-
<li><a href="privacy.html">
|
|
93
|
+
<li><a href="privacy.html">Privacy policy</a></li>
|
|
94
94
|
</ul>
|
|
95
95
|
</main>
|
|
96
96
|
</body>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
index.ts
|
|
3
|
+
Serves the home page.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
|
|
11
|
+
// FUNCTIONS
|
|
12
|
+
|
|
13
|
+
// Returns the home page.
|
|
14
|
+
export const answer = async () => {
|
|
15
|
+
const answerPage = await fs.readFile(path.join(import.meta.dirname, 'index.html'), 'utf8');
|
|
16
|
+
return {
|
|
17
|
+
status: 'ok',
|
|
18
|
+
answerPage
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -200,7 +200,7 @@ test('listDiagnoses returns an error for an unknown issue with a valid report',
|
|
|
200
200
|
|
|
201
201
|
test('listDiagnoses returns an error when report facts are not obtained', async () => {
|
|
202
202
|
pageDataStringsOverride = {
|
|
203
|
-
what: 'Mixed Outcomes
|
|
203
|
+
what: 'Mixed Outcomes',
|
|
204
204
|
url: 'https://example.com/mixed',
|
|
205
205
|
urlLink: '<a href="https://example.com/mixed">https://example.com/mixed</a>'
|
|
206
206
|
};
|
|
@@ -15,15 +15,6 @@
|
|
|
15
15
|
<h1><a href="/">Kilotest</a>: Issues reported for __target__</h1>
|
|
16
16
|
|
|
17
17
|
<h2>About the tests</h2>
|
|
18
|
-
<details>
|
|
19
|
-
<summary>How to deal with the issues</summary>
|
|
20
|
-
<h3>Do it yourself</h3>
|
|
21
|
-
<p>Explore the issues below in as much detail as you want. Decide which ones are actual defects. Plan and implement corrections.</p>
|
|
22
|
-
<h3>Or use AI</h3>
|
|
23
|
-
<p>Make Kilotest available to your AI assistant. There are <a href="/tutorialAI.html">step-by-step instructions</a> for this.</p>
|
|
24
|
-
<p>After that, you can ask:</p>
|
|
25
|
-
<blockquote>Kilotest reports defects on the __target__ web page. Summarize them and propose a plan to resolve the genuine ones.</blockquote>
|
|
26
|
-
</details>
|
|
27
18
|
__pageFacts__
|
|
28
19
|
<h2>History</h2>
|
|
29
20
|
__history__
|
|
@@ -52,6 +43,13 @@ __history__
|
|
|
52
43
|
__lowestDetails__
|
|
53
44
|
</ul>
|
|
54
45
|
</details>
|
|
46
|
+
<h2>What you can do</h2>
|
|
47
|
+
<p><strong>Choose how</strong> to address these issues:</p>
|
|
48
|
+
<h3>Do it yourself</h3>
|
|
49
|
+
<p>Explore the issues, following the links above. Decide which issues are actual defects. Plan and implement corrections. Then retest the page.</p>
|
|
50
|
+
<h3>Use artificial intelligence</h3>
|
|
51
|
+
<p><a href="/tutorialAI.html">Make Kilotest available to an AI assistant</a>. Then give it a prompt like this:</p>
|
|
52
|
+
<blockquote><q>Kilotest reports issues on the __target__ web page. Describe them and propose a plan to resolve the genuine defects.</q></blockquote>
|
|
55
53
|
</main>
|
|
56
54
|
</body>
|
|
57
55
|
</html>
|
|
@@ -58,17 +58,17 @@ test('listIssues returns an ok status with valid HTML for the mixed report', asy
|
|
|
58
58
|
|
|
59
59
|
test('listIssues includes the page description in the HTML for the mixed report', async () => {
|
|
60
60
|
const result = await answer('260101T0000/mix');
|
|
61
|
-
assert.ok(result.answerPage.includes('Mixed Outcomes
|
|
61
|
+
assert.ok(result.answerPage.includes('Mixed Outcomes'));
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
test('listIssues interpolates the page description into the AI prompt block quote', async () => {
|
|
65
65
|
const result = await answer('260101T0000/mix');
|
|
66
66
|
const html = parse(result.answerPage);
|
|
67
|
-
const blockQuote = html.querySelector('
|
|
67
|
+
const blockQuote = html.querySelector('blockquote');
|
|
68
68
|
assert.ok(blockQuote);
|
|
69
|
-
assert.ok(
|
|
70
|
-
|
|
71
|
-
);
|
|
69
|
+
assert.ok(blockQuote.textContent.startsWith(
|
|
70
|
+
'Kilotest reports issues on the Mixed Outcomes web page.'
|
|
71
|
+
));
|
|
72
72
|
// No placeholder may remain uninterpolated.
|
|
73
73
|
assert.ok(!blockQuote.textContent.includes('__target__'));
|
|
74
74
|
});
|
|
@@ -153,7 +153,7 @@ test('listIssues returns an error when getPageDataStrings fails after getReport
|
|
|
153
153
|
|
|
154
154
|
test('listIssues returns an error when report facts are not obtained', async () => {
|
|
155
155
|
pageDataStringsOverride = {
|
|
156
|
-
what: 'Mixed Outcomes
|
|
156
|
+
what: 'Mixed Outcomes',
|
|
157
157
|
url: 'https://example.com/mixed',
|
|
158
158
|
urlLink: '<a href="https://example.com/mixed">https://example.com/mixed</a>'
|
|
159
159
|
};
|
|
@@ -58,7 +58,7 @@ test('listPages lists each of the 7 tested pages once, by description', async ()
|
|
|
58
58
|
'All CantTell Page',
|
|
59
59
|
'Branch Coverage Page',
|
|
60
60
|
'Empty Results Page',
|
|
61
|
-
'Mixed Outcomes
|
|
61
|
+
'Mixed Outcomes',
|
|
62
62
|
'Multi Violator Page',
|
|
63
63
|
'No Outcomes Page',
|
|
64
64
|
'Prevented Page'
|
|
@@ -75,7 +75,7 @@ test('listPages introduces the list of tested pages', async () => {
|
|
|
75
75
|
test('listPages links each page to the issues in its latest report', async () => {
|
|
76
76
|
const result: any = await answer();
|
|
77
77
|
const links = getPageLinks(result.answerPage);
|
|
78
|
-
const mixedLink = links.find(a => a.text === 'Mixed Outcomes
|
|
78
|
+
const mixedLink = links.find(a => a.text === 'Mixed Outcomes');
|
|
79
79
|
assert.equal(mixedLink?.getAttribute('href'), 'listIssues.html/260202T0000/new');
|
|
80
80
|
const canttellLink = links.find(a => a.text === 'All CantTell Page');
|
|
81
81
|
assert.equal(canttellLink?.getAttribute('href'), 'listIssues.html/260101T0001/ct');
|
|
@@ -107,7 +107,7 @@ test('listPages shows requests when testRequests.json has entries', {timeout: 50
|
|
|
107
107
|
try {
|
|
108
108
|
const testRequests = {
|
|
109
109
|
'https://example.com/mixed': [
|
|
110
|
-
{description: 'Mixed Outcomes
|
|
110
|
+
{description: 'Mixed Outcomes', reason: 'Needs retesting for accessibility'}
|
|
111
111
|
]
|
|
112
112
|
};
|
|
113
113
|
await fs.writeFile(testRequestsPath, JSON.stringify(testRequests, null, 2));
|
|
@@ -188,7 +188,7 @@ test('listViolators includes take-me-there links for text-linkable violators', a
|
|
|
188
188
|
|
|
189
189
|
test('listViolators returns an error when report facts are not obtained', async () => {
|
|
190
190
|
pageDataStringsOverride = {
|
|
191
|
-
what: 'Mixed Outcomes
|
|
191
|
+
what: 'Mixed Outcomes',
|
|
192
192
|
url: 'https://example.com/mixed',
|
|
193
193
|
urlLink: '<a href="https://example.com/mixed">https://example.com/mixed</a>'
|
|
194
194
|
};
|
|
@@ -123,7 +123,7 @@ test('answer returns an error when a report already exists for the page', {timeo
|
|
|
123
123
|
const {answer} = await import('./index.ts');
|
|
124
124
|
// The fixture database already has a report for this description and URL.
|
|
125
125
|
const result: any = await answer(
|
|
126
|
-
'Mixed Outcomes
|
|
126
|
+
'Mixed Outcomes', 'https://example.com/mixed', 'Because accessibility'
|
|
127
127
|
);
|
|
128
128
|
assert.equal(result.status, 'error');
|
|
129
129
|
assert.equal(result.message, 'A report about a page with the same description or URL is already available');
|
|
@@ -102,7 +102,7 @@ test('answer returns an error for a duplicate retest request', async () => {
|
|
|
102
102
|
|
|
103
103
|
test('answer returns an error when the cited report has been superseded', async () => {
|
|
104
104
|
const {answer} = await import('./index.ts');
|
|
105
|
-
// 260101T0000-mix (Mixed Outcomes
|
|
105
|
+
// 260101T0000-mix (Mixed Outcomes) is superseded by 260202T0000-new.
|
|
106
106
|
const result: any = await answer('260101T0000/mix', 'Because changes were made');
|
|
107
107
|
assert.equal(result.status, 'error');
|
|
108
108
|
assert.equal(result.message, 'A later report about the page is already available');
|
|
@@ -141,4 +141,3 @@ test('answer returns an error with a fallback channel when the request queue is
|
|
|
141
141
|
assert.ok(result.message.includes('https://github.com/jrpool/kilotest/issues'));
|
|
142
142
|
assert.ok(result.message.includes('info@kilotest.com'));
|
|
143
143
|
});
|
|
144
|
-
|
|
@@ -35,7 +35,7 @@ test('requestRetestForm returns ok with the page name for a valid report', async
|
|
|
35
35
|
assert.ok(result.answerPage);
|
|
36
36
|
const html = parse(result.answerPage);
|
|
37
37
|
const title = html.querySelector('title')?.text;
|
|
38
|
-
assert.ok(title?.includes('Mixed Outcomes
|
|
38
|
+
assert.ok(title?.includes('Mixed Outcomes'));
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
test('requestRetestForm populates the form action with the timeStamp and jobID', async () => {
|
package/web/util.test.ts
CHANGED
|
@@ -129,7 +129,7 @@ const getFixtureReport = async (timeStamp: string, jobID: string) => {
|
|
|
129
129
|
|
|
130
130
|
test('getPageData returns page data for a valid report', async () => {
|
|
131
131
|
const data = getPageData(await getFixtureReport('260101T0000', 'mix'));
|
|
132
|
-
assert.equal(data.description, 'Mixed Outcomes
|
|
132
|
+
assert.equal(data.description, 'Mixed Outcomes');
|
|
133
133
|
assert.equal(data.url, 'https://example.com/mixed');
|
|
134
134
|
assert.equal(typeof data.daysAgo, 'number');
|
|
135
135
|
});
|
|
@@ -141,7 +141,7 @@ test('getReport returns an error for a nonexistent report', async () => {
|
|
|
141
141
|
|
|
142
142
|
test('getPageDataStrings returns HTML strings for a valid report', async () => {
|
|
143
143
|
const strings = getPageDataStrings(await getFixtureReport('260101T0000', 'mix'));
|
|
144
|
-
assert.equal(strings.description, 'Mixed Outcomes
|
|
144
|
+
assert.equal(strings.description, 'Mixed Outcomes');
|
|
145
145
|
assert.equal(strings.url, 'https://example.com/mixed');
|
|
146
146
|
assert.equal(strings.urlLink, '<a href="https://example.com/mixed">https://example.com/mixed</a>');
|
|
147
147
|
assert.ok(strings.testInfo.includes('by job <code>260101T0000-mix</code>'));
|