diff options
author | Nayeem Rahman <muhammed.9939@gmail.com> | 2020-03-15 09:34:24 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-15 10:34:24 +0100 |
commit | 64a35acd64f4a9aedfb52f6b364c229c6f7e4090 (patch) | |
tree | a2d3d68b3a072490c3d8e20333b07e165d3ab94b /cli/js | |
parent | a159165fe5f9fe53c3593af707888a7efc859d14 (diff) |
feat(cli/js/testing): Add TestDefinition::skip (#4351)
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 13 | ||||
-rw-r--r-- | cli/js/testing.ts | 131 | ||||
-rw-r--r-- | cli/js/tests/testing_test.ts | 12 |
3 files changed, 78 insertions, 78 deletions
diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index daae8b09d..2c3a9aef4 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -17,6 +17,7 @@ declare namespace Deno { export interface TestDefinition { fn: TestFunction; name: string; + skip?: boolean; } /** Register a test which will be run when `deno test` is used on the command @@ -32,12 +33,16 @@ declare namespace Deno { * when `Deno.runTests` is used */ export function test(name: string, fn: TestFunction): void; + enum TestStatus { + Passed = "passed", + Failed = "failed", + Skipped = "skipped" + } + interface TestResult { - passed: boolean; name: string; - skipped: boolean; - hasRun: boolean; - duration: number; + status: TestStatus; + duration?: number; error?: Error; } diff --git a/cli/js/testing.ts b/cli/js/testing.ts index a2944aff4..a4523d2b7 100644 --- a/cli/js/testing.ts +++ b/cli/js/testing.ts @@ -1,10 +1,11 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { red, green, bgRed, gray, italic } from "./colors.ts"; +import { bgRed, gray, green, italic, red, yellow } from "./colors.ts"; import { exit } from "./ops/os.ts"; import { Console } from "./web/console.ts"; const RED_FAILED = red("FAILED"); const GREEN_OK = green("OK"); +const YELLOW_SKIPPED = yellow("SKIPPED"); const RED_BG_FAIL = bgRed(" FAIL "); const disabledConsole = new Console((_x: string, _isErr?: boolean): void => {}); @@ -18,6 +19,7 @@ export type TestFunction = () => void | Promise<void>; export interface TestDefinition { fn: TestFunction; name: string; + skip?: boolean; } const TEST_REGISTRY: TestDefinition[] = []; @@ -31,34 +33,32 @@ export function test( t: string | TestDefinition | TestFunction, fn?: TestFunction ): void { - let name: string; + let testDef: TestDefinition; if (typeof t === "string") { - if (!fn) { - throw new Error("Missing test function"); + if (!fn || typeof fn != "function") { + throw new TypeError("Missing test function"); } - name = t; - if (!name) { - throw new Error("The name of test case can't be empty"); + if (!t) { + throw new TypeError("The test name can't be empty"); } + testDef = { fn: fn as TestFunction, name: t, skip: false }; } else if (typeof t === "function") { - fn = t; - name = t.name; - if (!name) { - throw new Error("Test function can't be anonymous"); + if (!t.name) { + throw new TypeError("The test function can't be anonymous"); } + testDef = { fn: t, name: t.name, skip: false }; } else { - fn = t.fn; - if (!fn) { - throw new Error("Missing test function"); + if (!t.fn) { + throw new TypeError("Missing test function"); } - name = t.name; - if (!name) { - throw new Error("The name of test case can't be empty"); + if (!t.name) { + throw new TypeError("The test name can't be empty"); } + testDef = { fn: t.fn, name: t.name, skip: Boolean(t.skip) }; } - TEST_REGISTRY.push({ fn, name }); + TEST_REGISTRY.push(testDef); } interface TestStats { @@ -78,20 +78,19 @@ export interface RunTestsOptions { reporter?: TestReporter; } +enum TestStatus { + Passed = "passed", + Failed = "failed", + Skipped = "skipped" +} + interface TestResult { - passed: boolean; name: string; - skipped: boolean; - hasRun: boolean; - duration: number; + status: TestStatus; + duration?: number; error?: Error; } -interface TestCase { - result: TestResult; - fn: TestFunction; -} - export enum TestEvent { Start = "start", Result = "result", @@ -115,24 +114,10 @@ interface TestEventEnd { results: TestResult[]; } -function testDefinitionToTestCase(def: TestDefinition): TestCase { - return { - fn: def.fn, - result: { - name: def.name, - passed: false, - skipped: false, - hasRun: false, - duration: 0 - } - }; -} - // TODO: already implements AsyncGenerator<RunTestsMessage>, but add as "implements to class" // TODO: implements PromiseLike<TestsResult> class TestApi { readonly testsToRun: TestDefinition[]; - readonly testCases: TestCase[]; readonly stats: TestStats = { filtered: 0, ignored: 0, @@ -148,7 +133,6 @@ class TestApi { ) { this.testsToRun = tests.filter(filterFn); this.stats.filtered = tests.length - this.testsToRun.length; - this.testCases = this.testsToRun.map(testDefinitionToTestCase); } async *[Symbol.asyncIterator](): AsyncIterator< @@ -159,32 +143,35 @@ class TestApi { tests: this.testsToRun.length }; + const results: TestResult[] = []; const suiteStart = +new Date(); - for (const testCase of this.testCases) { - const { fn, result } = testCase; - let shouldBreak = false; - try { + for (const { name, fn, skip } of this.testsToRun) { + const result: Partial<TestResult> = { name }; + if (skip) { + result.status = TestStatus.Skipped; + this.stats.ignored++; + } else { const start = +new Date(); - await fn(); - result.duration = +new Date() - start; - result.passed = true; - this.stats.passed++; - } catch (err) { - result.passed = false; - result.error = err; - this.stats.failed++; - shouldBreak = this.failFast; - } finally { - result.hasRun = true; - yield { kind: TestEvent.Result, result }; - if (shouldBreak) { - break; + try { + await fn(); + result.duration = +new Date() - start; + result.status = TestStatus.Passed; + this.stats.passed++; + } catch (err) { + result.duration = +new Date() - start; + result.status = TestStatus.Failed; + result.error = err; + this.stats.failed++; } } + yield { kind: TestEvent.Result, result: result as TestResult }; + results.push(result as TestResult); + if (this.failFast && result.error != null) { + break; + } } const duration = +new Date() - suiteStart; - const results = this.testCases.map(r => r.result); yield { kind: TestEvent.End, @@ -241,13 +228,21 @@ export class ConsoleTestReporter implements TestReporter { async result(event: TestEventResult): Promise<void> { const { result } = event; - if (result.passed) { - this.console.log( - `${GREEN_OK} ${result.name} ${formatDuration(result.duration)}` - ); - } else { - this.console.log(`${RED_FAILED} ${result.name}`); - this.console.log(result.error!); + switch (result.status) { + case TestStatus.Passed: + this.console.log( + `${GREEN_OK} ${result.name} ${formatDuration(result.duration!)}` + ); + break; + case TestStatus.Failed: + this.console.log( + `${RED_FAILED} ${result.name} ${formatDuration(result.duration!)}` + ); + this.console.log(result.error!); + break; + case TestStatus.Skipped: + this.console.log(`${YELLOW_SKIPPED} ${result.name}`); + break; } } diff --git a/cli/js/tests/testing_test.ts b/cli/js/tests/testing_test.ts index b47eb03e2..9ed89f532 100644 --- a/cli/js/tests/testing_test.ts +++ b/cli/js/tests/testing_test.ts @@ -11,8 +11,8 @@ unitTest(function nameOfTestCaseCantBeEmpty(): void { () => { Deno.test("", () => {}); }, - Error, - "The name of test case can't be empty" + TypeError, + "The test name can't be empty" ); assertThrows( () => { @@ -21,8 +21,8 @@ unitTest(function nameOfTestCaseCantBeEmpty(): void { fn: () => {} }); }, - Error, - "The name of test case can't be empty" + TypeError, + "The test name can't be empty" ); }); @@ -31,7 +31,7 @@ unitTest(function testFnCantBeAnonymous(): void { () => { Deno.test(function() {}); }, - Error, - "Test function can't be anonymous" + TypeError, + "The test function can't be anonymous" ); }); |