diff --git a/cli/js/deno.ts b/cli/js/deno.ts index 2c1d2a5b73fa0..ca323fc95051a 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 ef1a820604969..f3e95c70deea9 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; - export interface TestDefinition { - fn: TestFunction; + fn: () => void | Promise; 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; /** 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; - 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; - testStart(msg: TestEventTestStart): Promise; - testEnd(msg: TestEventTestEnd): Promise; - end(event: TestEventEnd): Promise; - } - - export class ConsoleTestReporter implements TestReporter { - constructor(); - start(event: TestEventStart): Promise; - testStart(msg: TestEventTestStart): Promise; - testEnd(msg: TestEventTestEnd): Promise; - end(event: TestEventEnd): Promise; + 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; + }; } 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; } /** 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 & {}; /** 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 94a4cc7026bd7..5f1a62c63c66d 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 | Promise { return async function asyncOpSanitizer(): Promise { 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 | Promise { return async function resourceSanitizer(): Promise { const pre = resources(); await fn(); @@ -63,10 +66,8 @@ After: ${postStr}`; }; } -export type TestFunction = () => void | Promise; - export interface TestDefinition { - fn: TestFunction; + fn: () => void | Promise; 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; +export function test(name: string, fn: () => void | Promise): 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), + fn?: () => void | Promise ): 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, 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; + }; } -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, but add as "implements to class" -// TODO: implements PromiseLike +// TODO: implements PromiseLike 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 { + yield { start: { tests: this.testsToRun } }; - const results: TestResult[] = []; + const results: Array = []; const suiteStart = +new Date(); - for (const { name, fn, ignore } of this.testsToRun) { - const result: Partial = { name, duration: 0 }; - yield { kind: TestEvent.TestStart, name }; - if (ignore) { - result.status = TestStatus.Ignored; + for (const test of this.testsToRun) { + const endMessage: Partial = { + 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; - testStart(msg: TestEventTestStart): Promise; - testEnd(msg: TestEventTestEnd): Promise; - end(msg: TestEventEnd): Promise; -} - -export class ConsoleTestReporter implements TestReporter { - start(event: TestEventStart): Promise { - ConsoleTestReporter.log(`running ${event.tests} tests`); - return Promise.resolve(); - } - - testStart(event: TestEventTestStart): Promise { - const { name } = event; - - ConsoleTestReporter.log(`test ${name} ... `, true); - return Promise.resolve(); - } - - testEnd(event: TestEventTestEnd): Promise { - 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 { - 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 { - 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; } 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 { 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 42c16b0c03745..0cb963ae69311 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 da2e917f8b5d2..a3b4b6ce46cd1 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; + 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(): Resolvable { 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 { - const encodedMsg = encoder.encode(JSON.stringify(msg) + "\n"); - await Deno.writeAll(this.#conn, encodedMsg); - } - - async start(msg: Deno.TestEventStart): Promise { - await this.write(msg); - } - - async testStart(msg: Deno.TestEventTestStart): Promise { - await this.write(msg); - } - - async testEnd(msg: Deno.TestEventTestEnd): Promise { - // 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 { - 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 { + 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 8d3eaa4f5ca71..0232bb43774c0 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 { @@ -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(); - 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 { // 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 e1b2d47bdc9f8..e4d497ffb4c2e 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(); -} diff --git a/std/fs/walk_test.ts b/std/fs/walk_test.ts index 96bfcae67571e..57d3cf8eab5f6 100644 --- a/std/fs/walk_test.ts +++ b/std/fs/walk_test.ts @@ -7,7 +7,7 @@ const isWindows = Deno.build.os == "win"; export function testWalk( setup: (arg0: string) => void | Promise, - t: Deno.TestFunction, + t: () => void | Promise, ignore = false ): void { const name = t.name; diff --git a/std/testing/README.md b/std/testing/README.md index c7c614103edbd..711aa02575d47 100644 --- a/std/testing/README.md +++ b/std/testing/README.md @@ -46,8 +46,6 @@ Deno.test({ assertEquals({ hello: "world" }, { hello: "world" }); }, }); - -await Deno.runTests(); ``` Short syntax (named function instead of object):