@jrpool/kilotest 60.1.3 → 60.1.5
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/lhm.plugin.json +1 -1
- package/logo.svg +1 -1
- package/openapi-3.0.yaml +1 -1
- package/openapi.yaml +1 -1
- package/package.json +1 -1
- package/server.json +1 -1
- package/style.css +76 -47
- package/web/home/index.html +5 -2
- package/web/listPages/index.html +10 -18
- package/web/listPages/index.ts +35 -15
package/lhm.plugin.json
CHANGED
package/logo.svg
CHANGED
package/openapi-3.0.yaml
CHANGED
|
@@ -2,7 +2,7 @@ openapi: 3.0.3
|
|
|
2
2
|
info:
|
|
3
3
|
title: Kilotest API
|
|
4
4
|
description: 'Kilotest is an ensemble testing and reporting service for front-end web quality. It uses an ensemble of 12 rule engines to test web pages for front-end quality (accessibility, usability, and web standards, including HTML, CSS, ARIA, and WCAG). Kilotest acts as a web server for human users, an MCP server for AI platforms, and an API for programmatic access. With this API you can request that a page be tested or retested, discover available reports, incrementally retrieve facts from a report: from what reports are available, to what issues were reported in one report, to what elements violated one issue, to what diagnoses rule engines gave for one violation.'
|
|
5
|
-
version: 60.1.
|
|
5
|
+
version: 60.1.5
|
|
6
6
|
license:
|
|
7
7
|
name: MIT
|
|
8
8
|
url: https://github.com/jrpool/kilotest/blob/main/LICENSE
|
package/openapi.yaml
CHANGED
|
@@ -2,7 +2,7 @@ openapi: 3.1.0
|
|
|
2
2
|
info:
|
|
3
3
|
title: Kilotest API
|
|
4
4
|
description: 'Kilotest is an ensemble testing and reporting service for front-end web quality. It uses an ensemble of 12 rule engines to test web pages for front-end quality (accessibility, usability, and web standards, including HTML, CSS, ARIA, and WCAG). Kilotest acts as a web server for human users, an MCP server for AI platforms, and an API for programmatic access. With this API you can request that a page be tested or retested, discover available reports, incrementally retrieve facts from a report: from what reports are available, to what issues were reported in one report, to what elements violated one issue, to what diagnoses rule engines gave for one violation.'
|
|
5
|
-
version: 60.1.
|
|
5
|
+
version: 60.1.5
|
|
6
6
|
license:
|
|
7
7
|
name: MIT
|
|
8
8
|
identifier: MIT
|
package/package.json
CHANGED
package/server.json
CHANGED
package/style.css
CHANGED
|
@@ -208,10 +208,10 @@ ul.xPathList li {
|
|
|
208
208
|
padding-left: 0;
|
|
209
209
|
overflow-wrap: break-word;
|
|
210
210
|
}
|
|
211
|
-
body.
|
|
211
|
+
body.styled {
|
|
212
212
|
--ink: #18212b;
|
|
213
|
-
--muted: #
|
|
214
|
-
--accent: #
|
|
213
|
+
--muted: #424e59;
|
|
214
|
+
--accent: #005c5c;
|
|
215
215
|
--accent-dark: #064f4f;
|
|
216
216
|
--bg: #f6f8f8;
|
|
217
217
|
--card: #fff;
|
|
@@ -224,36 +224,37 @@ body.home {
|
|
|
224
224
|
color: var(--ink);
|
|
225
225
|
background: var(--bg);
|
|
226
226
|
}
|
|
227
|
-
body.
|
|
227
|
+
body.styled, body.styled *, body.styled *::before, body.styled *::after {
|
|
228
228
|
box-sizing: border-box;
|
|
229
229
|
}
|
|
230
|
-
body.
|
|
230
|
+
body.styled a {
|
|
231
231
|
color: var(--accent);
|
|
232
232
|
text-underline-offset: 0.15em;
|
|
233
233
|
}
|
|
234
|
-
body.
|
|
234
|
+
body.styled a:hover {
|
|
235
235
|
color: var(--accent-dark);
|
|
236
236
|
background-color: transparent;
|
|
237
237
|
}
|
|
238
|
-
body.
|
|
238
|
+
body.styled a:focus-visible, body.styled summary:focus-visible {
|
|
239
239
|
outline: 3px solid var(--focus);
|
|
240
240
|
outline-offset: 2px;
|
|
241
241
|
border-radius: 4px;
|
|
242
242
|
}
|
|
243
|
-
body.
|
|
243
|
+
body.styled h2 {
|
|
244
244
|
color: var(--ink);
|
|
245
|
+
font-size: 1.4rem;
|
|
245
246
|
}
|
|
246
|
-
body.
|
|
247
|
+
body.styled li, body.styled p {
|
|
247
248
|
line-height: 1.6;
|
|
248
249
|
}
|
|
249
|
-
body.
|
|
250
|
+
body.styled p {
|
|
250
251
|
margin: 0.6rem 0;
|
|
251
252
|
}
|
|
252
|
-
body.
|
|
253
|
+
body.styled header {
|
|
253
254
|
background: var(--card);
|
|
254
255
|
border-bottom: 1px solid var(--line);
|
|
255
256
|
}
|
|
256
|
-
body.
|
|
257
|
+
body.styled .header-inner {
|
|
257
258
|
max-width: 64rem;
|
|
258
259
|
margin-inline: auto;
|
|
259
260
|
padding: 1.1rem 1.5rem;
|
|
@@ -261,35 +262,42 @@ body.home .header-inner {
|
|
|
261
262
|
align-items: baseline;
|
|
262
263
|
gap: 0.75rem;
|
|
263
264
|
}
|
|
264
|
-
body.
|
|
265
|
-
display: inline-flex;
|
|
266
|
-
align-items: center;
|
|
267
|
-
gap: 0.55rem;
|
|
265
|
+
body.styled .brand {
|
|
268
266
|
font-weight: 800;
|
|
269
267
|
font-size: 1.25rem;
|
|
270
268
|
letter-spacing: -0.02em;
|
|
271
269
|
}
|
|
272
|
-
body.
|
|
270
|
+
body.styled a.brand {
|
|
271
|
+
color: var(--accent);
|
|
272
|
+
text-decoration: none;
|
|
273
|
+
}
|
|
274
|
+
body.styled a.brand .brand-name {
|
|
275
|
+
text-decoration: underline;
|
|
276
|
+
text-underline-offset: 0.15em;
|
|
277
|
+
}
|
|
278
|
+
body.styled .brand svg {
|
|
273
279
|
width: 1.35rem;
|
|
274
280
|
height: 1.35rem;
|
|
281
|
+
margin-right: 0.55rem;
|
|
282
|
+
vertical-align: -0.2em;
|
|
275
283
|
}
|
|
276
|
-
body.
|
|
284
|
+
body.styled .brand-tag {
|
|
277
285
|
font-size: 0.85rem;
|
|
278
286
|
color: var(--muted);
|
|
279
287
|
}
|
|
280
|
-
body.
|
|
288
|
+
body.styled .hero {
|
|
281
289
|
max-width: 64rem;
|
|
282
290
|
margin-inline: auto;
|
|
283
291
|
padding: 4rem 1.5rem 0;
|
|
284
292
|
}
|
|
285
|
-
body.
|
|
293
|
+
body.styled .eyebrow {
|
|
286
294
|
margin: 0 0 0.75rem;
|
|
287
295
|
font-size: 0.85rem;
|
|
288
296
|
font-weight: 700;
|
|
289
297
|
letter-spacing: 0.04em;
|
|
290
298
|
color: var(--accent);
|
|
291
299
|
}
|
|
292
|
-
body.
|
|
300
|
+
body.styled .eyebrow::before {
|
|
293
301
|
content: "";
|
|
294
302
|
display: inline-block;
|
|
295
303
|
width: 1.4rem;
|
|
@@ -297,20 +305,19 @@ body.home .eyebrow::before {
|
|
|
297
305
|
margin: 0 0.5rem 0.22rem 0;
|
|
298
306
|
background: var(--accent);
|
|
299
307
|
}
|
|
300
|
-
body.
|
|
308
|
+
body.styled .hero h1 {
|
|
301
309
|
margin: 0 0 1rem;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
line-height: 1.12;
|
|
310
|
+
font-size: clamp(2rem, 4.5vw, 2.6rem);
|
|
311
|
+
line-height: 1.5;
|
|
305
312
|
letter-spacing: -0.03em;
|
|
306
313
|
}
|
|
307
|
-
body.
|
|
314
|
+
body.styled .hero .lede {
|
|
308
315
|
margin: 0 0 1.75rem;
|
|
309
316
|
max-width: 52ch;
|
|
310
317
|
font-size: 1.2rem;
|
|
311
318
|
color: var(--muted);
|
|
312
319
|
}
|
|
313
|
-
body.
|
|
320
|
+
body.styled details {
|
|
314
321
|
max-width: 52rem;
|
|
315
322
|
margin: 0 0 1rem;
|
|
316
323
|
padding: 0;
|
|
@@ -318,45 +325,43 @@ body.home details {
|
|
|
318
325
|
border: 1px solid var(--line);
|
|
319
326
|
border-radius: 0.75rem;
|
|
320
327
|
}
|
|
321
|
-
body.
|
|
328
|
+
body.styled summary {
|
|
322
329
|
min-height: 44px;
|
|
323
330
|
padding: 0.9rem 1.25rem;
|
|
324
331
|
font-weight: 600;
|
|
325
332
|
cursor: pointer;
|
|
326
333
|
}
|
|
327
|
-
body.
|
|
334
|
+
body.styled summary:hover {
|
|
328
335
|
background: #eef3f3;
|
|
329
336
|
border-radius: 0.75rem;
|
|
330
337
|
}
|
|
331
|
-
body.
|
|
338
|
+
body.styled details[open] summary {
|
|
332
339
|
border-bottom: 1px solid var(--line);
|
|
333
340
|
border-radius: 0.75rem 0.75rem 0 0;
|
|
334
341
|
}
|
|
335
|
-
body.
|
|
336
|
-
|
|
342
|
+
body.styled details > :not(summary) {
|
|
343
|
+
padding-inline: 1.25rem;
|
|
337
344
|
}
|
|
338
|
-
body.
|
|
345
|
+
body.styled details h2 {
|
|
339
346
|
margin: 1.5rem 0 0.5rem;
|
|
340
|
-
font-size: 1.3rem;
|
|
341
347
|
}
|
|
342
|
-
body.
|
|
348
|
+
body.styled details h3 {
|
|
343
349
|
margin: 1.35rem 0 0.35rem;
|
|
344
350
|
font-size: 1.08rem;
|
|
345
351
|
}
|
|
346
|
-
body.
|
|
352
|
+
body.styled .nav-section {
|
|
347
353
|
max-width: 64rem;
|
|
348
354
|
margin-inline: auto;
|
|
349
355
|
padding: 2.25rem 1.5rem 0;
|
|
350
356
|
}
|
|
351
|
-
body.
|
|
357
|
+
body.styled .nav-section:last-child {
|
|
352
358
|
padding-bottom: 5rem;
|
|
353
359
|
}
|
|
354
|
-
body.
|
|
360
|
+
body.styled .nav-section h2 {
|
|
355
361
|
margin: 0 0 1.25rem;
|
|
356
|
-
font-size: 1.4rem;
|
|
357
362
|
letter-spacing: -0.01em;
|
|
358
363
|
}
|
|
359
|
-
body.
|
|
364
|
+
body.styled ul.nav {
|
|
360
365
|
margin: 0;
|
|
361
366
|
padding: 0;
|
|
362
367
|
list-style: none;
|
|
@@ -364,7 +369,7 @@ body.home ul.nav {
|
|
|
364
369
|
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
|
|
365
370
|
gap: 1rem;
|
|
366
371
|
}
|
|
367
|
-
body.
|
|
372
|
+
body.styled ul.nav a {
|
|
368
373
|
display: block;
|
|
369
374
|
min-height: 44px;
|
|
370
375
|
height: 100%;
|
|
@@ -375,11 +380,11 @@ body.home ul.nav a {
|
|
|
375
380
|
text-decoration: none;
|
|
376
381
|
transition: background-color 0.12s ease-out, border-color 0.12s ease-out;
|
|
377
382
|
}
|
|
378
|
-
body.
|
|
383
|
+
body.styled ul.nav a:hover {
|
|
379
384
|
background: #eef4f4;
|
|
380
385
|
border-color: var(--accent);
|
|
381
386
|
}
|
|
382
|
-
body.
|
|
387
|
+
body.styled .card-title {
|
|
383
388
|
font-weight: 700;
|
|
384
389
|
font-size: 1.05rem;
|
|
385
390
|
color: var(--accent);
|
|
@@ -387,23 +392,47 @@ body.home .card-title {
|
|
|
387
392
|
text-decoration-thickness: 0.09em;
|
|
388
393
|
text-underline-offset: 0.2em;
|
|
389
394
|
}
|
|
390
|
-
body.
|
|
395
|
+
body.styled .card-title::after {
|
|
391
396
|
content: "\00a0→";
|
|
392
397
|
display: inline-block;
|
|
393
398
|
text-decoration: none;
|
|
394
399
|
font-weight: 700;
|
|
395
400
|
}
|
|
396
|
-
body.
|
|
401
|
+
body.styled ul.nav a:hover .card-title {
|
|
397
402
|
text-decoration-thickness: 0.18em;
|
|
398
403
|
}
|
|
399
|
-
body.
|
|
404
|
+
body.styled .card-desc {
|
|
400
405
|
display: block;
|
|
401
406
|
margin: 0.4rem 0 0;
|
|
402
407
|
font-size: 0.9rem;
|
|
403
408
|
color: var(--muted);
|
|
404
409
|
}
|
|
405
410
|
@media (prefers-reduced-motion: reduce) {
|
|
406
|
-
body.
|
|
411
|
+
body.styled ul.nav a {
|
|
407
412
|
transition: none;
|
|
408
413
|
}
|
|
409
414
|
}
|
|
415
|
+
body.styled .page {
|
|
416
|
+
max-width: 64rem;
|
|
417
|
+
margin-inline: auto;
|
|
418
|
+
padding: 2.5rem 1.5rem 3.5rem;
|
|
419
|
+
}
|
|
420
|
+
body.styled .page h1 {
|
|
421
|
+
margin: 0 0 1.5rem;
|
|
422
|
+
font-size: 2rem;
|
|
423
|
+
letter-spacing: -0.02em;
|
|
424
|
+
}
|
|
425
|
+
body.styled .page h2 {
|
|
426
|
+
margin: 2rem 0 0.75rem;
|
|
427
|
+
}
|
|
428
|
+
body.styled .page ol, body.styled .page ul {
|
|
429
|
+
margin: 0.5rem 0 1rem;
|
|
430
|
+
}
|
|
431
|
+
body.styled ul.links {
|
|
432
|
+
column-width: 20rem;
|
|
433
|
+
column-gap: 2.5rem;
|
|
434
|
+
}
|
|
435
|
+
body.styled ul.links li {
|
|
436
|
+
margin-bottom: 0.4rem;
|
|
437
|
+
break-inside: avoid;
|
|
438
|
+
}
|
package/web/home/index.html
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
}
|
|
52
52
|
</script>
|
|
53
53
|
</head>
|
|
54
|
-
<body class="
|
|
54
|
+
<body class="styled">
|
|
55
55
|
<header>
|
|
56
56
|
<div class="header-inner">
|
|
57
57
|
<span class="brand">__logo__Kilotest</span>
|
|
@@ -76,7 +76,10 @@
|
|
|
76
76
|
<h2>Features</h2>
|
|
77
77
|
<p>With Kilotest, you can get results of already performed tests and propose web pages for testing. (Immediate testing on request may become available in a future version.)</p>
|
|
78
78
|
<p>There is a <a href="/capability.md">capability document</a> that summarizes what Kilotest can do for human and AI-agent users.</p>
|
|
79
|
-
|
|
79
|
+
</details>
|
|
80
|
+
<details>
|
|
81
|
+
<summary>How to use Kilotest</summary>
|
|
82
|
+
<h2>Who are you?</h2>
|
|
80
83
|
<h3>If you are a human user on the web</h3>
|
|
81
84
|
<p>You can use Kilotest starting on this page.</p>
|
|
82
85
|
<p>If your main interest is accessibility, feel free to learn more about it with our <a href="/tutorialWeb.html">tutorial</a>.</p>
|
package/web/listPages/index.html
CHANGED
|
@@ -5,25 +5,17 @@
|
|
|
5
5
|
<meta name="keywords" content="report,accessibility,a11y">
|
|
6
6
|
<title>Pages tested | Kilotest</title>
|
|
7
7
|
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
<body class="styled">
|
|
9
|
+
<header>
|
|
10
|
+
<div class="header-inner">
|
|
11
|
+
<a class="brand" href="/">__logo__<span class="brand-name">Kilotest</span></a>
|
|
12
|
+
<span class="brand-tag">Ensemble front-end testing</span>
|
|
13
|
+
</div>
|
|
14
|
+
</header>
|
|
15
|
+
<main class="page">
|
|
16
|
+
<h1>Pages tested</h1>
|
|
17
|
+
__jobSections__
|
|
16
18
|
<p>Should Kilotest <a href="requestNewTestForm.html">test a page</a> that is not listed below?</p>
|
|
17
|
-
<h2>Queued for testing</h2>
|
|
18
|
-
<ol>
|
|
19
|
-
__queue__
|
|
20
|
-
</ol>
|
|
21
|
-
<p>__noQueued__</p>
|
|
22
|
-
<h2>Being tested now</h2>
|
|
23
|
-
<ul>
|
|
24
|
-
__claimed__
|
|
25
|
-
</ul>
|
|
26
|
-
<p>__noClaimed__</p>
|
|
27
19
|
<h2>Already tested</h2>
|
|
28
20
|
__testedPages__
|
|
29
21
|
</main>
|
package/web/listPages/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ import path from 'node:path';
|
|
|
19
19
|
|
|
20
20
|
// Adds parameters to a query for the answer page.
|
|
21
21
|
const populateQuery = async (query: Record<string, any>) => {
|
|
22
|
-
const margin = ' '.repeat(
|
|
22
|
+
const margin = ' '.repeat(6);
|
|
23
23
|
// Initialize the classes of lines.
|
|
24
24
|
const lines: {requests: string[], queue: string[], claimed: string[], tested: string[]} = {
|
|
25
25
|
requests: [],
|
|
@@ -35,17 +35,11 @@ const populateQuery = async (query: Record<string, any>) => {
|
|
|
35
35
|
testRequests[url]!.forEach((req: any) => {
|
|
36
36
|
const {description, reason} = req;
|
|
37
37
|
// Add a line.
|
|
38
|
-
lines.requests.push(`${margin}<li><code>${url}</code> (${description}): ${reason}</li>`);
|
|
38
|
+
lines.requests.push(`${margin} <li><code>${url}</code> (${description}): ${reason}</li>`);
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
// Sort the lines in alphabetical order by URL and secondarily by proposed name.
|
|
42
42
|
lines.requests.sort();
|
|
43
|
-
// Add the lines to the query.
|
|
44
|
-
query.requests = lines.requests.join('\n');
|
|
45
|
-
// Add a no-requests message, if applicable, to the query.
|
|
46
|
-
query.noRequests = lines.requests.length
|
|
47
|
-
? 'Kilotest managers can <a href="enqueueForm.html">approve or reject a request</a>.'
|
|
48
|
-
: 'No requests await approval now.';
|
|
49
43
|
// Get the file names of all queued and claimed jobs.
|
|
50
44
|
const jobFileNames = await getJobNames();
|
|
51
45
|
// For each job category:
|
|
@@ -55,15 +49,41 @@ const populateQuery = async (query: Record<string, any>) => {
|
|
|
55
49
|
// Get the job.
|
|
56
50
|
const job = await getObject(path.join(jobsPath(), category, fileName)) as {target: {url: string, what: string}};
|
|
57
51
|
// Add a line.
|
|
58
|
-
lines[category].push(`${margin}<li><code>${job.target.url}</code> (${job.target.what})</li>`);
|
|
52
|
+
lines[category].push(`${margin} <li><code>${job.target.url}</code> (${job.target.what})</li>`);
|
|
59
53
|
}
|
|
60
|
-
// Add the lines to the query.
|
|
61
|
-
query[category] = lines[category].join('\n');
|
|
62
54
|
}
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
// Add a
|
|
66
|
-
|
|
55
|
+
// Initialize the conditional activity sections.
|
|
56
|
+
const sections: string[] = [];
|
|
57
|
+
// Add a section for the test requests, if there are any.
|
|
58
|
+
if (lines.requests.length) {
|
|
59
|
+
sections.push([
|
|
60
|
+
`${margin}<h2>Requested for testing</h2>`,
|
|
61
|
+
`${margin}<ol>`,
|
|
62
|
+
...lines.requests,
|
|
63
|
+
`${margin}</ol>`,
|
|
64
|
+
`${margin}<p>Kilotest managers can <a href="enqueueForm.html">approve or reject a request</a>.</p>`
|
|
65
|
+
].join('\n'));
|
|
66
|
+
}
|
|
67
|
+
// Add a section for the queued jobs, if there are any.
|
|
68
|
+
if (lines.queue.length) {
|
|
69
|
+
sections.push([
|
|
70
|
+
`${margin}<h2>Queued for testing</h2>`,
|
|
71
|
+
`${margin}<ol>`,
|
|
72
|
+
...lines.queue,
|
|
73
|
+
`${margin}</ol>`
|
|
74
|
+
].join('\n'));
|
|
75
|
+
}
|
|
76
|
+
// Add a section for the claimed jobs, if there are any.
|
|
77
|
+
if (lines.claimed.length) {
|
|
78
|
+
sections.push([
|
|
79
|
+
`${margin}<h2>Being tested now</h2>`,
|
|
80
|
+
`${margin}<ul>`,
|
|
81
|
+
...lines.claimed,
|
|
82
|
+
`${margin}</ul>`
|
|
83
|
+
].join('\n'));
|
|
84
|
+
}
|
|
85
|
+
// Add the sections to the query.
|
|
86
|
+
query.jobSections = sections.join('\n');
|
|
67
87
|
// Get extracts of the latest reports about all tested pages, sorted by page description.
|
|
68
88
|
const latestExtracts = await getReportExtracts(true);
|
|
69
89
|
const pageCount = latestExtracts.length;
|