diff options
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 3 | ||||
-rw-r--r-- | cli/js/testing.ts | 35 | ||||
-rw-r--r-- | cli/tests/deno_test_only.ts | 15 | ||||
-rw-r--r-- | cli/tests/deno_test_only.ts.out | 7 | ||||
-rw-r--r-- | cli/tests/integration_tests.rs | 12 | ||||
-rw-r--r-- | cli/tests/unit/test_util.ts | 9 | ||||
-rwxr-xr-x | cli/tests/unit/unit_test_runner.ts | 9 |
7 files changed, 75 insertions, 15 deletions
diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index c70eca68e..f9438ed9c 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -38,6 +38,9 @@ declare namespace Deno { fn: () => void | Promise<void>; name: string; ignore?: boolean; + /** If at lease one test has `only` set to true, only run tests that have + * `only` set to true and fail the test suite. */ + only?: boolean; /** Check that the number of async completed ops after the test is the same * as number of dispatched ops. Defaults to true.*/ sanitizeOps?: boolean; diff --git a/cli/js/testing.ts b/cli/js/testing.ts index ffe978888..a6010ed53 100644 --- a/cli/js/testing.ts +++ b/cli/js/testing.ts @@ -52,8 +52,8 @@ Before: After: - dispatched: ${post.opsDispatchedAsync} - completed: ${post.opsCompletedAsync} - -Make sure to await all promises returned from Deno APIs before + +Make sure to await all promises returned from Deno APIs before finishing test case.` ); }; @@ -76,7 +76,7 @@ function assertResources( Before: ${preStr} After: ${postStr} -Make sure to close all open resource handles returned from Deno APIs before +Make sure to close all open resource handles returned from Deno APIs before finishing test case.`; assert(preStr === postStr, msg); }; @@ -86,6 +86,7 @@ export interface TestDefinition { fn: () => void | Promise<void>; name: string; ignore?: boolean; + only?: boolean; sanitizeOps?: boolean; sanitizeResources?: boolean; } @@ -103,6 +104,7 @@ export function test( let testDef: TestDefinition; const defaults = { ignore: false, + only: false, sanitizeOps: true, sanitizeResources: true, }; @@ -156,6 +158,7 @@ interface TestMessage { measured: number; passed: number; failed: number; + usedOnly: boolean; duration: number; results: Array<TestMessage["testEnd"] & {}>; }; @@ -218,6 +221,10 @@ function reportToConsole(message: TestMessage): void { `${message.end.filtered} filtered out ` + `${formatDuration(message.end.duration)}\n` ); + + if (message.end.usedOnly && message.end.failed == 0) { + log(`${RED_FAILED} because the "only" option was used\n`); + } } } @@ -225,7 +232,7 @@ exposeForTest("reportToConsole", reportToConsole); // TODO: already implements AsyncGenerator<RunTestsMessage>, but add as "implements to class" // TODO: implements PromiseLike<RunTestsEndResult> -class TestApi { +class TestRunner { readonly testsToRun: TestDefinition[]; readonly stats = { filtered: 0, @@ -234,14 +241,18 @@ class TestApi { passed: 0, failed: 0, }; + private usedOnly: boolean; constructor( - public tests: TestDefinition[], + tests: TestDefinition[], public filterFn: (def: TestDefinition) => boolean, public failFast: boolean ) { - this.testsToRun = tests.filter(filterFn); - this.stats.filtered = tests.length - this.testsToRun.length; + const onlyTests = tests.filter(({ only }) => only); + this.usedOnly = onlyTests.length > 0; + const unfilteredTests = this.usedOnly ? onlyTests : tests; + this.testsToRun = unfilteredTests.filter(filterFn); + this.stats.filtered = unfilteredTests.length - this.testsToRun.length; } async *[Symbol.asyncIterator](): AsyncIterator<TestMessage> { @@ -280,7 +291,9 @@ class TestApi { const duration = +new Date() - suiteStart; - yield { end: { ...this.stats, duration, results } }; + yield { + end: { ...this.stats, usedOnly: this.usedOnly, duration, results }, + }; } } @@ -331,7 +344,7 @@ async function runTests({ onMessage = undefined, }: RunTestsOptions = {}): Promise<TestMessage["end"] & {}> { const filterFn = createFilterFn(filter, skip); - const testApi = new TestApi(TEST_REGISTRY, filterFn, failFast); + const testRunner = new TestRunner(TEST_REGISTRY, filterFn, failFast); const originalConsole = globalThis.console; @@ -342,7 +355,7 @@ async function runTests({ let endMsg: TestMessage["end"]; - for await (const message of testApi) { + for await (const message of testRunner) { if (onMessage != null) { await onMessage(message); } @@ -358,7 +371,7 @@ async function runTests({ globalThis.console = originalConsole; } - if (endMsg!.failed > 0 && exitOnFail) { + if ((endMsg!.failed > 0 || endMsg?.usedOnly) && exitOnFail) { exit(1); } diff --git a/cli/tests/deno_test_only.ts b/cli/tests/deno_test_only.ts new file mode 100644 index 000000000..12425f21f --- /dev/null +++ b/cli/tests/deno_test_only.ts @@ -0,0 +1,15 @@ +Deno.test({ + name: "abc", + fn() {}, +}); + +Deno.test({ + only: true, + name: "def", + fn() {}, +}); + +Deno.test({ + name: "ghi", + fn() {}, +}); diff --git a/cli/tests/deno_test_only.ts.out b/cli/tests/deno_test_only.ts.out new file mode 100644 index 000000000..a23f2505c --- /dev/null +++ b/cli/tests/deno_test_only.ts.out @@ -0,0 +1,7 @@ +[WILDCARD]running 1 tests +test def ... ok ([WILDCARD]) + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD]) + +FAILED because the "only" option was used + diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 89b46acf3..66308a499 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -1272,16 +1272,22 @@ itest!(_026_redirect_javascript { http_server: true, }); +itest!(deno_test { + args: "test test_runner_test.ts", + exit_code: 1, + output: "deno_test.out", +}); + itest!(deno_test_fail_fast { args: "test --failfast test_runner_test.ts", exit_code: 1, output: "deno_test_fail_fast.out", }); -itest!(deno_test { - args: "test test_runner_test.ts", +itest!(deno_test_only { + args: "test deno_test_only.ts", exit_code: 1, - output: "deno_test.out", + output: "deno_test_only.ts.out", }); #[test] diff --git a/cli/tests/unit/test_util.ts b/cli/tests/unit/test_util.ts index 660e13511..25da7a638 100644 --- a/cli/tests/unit/test_util.ts +++ b/cli/tests/unit/test_util.ts @@ -1,6 +1,8 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { assert, assertEquals } from "../../../std/testing/asserts.ts"; +import * as colors from "../../../std/fmt/colors.ts"; +export { colors }; import { resolve } from "../../../std/path/mod.ts"; export { assert, @@ -93,7 +95,9 @@ function registerPermCombination(perms: Permissions): void { export async function registerUnitTests(): Promise<void> { const processPerms = await getProcessPermissions(); - for (const unitTestDefinition of REGISTERED_UNIT_TESTS) { + const onlyTests = REGISTERED_UNIT_TESTS.filter(({ only }) => only); + const unitTests = onlyTests.length > 0 ? onlyTests : REGISTERED_UNIT_TESTS; + for (const unitTestDefinition of unitTests) { if (!permissionsMatch(processPerms, unitTestDefinition.perms)) { continue; } @@ -126,11 +130,13 @@ interface UnitTestPermissions { interface UnitTestOptions { ignore?: boolean; + only?: boolean; perms?: UnitTestPermissions; } interface UnitTestDefinition extends Deno.TestDefinition { ignore: boolean; + only: boolean; perms: Permissions; } @@ -174,6 +180,7 @@ export function unitTest( name, fn, ignore: !!options.ignore, + only: !!options.only, perms: normalizedPerms, }; diff --git a/cli/tests/unit/unit_test_runner.ts b/cli/tests/unit/unit_test_runner.ts index e3df358d7..38db545c7 100755 --- a/cli/tests/unit/unit_test_runner.ts +++ b/cli/tests/unit/unit_test_runner.ts @@ -2,6 +2,8 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import "./unit_tests.ts"; import { + REGISTERED_UNIT_TESTS, + colors, readLines, permissionCombinations, Permissions, @@ -225,6 +227,13 @@ async function masterRunnerMain( } console.log("Unit tests passed"); + + if (REGISTERED_UNIT_TESTS.find(({ only }) => only)) { + console.error( + `\n${colors.red("FAILED")} because the "only" option was used` + ); + Deno.exit(1); + } } const HELP = `Unit test runner |