summaryrefslogtreecommitdiff
path: root/cli/js
diff options
context:
space:
mode:
Diffstat (limited to 'cli/js')
-rw-r--r--cli/js/deno.ts8
-rw-r--r--cli/js/lib.deno.ns.d.ts107
-rw-r--r--cli/js/testing.ts344
-rw-r--r--cli/js/tests/format_error_test.ts4
-rw-r--r--cli/js/tests/test_util.ts80
-rwxr-xr-xcli/js/tests/unit_test_runner.ts64
-rw-r--r--cli/js/tests/url_test.ts4
7 files changed, 233 insertions, 378 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts
index 2c1d2a5b7..ca323fc95 100644
--- a/cli/js/deno.ts
+++ b/cli/js/deno.ts
@@ -115,7 +115,13 @@ export { utimeSync, utime } from "./ops/fs/utime.ts";
export { version } from "./version.ts";
export { writeFileSync, writeFile, WriteFileOptions } from "./write_file.ts";
export const args: string[] = [];
-export { test, runTests, TestEvent, ConsoleTestReporter } from "./testing.ts";
+export {
+ RunTestsOptions,
+ TestDefinition,
+ TestMessage,
+ runTests,
+ test,
+} from "./testing.ts";
// These are internal Deno APIs. We are marking them as internal so they do not
// appear in the runtime type library.
diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts
index ef1a82060..f3e95c70d 100644
--- a/cli/js/lib.deno.ns.d.ts
+++ b/cli/js/lib.deno.ns.d.ts
@@ -12,10 +12,8 @@ declare namespace Deno {
* See: https://no-color.org/ */
export let noColor: boolean;
- export type TestFunction = () => void | Promise<void>;
-
export interface TestDefinition {
- fn: TestFunction;
+ fn: () => void | Promise<void>;
name: string;
ignore?: boolean;
disableOpSanitizer?: boolean;
@@ -70,7 +68,7 @@ declare namespace Deno {
* assertEquals(decoder.decode(data), "Hello world")
* });
**/
- export function test(fn: TestFunction): void;
+ export function test(fn: () => void | Promise<void>): void;
/** Register a test which will be run when `deno test` is used on the command
* line and the containing module looks like a test module, or explicitly
@@ -88,78 +86,37 @@ declare namespace Deno {
* assertEquals(decoder.decode(data), "Hello world")
* });
* */
- export function test(name: string, fn: TestFunction): void;
-
- enum TestStatus {
- Passed = "passed",
- Failed = "failed",
- Ignored = "ignored",
- }
+ export function test(name: string, fn: () => void | Promise<void>): void;
- interface TestResult {
- name: string;
- status: TestStatus;
- duration?: number;
- error?: Error;
- }
-
- interface TestStats {
- filtered: number;
- ignored: number;
- measured: number;
- passed: number;
- failed: number;
- }
-
- export enum TestEvent {
- Start = "start",
- TestStart = "testStart",
- TestEnd = "testEnd",
- End = "end",
- }
-
- interface TestEventStart {
- kind: TestEvent.Start;
- tests: number;
- }
-
- interface TestEventTestStart {
- kind: TestEvent.TestStart;
- name: string;
- }
-
- interface TestEventTestEnd {
- kind: TestEvent.TestEnd;
- result: TestResult;
- }
-
- interface TestEventEnd {
- kind: TestEvent.End;
- stats: TestStats;
- duration: number;
- results: TestResult[];
- }
-
- interface TestReporter {
- start(event: TestEventStart): Promise<void>;
- testStart(msg: TestEventTestStart): Promise<void>;
- testEnd(msg: TestEventTestEnd): Promise<void>;
- end(event: TestEventEnd): Promise<void>;
- }
-
- export class ConsoleTestReporter implements TestReporter {
- constructor();
- start(event: TestEventStart): Promise<void>;
- testStart(msg: TestEventTestStart): Promise<void>;
- testEnd(msg: TestEventTestEnd): Promise<void>;
- end(event: TestEventEnd): Promise<void>;
+ export interface TestMessage {
+ start?: {
+ tests: TestDefinition[];
+ };
+ testStart?: {
+ [P in keyof TestDefinition]: TestDefinition[P];
+ };
+ testEnd?: {
+ name: string;
+ status: "passed" | "failed" | "ignored";
+ duration: number;
+ error?: Error;
+ };
+ end?: {
+ filtered: number;
+ ignored: number;
+ measured: number;
+ passed: number;
+ failed: number;
+ duration: number;
+ results: Array<TestMessage["testEnd"] & {}>;
+ };
}
export interface RunTestsOptions {
/** If `true`, Deno will exit with status code 1 if there was
* test failure. Defaults to `true`. */
exitOnFail?: boolean;
- /** If `true`, Deno will exit upon first test failure Defaults to `false`. */
+ /** If `true`, Deno will exit upon first test failure. Defaults to `false`. */
failFast?: boolean;
/** String or RegExp used to filter test to run. Only test with names
* matching provided `String` or `RegExp` will be run. */
@@ -169,8 +126,10 @@ declare namespace Deno {
skip?: string | RegExp;
/** Disable logging of the results. Defaults to `false`. */
disableLog?: boolean;
- /** Custom reporter class. If not provided uses console reporter. */
- reporter?: TestReporter;
+ /** If true, report results to the console as is done for `deno test`. Defaults to `true`. */
+ reportToConsole?: boolean;
+ /** Called for each message received from the test run. */
+ onMessage?: (message: TestMessage) => void | Promise<void>;
}
/** Run any tests which have been registered via `Deno.test()`. Always resolves
@@ -193,11 +152,7 @@ declare namespace Deno {
*/
export function runTests(
opts?: RunTestsOptions
- ): Promise<{
- results: TestResult[];
- stats: TestStats;
- duration: number;
- }>;
+ ): Promise<TestMessage["end"]> & {};
/** Returns an array containing the 1, 5, and 15 minute load averages. The
* load average is a measure of CPU and IO utilization of the last one, five,
diff --git a/cli/js/testing.ts b/cli/js/testing.ts
index 94a4cc702..5f1a62c63 100644
--- a/cli/js/testing.ts
+++ b/cli/js/testing.ts
@@ -3,6 +3,7 @@ import { gray, green, italic, red, yellow } from "./colors.ts";
import { exit } from "./ops/os.ts";
import { Console, stringifyArgs } from "./web/console.ts";
import { stdout } from "./files.ts";
+import { exposeForTest } from "./internals.ts";
import { TextEncoder } from "./web/text_encoding.ts";
import { metrics } from "./ops/runtime.ts";
import { resources } from "./ops/resources.ts";
@@ -18,12 +19,12 @@ function formatDuration(time = 0): string {
return gray(italic(timeStr));
}
-// Wrap `TestFunction` in additional assertion that makes sure
+// Wrap test function in additional assertion that makes sure
// the test case does not leak async "ops" - ie. number of async
// completed ops after the test is the same as number of dispatched
// ops. Note that "unref" ops are ignored since in nature that are
// optional.
-function assertOps(fn: TestFunction): TestFunction {
+function assertOps(fn: () => void | Promise<void>): () => void | Promise<void> {
return async function asyncOpSanitizer(): Promise<void> {
const pre = metrics();
await fn();
@@ -38,17 +39,19 @@ function assertOps(fn: TestFunction): TestFunction {
Before:
- dispatched: ${pre.opsDispatchedAsync}
- completed: ${pre.opsCompletedAsync}
-After:
+After:
- dispatched: ${post.opsDispatchedAsync}
- completed: ${post.opsCompletedAsync}`
);
};
}
-// Wrap `TestFunction` in additional assertion that makes sure
+// Wrap test function in additional assertion that makes sure
// the test case does not "leak" resources - ie. resource table after
// the test has exactly the same contents as before the test.
-function assertResources(fn: TestFunction): TestFunction {
+function assertResources(
+ fn: () => void | Promise<void>
+): () => void | Promise<void> {
return async function resourceSanitizer(): Promise<void> {
const pre = resources();
await fn();
@@ -63,10 +66,8 @@ After: ${postStr}`;
};
}
-export type TestFunction = () => void | Promise<void>;
-
export interface TestDefinition {
- fn: TestFunction;
+ fn: () => void | Promise<void>;
name: string;
ignore?: boolean;
disableOpSanitizer?: boolean;
@@ -76,13 +77,13 @@ export interface TestDefinition {
const TEST_REGISTRY: TestDefinition[] = [];
export function test(t: TestDefinition): void;
-export function test(fn: TestFunction): void;
-export function test(name: string, fn: TestFunction): void;
+export function test(fn: () => void | Promise<void>): void;
+export function test(name: string, fn: () => void | Promise<void>): void;
// Main test function provided by Deno, as you can see it merely
// creates a new object with "name" and "fn" fields.
export function test(
- t: string | TestDefinition | TestFunction,
- fn?: TestFunction
+ t: string | TestDefinition | (() => void | Promise<void>),
+ fn?: () => void | Promise<void>
): void {
let testDef: TestDefinition;
@@ -93,7 +94,7 @@ export function test(
if (!t) {
throw new TypeError("The test name can't be empty");
}
- testDef = { fn: fn as TestFunction, name: t, ignore: false };
+ testDef = { fn: fn as () => void | Promise<void>, name: t, ignore: false };
} else if (typeof t === "function") {
if (!t.name) {
throw new TypeError("The test function can't be anonymous");
@@ -120,70 +121,98 @@ export function test(
TEST_REGISTRY.push(testDef);
}
-interface TestStats {
- filtered: number;
- ignored: number;
- measured: number;
- passed: number;
- failed: number;
-}
-
-export interface RunTestsOptions {
- exitOnFail?: boolean;
- failFast?: boolean;
- only?: string | RegExp;
- skip?: string | RegExp;
- disableLog?: boolean;
- reporter?: TestReporter;
+export interface TestMessage {
+ start?: {
+ tests: TestDefinition[];
+ };
+ // Must be extensible, avoiding `testStart?: TestDefinition;`.
+ testStart?: {
+ [P in keyof TestDefinition]: TestDefinition[P];
+ };
+ testEnd?: {
+ name: string;
+ status: "passed" | "failed" | "ignored";
+ duration: number;
+ error?: Error;
+ };
+ end?: {
+ filtered: number;
+ ignored: number;
+ measured: number;
+ passed: number;
+ failed: number;
+ duration: number;
+ results: Array<TestMessage["testEnd"] & {}>;
+ };
}
-enum TestStatus {
- Passed = "passed",
- Failed = "failed",
- Ignored = "ignored",
-}
+const encoder = new TextEncoder();
-interface TestResult {
- name: string;
- status: TestStatus;
- duration: number;
- error?: Error;
-}
+function log(msg: string, noNewLine = false): void {
+ if (!noNewLine) {
+ msg += "\n";
+ }
-export enum TestEvent {
- Start = "start",
- TestStart = "testStart",
- TestEnd = "testEnd",
- End = "end",
+ // Using `stdout` here because it doesn't force new lines
+ // compared to `console.log`; `core.print` on the other hand
+ // is line-buffered and doesn't output message without newline
+ stdout.writeSync(encoder.encode(msg));
}
-interface TestEventStart {
- kind: TestEvent.Start;
- tests: number;
-}
+function reportToConsole(message: TestMessage): void {
+ if (message.start != null) {
+ log(`running ${message.start.tests.length} tests`);
+ } else if (message.testStart != null) {
+ const { name } = message.testStart;
+
+ log(`test ${name} ... `, true);
+ return;
+ } else if (message.testEnd != null) {
+ switch (message.testEnd.status) {
+ case "passed":
+ log(`${GREEN_OK} ${formatDuration(message.testEnd.duration)}`);
+ break;
+ case "failed":
+ log(`${RED_FAILED} ${formatDuration(message.testEnd.duration)}`);
+ break;
+ case "ignored":
+ log(`${YELLOW_IGNORED} ${formatDuration(message.testEnd.duration)}`);
+ break;
+ }
+ } else if (message.end != null) {
+ const failures = message.end.results.filter((m) => m.error != null);
+ if (failures.length > 0) {
+ log(`\nfailures:\n`);
+
+ for (const { name, error } of failures) {
+ log(name);
+ log(stringifyArgs([error!]));
+ log("");
+ }
-interface TestEventTestStart {
- kind: TestEvent.TestStart;
- name: string;
-}
+ log(`failures:\n`);
-interface TestEventTestEnd {
- kind: TestEvent.TestEnd;
- result: TestResult;
+ for (const { name } of failures) {
+ log(`\t${name}`);
+ }
+ }
+ log(
+ `\ntest result: ${message.end.failed ? RED_FAILED : GREEN_OK}. ` +
+ `${message.end.passed} passed; ${message.end.failed} failed; ` +
+ `${message.end.ignored} ignored; ${message.end.measured} measured; ` +
+ `${message.end.filtered} filtered out ` +
+ `${formatDuration(message.end.duration)}\n`
+ );
+ }
}
-interface TestEventEnd {
- kind: TestEvent.End;
- stats: TestStats;
- duration: number;
- results: TestResult[];
-}
+exposeForTest("reportToConsole", reportToConsole);
// TODO: already implements AsyncGenerator<RunTestsMessage>, but add as "implements to class"
-// TODO: implements PromiseLike<TestsResult>
+// TODO: implements PromiseLike<RunTestsEndResult>
class TestApi {
readonly testsToRun: TestDefinition[];
- readonly stats: TestStats = {
+ readonly stats = {
filtered: 0,
ignored: 0,
measured: 0,
@@ -200,51 +229,43 @@ class TestApi {
this.stats.filtered = tests.length - this.testsToRun.length;
}
- async *[Symbol.asyncIterator](): AsyncIterator<
- TestEventStart | TestEventTestStart | TestEventTestEnd | TestEventEnd
- > {
- yield {
- kind: TestEvent.Start,
- tests: this.testsToRun.length,
- };
+ async *[Symbol.asyncIterator](): AsyncIterator<TestMessage> {
+ yield { start: { tests: this.testsToRun } };
- const results: TestResult[] = [];
+ const results: Array<TestMessage["testEnd"] & {}> = [];
const suiteStart = +new Date();
- for (const { name, fn, ignore } of this.testsToRun) {
- const result: Partial<TestResult> = { name, duration: 0 };
- yield { kind: TestEvent.TestStart, name };
- if (ignore) {
- result.status = TestStatus.Ignored;
+ for (const test of this.testsToRun) {
+ const endMessage: Partial<TestMessage["testEnd"] & {}> = {
+ name: test.name,
+ duration: 0,
+ };
+ yield { testStart: { ...test } };
+ if (test.ignore) {
+ endMessage.status = "ignored";
this.stats.ignored++;
} else {
const start = +new Date();
try {
- await fn();
- result.status = TestStatus.Passed;
+ await test.fn();
+ endMessage.status = "passed";
this.stats.passed++;
} catch (err) {
- result.status = TestStatus.Failed;
- result.error = err;
+ endMessage.status = "failed";
+ endMessage.error = err;
this.stats.failed++;
- } finally {
- result.duration = +new Date() - start;
}
+ endMessage.duration = +new Date() - start;
}
- yield { kind: TestEvent.TestEnd, result: result as TestResult };
- results.push(result as TestResult);
- if (this.failFast && result.error != null) {
+ results.push(endMessage as TestMessage["testEnd"] & {});
+ yield { testEnd: endMessage as TestMessage["testEnd"] };
+ if (this.failFast && endMessage.error != null) {
break;
}
}
const duration = +new Date() - suiteStart;
- yield {
- kind: TestEvent.End,
- stats: this.stats,
- results,
- duration,
- };
+ yield { end: { ...this.stats, duration, results } };
}
}
@@ -275,95 +296,14 @@ function createFilterFn(
};
}
-interface TestReporter {
- start(msg: TestEventStart): Promise<void>;
- testStart(msg: TestEventTestStart): Promise<void>;
- testEnd(msg: TestEventTestEnd): Promise<void>;
- end(msg: TestEventEnd): Promise<void>;
-}
-
-export class ConsoleTestReporter implements TestReporter {
- start(event: TestEventStart): Promise<void> {
- ConsoleTestReporter.log(`running ${event.tests} tests`);
- return Promise.resolve();
- }
-
- testStart(event: TestEventTestStart): Promise<void> {
- const { name } = event;
-
- ConsoleTestReporter.log(`test ${name} ... `, true);
- return Promise.resolve();
- }
-
- testEnd(event: TestEventTestEnd): Promise<void> {
- const { result } = event;
-
- switch (result.status) {
- case TestStatus.Passed:
- ConsoleTestReporter.log(
- `${GREEN_OK} ${formatDuration(result.duration)}`
- );
- break;
- case TestStatus.Failed:
- ConsoleTestReporter.log(
- `${RED_FAILED} ${formatDuration(result.duration)}`
- );
- break;
- case TestStatus.Ignored:
- ConsoleTestReporter.log(
- `${YELLOW_IGNORED} ${formatDuration(result.duration)}`
- );
- break;
- }
-
- return Promise.resolve();
- }
-
- end(event: TestEventEnd): Promise<void> {
- const { stats, duration, results } = event;
- // Attempting to match the output of Rust's test runner.
- const failedTests = results.filter((r) => r.error);
-
- if (failedTests.length > 0) {
- ConsoleTestReporter.log(`\nfailures:\n`);
-
- for (const result of failedTests) {
- ConsoleTestReporter.log(`${result.name}`);
- ConsoleTestReporter.log(`${stringifyArgs([result.error!])}`);
- ConsoleTestReporter.log("");
- }
-
- ConsoleTestReporter.log(`failures:\n`);
-
- for (const result of failedTests) {
- ConsoleTestReporter.log(`\t${result.name}`);
- }
- }
-
- ConsoleTestReporter.log(
- `\ntest result: ${stats.failed ? RED_FAILED : GREEN_OK}. ` +
- `${stats.passed} passed; ${stats.failed} failed; ` +
- `${stats.ignored} ignored; ${stats.measured} measured; ` +
- `${stats.filtered} filtered out ` +
- `${formatDuration(duration)}\n`
- );
-
- return Promise.resolve();
- }
-
- static encoder = new TextEncoder();
-
- static log(msg: string, noNewLine = false): Promise<void> {
- if (!noNewLine) {
- msg += "\n";
- }
-
- // Using `stdout` here because it doesn't force new lines
- // compared to `console.log`; `core.print` on the other hand
- // is line-buffered and doesn't output message without newline
- stdout.writeSync(ConsoleTestReporter.encoder.encode(msg));
- return Promise.resolve();
- }
+export interface RunTestsOptions {
+ exitOnFail?: boolean;
+ failFast?: boolean;
+ only?: string | RegExp;
+ skip?: string | RegExp;
+ disableLog?: boolean;
+ reportToConsole?: boolean;
+ onMessage?: (message: TestMessage) => void | Promise<void>;
}
export async function runTests({
@@ -372,19 +312,12 @@ export async function runTests({
only = undefined,
skip = undefined,
disableLog = false,
- reporter = undefined,
-}: RunTestsOptions = {}): Promise<{
- results: TestResult[];
- stats: TestStats;
- duration: number;
-}> {
+ reportToConsole: reportToConsole_ = true,
+ onMessage = undefined,
+}: RunTestsOptions = {}): Promise<TestMessage["end"] & {}> {
const filterFn = createFilterFn(only, skip);
const testApi = new TestApi(TEST_REGISTRY, filterFn, failFast);
- if (!reporter) {
- reporter = new ConsoleTestReporter();
- }
-
// @ts-ignore
const originalConsole = globalThis.console;
@@ -393,24 +326,17 @@ export async function runTests({
globalThis.console = disabledConsole;
}
- let endMsg: TestEventEnd;
-
- for await (const testMsg of testApi) {
- switch (testMsg.kind) {
- case TestEvent.Start:
- await reporter.start(testMsg);
- continue;
- case TestEvent.TestStart:
- await reporter.testStart(testMsg);
- continue;
- case TestEvent.TestEnd:
- await reporter.testEnd(testMsg);
- continue;
- case TestEvent.End:
- endMsg = testMsg;
- delete endMsg!.kind;
- await reporter.end(testMsg);
- continue;
+ let endMsg: TestMessage["end"];
+
+ for await (const message of testApi) {
+ if (onMessage != null) {
+ await onMessage(message);
+ }
+ if (reportToConsole_) {
+ reportToConsole(message);
+ }
+ if (message.end != null) {
+ endMsg = message.end;
}
}
@@ -419,7 +345,7 @@ export async function runTests({
globalThis.console = originalConsole;
}
- if (endMsg!.stats.failed > 0 && exitOnFail) {
+ if (endMsg!.failed > 0 && exitOnFail) {
exit(1);
}
diff --git a/cli/js/tests/format_error_test.ts b/cli/js/tests/format_error_test.ts
index 42c16b0c0..0cb963ae6 100644
--- a/cli/js/tests/format_error_test.ts
+++ b/cli/js/tests/format_error_test.ts
@@ -31,7 +31,3 @@ unitTest(function formatDiagnosticError() {
}
assert(thrown);
});
-
-if (import.meta.main) {
- Deno.runTests();
-}
diff --git a/cli/js/tests/test_util.ts b/cli/js/tests/test_util.ts
index da2e917f8..a3b4b6ce4 100644
--- a/cli/js/tests/test_util.ts
+++ b/cli/js/tests/test_util.ts
@@ -132,19 +132,21 @@ interface UnitTestDefinition extends Deno.TestDefinition {
perms: Permissions;
}
+type TestFunction = () => void | Promise<void>;
+
export const REGISTERED_UNIT_TESTS: UnitTestDefinition[] = [];
-export function unitTest(fn: Deno.TestFunction): void;
-export function unitTest(options: UnitTestOptions, fn: Deno.TestFunction): void;
+export function unitTest(fn: TestFunction): void;
+export function unitTest(options: UnitTestOptions, fn: TestFunction): void;
export function unitTest(
- optionsOrFn: UnitTestOptions | Deno.TestFunction,
- maybeFn?: Deno.TestFunction
+ optionsOrFn: UnitTestOptions | TestFunction,
+ maybeFn?: TestFunction
): void {
assert(optionsOrFn, "At least one argument is required");
let options: UnitTestOptions;
let name: string;
- let fn: Deno.TestFunction;
+ let fn: TestFunction;
if (typeof optionsOrFn === "function") {
options = {};
@@ -196,44 +198,38 @@ export function createResolvable<T>(): Resolvable<T> {
const encoder = new TextEncoder();
-export class SocketReporter implements Deno.TestReporter {
- #conn: Deno.Conn;
-
- constructor(conn: Deno.Conn) {
- this.#conn = conn;
- }
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- async write(msg: any): Promise<void> {
- const encodedMsg = encoder.encode(JSON.stringify(msg) + "\n");
- await Deno.writeAll(this.#conn, encodedMsg);
- }
-
- async start(msg: Deno.TestEventStart): Promise<void> {
- await this.write(msg);
- }
-
- async testStart(msg: Deno.TestEventTestStart): Promise<void> {
- await this.write(msg);
- }
-
- async testEnd(msg: Deno.TestEventTestEnd): Promise<void> {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const serializedMsg: any = { ...msg };
-
- // Error is a JS object, so we need to turn it into string to
- // send over socket.
- if (serializedMsg.result.error) {
- serializedMsg.result.error = String(serializedMsg.result.error.stack);
- }
-
- await this.write(serializedMsg);
- }
+// Replace functions with null, errors with their stack strings, and JSONify.
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function serializeTestMessage(message: Deno.TestMessage): string {
+ return JSON.stringify({
+ start: message.start && {
+ ...message.start,
+ tests: message.start.tests.map((test) => ({ ...test, fn: null })),
+ },
+ testStart: message.testStart && { ...message.testStart, fn: null },
+ testEnd: message.testEnd && {
+ ...message.testEnd,
+ error: String(message.testEnd.error?.stack),
+ },
+ end: message.end && {
+ ...message.end,
+ results: message.end.results.map((result) => ({
+ ...result,
+ error: result.error?.stack,
+ })),
+ },
+ });
+}
- async end(msg: Deno.TestEventEnd): Promise<void> {
- const encodedMsg = encoder.encode(JSON.stringify(msg));
- await Deno.writeAll(this.#conn, encodedMsg);
- this.#conn.closeWrite();
+export async function reportToConn(
+ conn: Deno.Conn,
+ message: Deno.TestMessage
+): Promise<void> {
+ const line = serializeTestMessage(message);
+ const encodedMsg = encoder.encode(line + (message.end == null ? "\n" : ""));
+ await Deno.writeAll(conn, encodedMsg);
+ if (message.end != null) {
+ conn.closeWrite();
}
}
diff --git a/cli/js/tests/unit_test_runner.ts b/cli/js/tests/unit_test_runner.ts
index 8d3eaa4f5..0232bb437 100755
--- a/cli/js/tests/unit_test_runner.ts
+++ b/cli/js/tests/unit_test_runner.ts
@@ -6,18 +6,20 @@ import {
permissionCombinations,
Permissions,
registerUnitTests,
- SocketReporter,
fmtPerms,
parseArgs,
+ reportToConn,
} from "./test_util.ts";
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const reportToConsole = (Deno as any)[Deno.symbols.internal]
+ .reportToConsole as (message: Deno.TestMessage) => void;
+
interface PermissionSetTestResult {
perms: Permissions;
passed: boolean;
- stats: Deno.TestStats;
+ endMessage: Deno.TestMessage["end"];
permsStr: string;
- duration: number;
- results: Deno.TestResult[];
}
const PERMISSIONS: Deno.PermissionName[] = [
@@ -59,17 +61,16 @@ async function workerRunnerMain(
}
// Setup reporter
const conn = await Deno.connect(addr);
- const socketReporter = new SocketReporter(conn);
// Drop current process permissions to requested set
await dropWorkerPermissions(perms);
// Register unit tests that match process permissions
await registerUnitTests();
// Execute tests
await Deno.runTests({
- failFast: false,
exitOnFail: false,
- reporter: socketReporter,
only: filter,
+ reportToConsole: false,
+ onMessage: reportToConn.bind(null, conn),
});
}
@@ -117,7 +118,6 @@ async function runTestsForPermissionSet(
listener: Deno.Listener,
addrStr: string,
verbose: boolean,
- reporter: Deno.ConsoleTestReporter,
perms: Permissions,
filter?: string
): Promise<PermissionSetTestResult> {
@@ -128,22 +128,16 @@ async function runTestsForPermissionSet(
const conn = await listener.accept();
let expectedPassedTests;
- let endEvent;
+ let endMessage: Deno.TestMessage["end"];
try {
for await (const line of readLines(conn)) {
- const msg = JSON.parse(line);
-
- if (msg.kind === Deno.TestEvent.Start) {
- expectedPassedTests = msg.tests;
- await reporter.start(msg);
- } else if (msg.kind === Deno.TestEvent.TestStart) {
- await reporter.testStart(msg);
- } else if (msg.kind === Deno.TestEvent.TestEnd) {
- await reporter.testEnd(msg);
- } else {
- endEvent = msg;
- await reporter.end(msg);
+ const message = JSON.parse(line) as Deno.TestMessage;
+ reportToConsole(message);
+ if (message.start != null) {
+ expectedPassedTests = message.start.tests.length;
+ } else if (message.end != null) {
+ endMessage = message.end;
}
}
} finally {
@@ -151,11 +145,11 @@ async function runTestsForPermissionSet(
conn.close();
}
- if (expectedPassedTests === undefined) {
+ if (expectedPassedTests == null) {
throw new Error("Worker runner didn't report start");
}
- if (endEvent === undefined) {
+ if (endMessage == null) {
throw new Error("Worker runner didn't report end");
}
@@ -168,16 +162,13 @@ async function runTestsForPermissionSet(
workerProcess.close();
- const passed =
- expectedPassedTests === endEvent.stats.passed + endEvent.stats.ignored;
+ const passed = expectedPassedTests === endMessage.passed + endMessage.ignored;
return {
perms,
passed,
permsStr: permsFmt,
- duration: endEvent.duration,
- stats: endEvent.stats,
- results: endEvent.results,
+ endMessage,
};
}
@@ -195,7 +186,6 @@ async function masterRunnerMain(
}
const testResults = new Set<PermissionSetTestResult>();
- const consoleReporter = new Deno.ConsoleTestReporter();
const addr = { hostname: "127.0.0.1", port: 4510 };
const addrStr = `${addr.hostname}:${addr.port}`;
const listener = Deno.listen(addr);
@@ -205,7 +195,6 @@ async function masterRunnerMain(
listener,
addrStr,
verbose,
- consoleReporter,
perms,
filter
);
@@ -217,14 +206,9 @@ async function masterRunnerMain(
let testsPassed = true;
for (const testResult of testResults) {
- const { permsStr, stats, duration, results } = testResult;
+ const { permsStr, endMessage } = testResult;
console.log(`Summary for ${permsStr}`);
- await consoleReporter.end({
- kind: Deno.TestEvent.End,
- stats,
- duration,
- results,
- });
+ reportToConsole({ end: endMessage });
testsPassed = testsPassed && testResult.passed;
}
@@ -312,11 +296,7 @@ async function main(): Promise<void> {
// Running tests matching current process permissions
await registerUnitTests();
- await Deno.runTests({
- failFast: false,
- exitOnFail: true,
- only: filter,
- });
+ await Deno.runTests({ only: filter });
}
main();
diff --git a/cli/js/tests/url_test.ts b/cli/js/tests/url_test.ts
index e1b2d47bd..e4d497ffb 100644
--- a/cli/js/tests/url_test.ts
+++ b/cli/js/tests/url_test.ts
@@ -212,7 +212,3 @@ unitTest(function createBadUrl(): void {
new URL("0.0.0.0:8080");
});
});
-
-if (import.meta.main) {
- Deno.runTests();
-}