diff --git a/cmd/pkgserver/ui/static/run_tests.ts b/cmd/pkgserver/ui/static/run_tests.ts index 71ce2df5..1b8bff83 100644 --- a/cmd/pkgserver/ui/static/run_tests.ts +++ b/cmd/pkgserver/ui/static/run_tests.ts @@ -3,5 +3,5 @@ // provides faster iteration, especially for those acclimated to test-driven // development. import "./all_tests.js"; -import { StreamReporter, run } from "./test.js"; -run(new StreamReporter({ writeln: console.log })); +import { StreamReporter, TESTS } from "./test.js"; +TESTS.run(new StreamReporter({ writeln: console.log })); diff --git a/cmd/pkgserver/ui/static/test.ts b/cmd/pkgserver/ui/static/test.ts index eec88d82..27553bcf 100644 --- a/cmd/pkgserver/ui/static/test.ts +++ b/cmd/pkgserver/ui/static/test.ts @@ -5,11 +5,32 @@ type TestTree = TestGroup | Test; type TestGroup = { name: string, children: TestTree[] }; type Test = { name: string, test: (TestController) => void }; -let TESTS: TestGroup[] = []; +export class TestRegistrar { + #suites: TestGroup[]; + constructor() { + this.#suites = []; + } + + suite(name: string, children: TestTree[]) { + checkDuplicates(name, children) + this.#suites.push({ name, children }); + } + + run(reporter: Reporter) { + reporter.register(this.#suites); + for (const suite of this.#suites) { + for (const c of suite.children) runTests(reporter, [suite.name], c); + } + reporter.finalize(); + } +} + +export let TESTS = new TestRegistrar(); + +// Register a suite in the global registrar. export function suite(name: string, children: TestTree[]) { - checkDuplicates(name, children); - TESTS.push({ name, children }); + TESTS.suite(name, children); } export function context(name: string, children: TestTree[]): TestTree { @@ -79,14 +100,6 @@ export interface TestResult { logs: string[]; } -export function run(reporter: Reporter) { - reporter.register(TESTS); - for (const suite of TESTS) { - for (const c of suite.children) runTests(reporter, [suite.name], c); - } - reporter.finalize(); -} - function runTests(reporter: Reporter, parents: string[], node: TestTree) { const path = [...parents, node.name]; if ("children" in node) { @@ -124,6 +137,30 @@ export interface Reporter { finalize(): void; } +export class NoOpReporter implements Reporter { + suites: TestGroup[]; + results: ({ path: string[] } & TestResult)[]; + finalized: boolean; + + constructor() { + this.suites = []; + this.results = []; + this.finalized = false; + } + + register(suites: TestGroup[]) { + this.suites = suites; + } + + update(path: string[], result: TestResult) { + this.results.push({ path, ...result }); + } + + finalize() { + this.finalized = true; + } +} + export interface Stream { writeln(s: string): void; } diff --git a/cmd/pkgserver/ui/static/test_tests.ts b/cmd/pkgserver/ui/static/test_tests.ts index 33532f78..fb1627c4 100644 --- a/cmd/pkgserver/ui/static/test_tests.ts +++ b/cmd/pkgserver/ui/static/test_tests.ts @@ -1,4 +1,4 @@ -import { context, group, suite, test } from "./test.js"; +import { NoOpReporter, TestRegistrar, context, group, suite, test } from "./test.js"; suite("dog", [ group("tail", [ @@ -37,4 +37,45 @@ suite("cat", [ test("likes headpats", (t) => { t.log("meow"); }), + test("tester tester", (t) => { + const r = new TestRegistrar(); + r.suite("explod", [ + test("with yarn", (t) => { + t.log("YAY"); + }), + ]); + const reporter = new NoOpReporter(); + r.run(reporter); + if (reporter.suites.length !== 1) { + t.fatal(`incorrect number of suites registered got=${reporter.suites.length} want=1`); + } + const suite = reporter.suites[0]; + if (suite.name !== "explod") { + t.error(`suite name incorrect got='${suite.name}' want='explod'`); + } + if (suite.children.length !== 1) { + t.fatal(`incorrect number of suite children got=${suite.children.length} want=1`); + } + const test_ = suite.children[0]; + if (test_.name !== "with yarn") { + t.error(`incorrect test name got='${test_.name}' want='with yarn'`); + } + if ("children" in test_) { + t.error(`expected leaf node, got group of ${test_.children.length} children`); + } + if (!reporter.finalized) t.error(`expected reporter to have been finalized`); + if (reporter.results.length !== 1) { + t.fatal(`incorrect result count got=${reporter.results.length} want=1`); + } + const result = reporter.results[0]; + if (!(result.path.length === 2 && + result.path[0] === "explod" && + result.path[1] === "with yarn")) { + t.error(`incorrect result path got=${result.path} want=["explod", "with yarn"]`); + } + if (!result.success) t.error(`expected test to succeed`); + if (!(result.logs.length === 1 && result.logs[0] === "YAY")) { + t.error(`incorrect result logs got=${result.logs} want=["YAY"]`); + } + }), ]); diff --git a/cmd/pkgserver/ui/test.html b/cmd/pkgserver/ui/test.html index 05f14e7f..1b7ab015 100644 --- a/cmd/pkgserver/ui/test.html +++ b/cmd/pkgserver/ui/test.html @@ -20,8 +20,8 @@