diff --git a/cmd/pkgserver/ui_test/lib/go_test_entrypoint.ts b/cmd/pkgserver/ui_test/lib/go_test_entrypoint.ts new file mode 100644 index 00000000..fa8d96f2 --- /dev/null +++ b/cmd/pkgserver/ui_test/lib/go_test_entrypoint.ts @@ -0,0 +1,3 @@ +import "../all_tests.js"; +import { GoTestReporter, GLOBAL_REGISTRAR } from "./test.js"; +GLOBAL_REGISTRAR.run(new GoTestReporter()); diff --git a/cmd/pkgserver/ui_test/lib/test.ts b/cmd/pkgserver/ui_test/lib/test.ts index 7c441f00..e88d9b18 100644 --- a/cmd/pkgserver/ui_test/lib/test.ts +++ b/cmd/pkgserver/ui_test/lib/test.ts @@ -18,6 +18,7 @@ export class TestRegistrar { } run(reporter: Reporter) { + reporter.register(this.#suites); for (const suite of this.#suites) { for (const c of suite.children) runTests(reporter, [suite.name], c); } @@ -132,19 +133,26 @@ function extractExceptionString(e: any): string { // Reporting export interface Reporter { + register(suites: TestGroup[]): void; update(path: string[], result: TestResult): void; 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 }); } @@ -177,6 +185,8 @@ export class StreamReporter implements Reporter { return this.counts.successes > 0 && this.counts.failures === 0; } + register(suites: TestGroup[]) {} + update(path: string[], result: TestResult) { if (path.length === 0) throw new RangeError("path is empty"); const pathStr = path.join(SEP); @@ -244,6 +254,8 @@ function assertGetElementById(id: string): HTMLElement { } export class DOMReporter implements Reporter { + register(suites: TestGroup[]) {} + update(path: string[], result: TestResult) { if (path.length === 0) throw new RangeError("path is empty"); const counter = assertGetElementById(result.success ? "successes" : "failures"); @@ -292,3 +304,31 @@ export class DOMReporter implements Reporter { finalize() {} } + +interface GoNode { + name: string; + subtests?: GoNode[]; +} + +// Used to display results via `go test`, via some glue code from the Go side. +export class GoTestReporter implements Reporter { + register(suites: TestGroup[]) { + console.log(JSON.stringify(suites.map(GoTestReporter.serialize))); + } + + // Convert a test tree into the one expected by the Go code. + static serialize(node: TestTree): GoNode { + return { + name: node.name, + subtests: "children" in node ? node.children.map(GoTestReporter.serialize) : undefined, + }; + } + + update(path: string[], result: TestResult) { + console.log(JSON.stringify({ path, ...result })); + } + + finalize() { + console.log("null"); + } +} diff --git a/cmd/pkgserver/ui_test/sample_tests.ts b/cmd/pkgserver/ui_test/sample_tests.ts index 61ca3820..d3a9dfed 100644 --- a/cmd/pkgserver/ui_test/sample_tests.ts +++ b/cmd/pkgserver/ui_test/sample_tests.ts @@ -46,6 +46,23 @@ suite("cat", [ ]); 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`);