1
0
forked from rosa/hakurei

18 Commits

Author SHA1 Message Date
Kat
d01cf2cb25 TODO: docs maybe?? 2026-03-23 04:12:08 +11:00
Kat
ed1c89afaa TODO: actually write tests lol 2026-03-23 04:12:08 +11:00
Kat
6b4fc12751 TODO: relocate test code 2026-03-23 04:12:08 +11:00
Kat
1d91fd2bfc cmd/pkgserver: aria-describe test node summary with state
The summary marker does not appear in the AOM, so setting its alt text
is fruitless.
2026-03-23 03:15:36 +11:00
Kat
b8a1cd43e7 cmd/pkgserver: provide role descriptions for test nodes in web UI 2026-03-23 03:15:36 +11:00
Kat
c9e56fca41 cmd/pkgserver: fix dark mode in test web UI 2026-03-23 03:15:36 +11:00
Kat
4407e7dab4 cmd/pkgserver: serialize JS enums as ints instead of strings 2026-03-23 03:15:36 +11:00
Kat
c1943e96ca cmd/pkgserver: set exit code when running JS tests from CLI 2026-03-23 03:15:36 +11:00
Kat
b7e86a6a0b cmd/pkgserver: expose verbose StreamReporter flag via CLI 2026-03-23 03:15:36 +11:00
Kat
a533f7ceec cmd/pkgserver: implement skipping JS tests from the DSL 2026-03-23 03:15:36 +11:00
Kat
8e3ecda93e cmd/pkgserver: allow non-global JS test suites 2026-03-23 02:19:58 +11:00
Kat
cfc4ef9822 cmd/pkgserver: serialize raw log list for go test consumption 2026-03-23 02:19:58 +11:00
Kat
03aba72900 cmd/pkgserver: add JSON reporter to facilitate go test integration 2026-03-23 02:19:58 +11:00
Kat
0e4ecda19f cmd/pkgserver: fix multi-line JS test output display 2026-03-23 02:19:58 +11:00
Kat
2b9cc602fa cmd/pkgserver: implement JS test DSL and runner 2026-03-23 02:19:58 +11:00
Kat
ee0983ef01 cmd/pkgserver: move StreamReporter display() to Reporter interface 2026-03-23 02:19:58 +11:00
Kat
e5aa3918ab cmd/pkgserver: add DOM reporter for JS tests 2026-03-23 02:19:58 +11:00
Kat
9346fb16f8 cmd/pkgserver: add basic CLI reporter for testing JS 2026-03-17 07:07:07 +11:00
4 changed files with 24 additions and 42 deletions

View File

@@ -1,10 +1,4 @@
function assertGetElementById(id: string): HTMLElement {
let elem = document.getElementById(id)
if(elem == null) throw new ReferenceError(`element with ID '${id}' missing from DOM`)
return elem
}
interface PackageIndexEntry {
class PackageIndexEntry {
name: string
size: number | null
description: string | null
@@ -40,7 +34,7 @@ function toByteSizeString(bytes: number): string {
const API_VERSION = 1
const ENDPOINT = `/api/v${API_VERSION}`
interface InfoPayload {
class InfoPayload {
count: number
hakurei_version: string
}
@@ -48,9 +42,9 @@ interface InfoPayload {
async function infoRequest(): Promise<InfoPayload> {
const res = await fetch(`${ENDPOINT}/info`)
const payload = await res.json()
return payload
return payload as InfoPayload
}
interface GetPayload {
class GetPayload {
values: PackageIndexEntry[]
}
@@ -63,7 +57,7 @@ enum SortOrders {
async function getRequest(limit: number, index: number, sort: SortOrders): Promise<GetPayload> {
const res = await fetch(`${ENDPOINT}/get?limit=${limit}&index=${index}&sort=${sort.valueOf()}`)
const payload = await res.json()
return payload
return payload as GetPayload
}
class State {
entriesPerPage: number = 10
@@ -102,16 +96,16 @@ class State {
}
updatePage() {
let page = Math.ceil(((this.getEntryIndex() + this.getEntriesPerPage()) - 1) / this.getEntriesPerPage())
assertGetElementById("page-number").innerText = String(page)
document.getElementById("page-number").innerText = String(page)
}
updateRange() {
let max = Math.min(this.getEntryIndex() + this.getEntriesPerPage(), this.getMaxEntries())
assertGetElementById("entry-counter").innerText = `${this.getEntryIndex() + 1}-${max} of ${this.getMaxEntries()}`
document.getElementById("entry-counter").innerText = `${this.getEntryIndex() + 1}-${max} of ${this.getMaxEntries()}`
}
updateListings() {
getRequest(this.getEntriesPerPage(), this.getEntryIndex(), this.getSortOrder())
.then(res => {
let table = assertGetElementById("pkg-list")
let table = document.getElementById("pkg-list")
table.innerHTML = ''
res.values.forEach((row) => {
table.appendChild(toHTML(row))
@@ -147,15 +141,15 @@ document.addEventListener("DOMContentLoaded", () => {
infoRequest()
.then(res => {
STATE.setMaxEntries(res.count)
assertGetElementById("hakurei-version").innerText = res.hakurei_version
document.getElementById("hakurei-version").innerText = res.hakurei_version
STATE.updateRange()
STATE.updateListings()
})
assertGetElementById("count").addEventListener("change", (event) => {
document.getElementById("count").addEventListener("change", (event) => {
STATE.setEntriesPerPage(parseInt((event.target as HTMLSelectElement).value))
})
assertGetElementById("sort").addEventListener("change", (event) => {
document.getElementById("sort").addEventListener("change", (event) => {
STATE.setSortOrder(parseInt((event.target as HTMLSelectElement).value))
})
})

View File

@@ -10,8 +10,8 @@ import { StreamReporter, TESTS } from "./test.js";
// TypeScript doesn't like process and Deno as their type definitions aren't
// installed, but doesn't seem to complain if they're accessed through
// globalThis.
const process: any = (globalThis as any).process;
const Deno: any = (globalThis as any).Deno;
const process: any = globalThis.process;
const Deno: any = globalThis.Deno;
function getArgs(): string[] {
if (process) {

View File

@@ -3,7 +3,7 @@
type TestTree = TestGroup | Test;
type TestGroup = { name: string, children: TestTree[] };
type Test = { name: string, test: (t: TestController) => void };
type Test = { name: string, test: (TestController) => void };
export class TestRegistrar {
#suites: TestGroup[];
@@ -39,7 +39,7 @@ export function context(name: string, children: TestTree[]): TestTree {
}
export const group = context;
export function test(name: string, test: (t: TestController) => void): TestTree {
export function test(name: string, test: (TestController) => void): TestTree {
return { name, test };
}
@@ -137,7 +137,7 @@ function extractExceptionString(e: any): string {
// String() instead of .toString() as null and undefined don't have
// properties.
const s = String(e);
if (!(e instanceof Error && e.stack)) return s;
if (!(e instanceof Error && "stack" in e)) return s;
// v8 (Chromium, NodeJS) include the error message, while Firefox and WebKit
// do not.
if (e.stack.startsWith(s)) return e.stack;
@@ -241,10 +241,9 @@ export class StreamReporter implements Reporter {
// into { "a b": ["c", "d"] }.
let pathMap = new Map<string, ({ name: string } & TestResult)[]>();
for (const t of data) {
if (t.path.length === 0) throw new RangeError("path is empty");
const key = t.path.slice(0, -1).join(SEP);
if (!pathMap.has(key)) pathMap.set(key, []);
pathMap.get(key)!.push({ name: t.path.at(-1)!, ...t });
pathMap.get(key).push({ name: t.path.at(-1), ...t });
}
this.stream.writeln("");
@@ -281,31 +280,22 @@ export class StreamReporter implements Reporter {
}
}
function throwNotInDOMError(id: string): never {
throw new ReferenceError(`element with ID '${id}' missing from DOM`);
}
export class DOMReporter implements Reporter {
register(suites: TestGroup[]) {}
update(path: string[], result: TestResult) {
if (path.length === 0) throw new RangeError("path is empty");
if (result.state === "skip") {
const text = document.getElementById("skip-counter-text");
if (!text) throwNotInDOMError("skip-counter-text");
text.classList.remove("hidden");
document.getElementById("skip-counter-text").classList.remove("hidden");
}
const counter = document.getElementById(`${result.state}-counter`);
if (!counter) throwNotInDOMError(`${result.state}-counter`);
counter.innerText = (Number(counter.innerText) + 1).toString();
let parent = document.getElementById("root");
if (!parent) throwNotInDOMError("root");
for (const node of path) {
let child: HTMLDetailsElement | null = null;
let summary: HTMLElement | null = null;
let d: Element;
outer: for (d of parent.children) {
let child: HTMLDetailsElement;
let summary: HTMLElement;
outer: for (const d of parent.children) {
if (!(d instanceof HTMLDetailsElement)) continue;
for (const s of d.children) {
if (!(s instanceof HTMLElement)) continue;
@@ -325,7 +315,6 @@ export class DOMReporter implements Reporter {
child.appendChild(summary);
parent.appendChild(child);
}
if (!summary) throw new Error("unreachable as assigned above");
switch (result.state) {
case "failure":
@@ -369,7 +358,7 @@ export class DOMReporter implements Reporter {
interface GoNode {
name: string;
subtests: GoNode[] | null;
subtests?: GoNode[];
}
// Used to display results via `go test`, via some glue code from the Go side.

View File

@@ -1,6 +1,5 @@
{
"compilerOptions": {
"strict": true,
"target": "ES2024"
}
}