diff --git a/mod.ts b/mod.ts index c15ab4e0..f7a2ec98 100644 --- a/mod.ts +++ b/mod.ts @@ -1,80 +1,7 @@ import { asserts } from "./deps.ts"; import { MockServerRequest } from "./src/mocks/server_request.ts"; import { TestCase } from "./src/test_case.ts"; - -/** - * Example: - * - * { - * suites: { - * "My Suite": { - * cases: [ - * { - * name: "My Case", - * new_name: this.formatTestCaseName(name), - * testFn: Function - * }, - * ... - * ], - * after_all_case_hook: Function, - * after_each_case_hook: Function, - * before_all_case_hook: Function, - * before_each_case_hook: Function - * }, - * ... // More suites allowed - * }, - * after_all_suite_hook: Function; - * after_each_suite_hook: Function; - * before_all_suite_hook: Function; - * before_each_suite_hook: Function; - * } - * - * or: - * - * { - suites: { - run(): { - cases: [Array], - after_all_case_hook: [Function], - before_all_case_hook: [Function], - before_each_case_hook: [Function], - after_each_case_hook: [Function] - }, - close(): { - cases: [Array], - after_all_case_hook: [Function], - before_all_case_hook: [Function], - before_each_case_hook: [Function], - after_each_case_hook: [Function] - } - }, - before_each_suite_hook: [Function], - after_each_suite_hook: [Function], - after_all_suite_hook: [Function], - before_all_suite_hook: [Function] - * } - */ -interface Plan { - [key: string]: { // Plan name - suites?: { - [key: string]: { // suite names - cases?: Array<{ - name: string; - new_name: string; - testFn: Function; - }>; - after_all_case_hook?: Function; - after_each_case_hook?: Function; - before_all_case_hook?: Function; - before_each_case_hook?: Function; - }; - }; - after_all_suite_hook?: Function; - after_each_suite_hook?: Function; - before_all_suite_hook?: Function; - before_each_suite_hook?: Function; - }; -} +import { ITestPlan, ITestSuite, ITestCase } from "./src/interfaces.ts"; /** * @description @@ -131,7 +58,7 @@ export class RhumRunner { protected passed_in_test_suite: string = ""; protected test_plan_in_progress: string = ""; protected test_suite_in_progress: string = ""; - protected plan: any = {}; // TODO(ebebbington) Needs a type, use Plan interface but fix the TS errors it gives + protected plan: ITestPlan = { suites: {} }; // FILE MARKER - METHODS - CONSTRUCTOR /////////////////////////////////////// @@ -159,7 +86,7 @@ export class RhumRunner { // Check if the hook is for test cases inside of a suite if (this.passed_in_test_plan && this.passed_in_test_suite) { // is a before each inside a suite for every test case - this.plan.suites[this.passed_in_test_suite].before_each_case_hook = cb; + this.plan.suites![this.passed_in_test_suite].before_each_case_hook = cb; } else if (this.passed_in_test_plan && !this.passed_in_test_suite) { // before each hooks for the suites this.plan.before_each_suite_hook = cb; @@ -180,7 +107,7 @@ export class RhumRunner { // Check if the hook is for test cases inside of a suite if (this.passed_in_test_plan && this.passed_in_test_suite) { // is a after each inside a suite for every test case - this.plan.suites[this.passed_in_test_suite].after_each_case_hook = cb; + this.plan.suites![this.passed_in_test_suite].after_each_case_hook = cb; } else if (this.passed_in_test_plan && !this.passed_in_test_suite) { // after each hooks for the suites this.plan.after_each_suite_hook = cb; @@ -201,7 +128,7 @@ export class RhumRunner { // Check if the hook is for test cases inside of a suite if (this.passed_in_test_plan && this.passed_in_test_suite) { // is a before all inside a suite for every test case - this.plan.suites[this.passed_in_test_suite].after_all_case_hook = cb; + this.plan.suites![this.passed_in_test_suite].after_all_case_hook = cb; } else if (this.passed_in_test_plan && !this.passed_in_test_suite) { // before all hooks for the suites this.plan.after_all_suite_hook = cb; @@ -222,7 +149,7 @@ export class RhumRunner { // Check if the hook is for test cases inside of a suite if (this.passed_in_test_plan && this.passed_in_test_suite) { // is a before all inside a suite for every test case - this.plan.suites[this.passed_in_test_suite].before_all_case_hook = cb; + this.plan.suites![this.passed_in_test_suite].before_all_case_hook = cb; } else if (this.passed_in_test_plan && !this.passed_in_test_suite) { // before all hooks for the suites this.plan.before_all_suite_hook = cb; @@ -268,7 +195,7 @@ export class RhumRunner { * @return void */ public testCase(name: string, testFn: Function): void { - this.plan.suites[this.passed_in_test_suite].cases.push({ + this.plan.suites[this.passed_in_test_suite].cases!.push({ name, new_name: this.formatTestCaseName(name), testFn, @@ -289,9 +216,6 @@ export class RhumRunner { public testPlan(name: string, testSuites: Function): void { this.passed_in_test_suite = ""; // New plan this.passed_in_test_plan = name; - this.plan = { - suites: {}, - }; testSuites(); } @@ -308,7 +232,7 @@ export class RhumRunner { */ public testSuite(name: string, testCases: Function): void { this.passed_in_test_suite = name; - this.plan.suites[name] = { cases: [] }; + this.plan.suites![name] = { cases: [] }; testCases(); } diff --git a/src/interfaces.ts b/src/interfaces.ts new file mode 100644 index 00000000..985b3c14 --- /dev/null +++ b/src/interfaces.ts @@ -0,0 +1,126 @@ +/** + * @description + * + * suites + * An object of objects matching the ITestSuite interface. + * + * after_all_suite_hook? + * A callback function to execute after all test suites. + * + * after_each_suite_hook? + * A callback function to execute after each test suite. + * + * before_all_suite_hook? + * A callback function to execute before all test suites. + * + * before_each_suite_hook? + * A callback function to execute before each test suite. + * + * + * Example below ... + * + * { + * suites: { + * "My Suite": { + * cases: [ + * { + * name: "My Case", + * new_name: this.formatTestCaseName(name), + * testFn: Function + * }, + * ... + * ], + * after_all_case_hook: Function, + * after_each_case_hook: Function, + * before_all_case_hook: Function, + * before_each_case_hook: Function + * }, + * ... // More suites allowed + * }, + * after_all_suite_hook: Function; + * after_each_suite_hook: Function; + * before_all_suite_hook: Function; + * before_each_suite_hook: Function; + * } + * + * ... or ... + * + * { + * suites: { + * run(): { + * cases: [Array], + * after_all_case_hook: [Function], + * before_all_case_hook: [Function], + * before_each_case_hook: [Function], + * after_each_case_hook: [Function] + * }, + * close(): { + * cases: [Array], + * after_all_case_hook: [Function], + * before_all_case_hook: [Function], + * before_each_case_hook: [Function], + * after_each_case_hook: [Function] + * } + * }, + * before_each_suite_hook: [Function], + * after_each_suite_hook: [Function], + * after_all_suite_hook: [Function], + * before_all_suite_hook: [Function] + * } + */ +export interface ITestPlan { + suites: { + [key: string]: ITestSuite; // "key" is the suite name + }; + after_all_suite_hook?: Function; + after_each_suite_hook?: Function; + before_all_suite_hook?: Function; + before_each_suite_hook?: Function; +} + +/** + * @description + * cases? + * An array of objects matching the ITestCase interface. + * + * after_all_case_hook? + * A callback function to execute after all test cases. + * + * after_each_case_hook? + * A callback function to execute after each test case. + * + * before_all_case_hook? + * A callback function to execute before all test cases. + * + * before_each_case_hook? + * A callback function to execute before each test case. + */ +export interface ITestSuite { + cases?: ITestCase[]; + after_all_case_hook?: Function; + after_each_case_hook?: Function; + before_all_case_hook?: Function; + before_each_case_hook?: Function; +} + +/** + * @description + * name + * The name of the test case. + * + * new_name + * The new name of the test. This is strictly for outputting purposes. + * Deno's test runner outputs "test name of test" and we want to + * overwrite that text. This new_name string helps us do that. See + * formatTestCaseName() in mod.ts for more information. + * + * testFn + * The test function. Ultimately, this gets passed as the second + * argument of Deno.test(). + */ +export interface ITestCase { + name: string; + new_name: string; + testFn: Function; +} + diff --git a/src/test_case.ts b/src/test_case.ts index 1b336c7b..3acf3e94 100644 --- a/src/test_case.ts +++ b/src/test_case.ts @@ -1,12 +1,13 @@ const encoder = new TextEncoder(); +import { ITestPlan, ITestCase } from "./interfaces.ts"; /** * A class to help create uniform test case objects. */ export class TestCase { - protected plan: any; // TODO(ebebbington) Use Plan interface + protected plan: ITestPlan; - constructor(plan: any) { // TODO(ebebbington) Use Plan interface + constructor(plan: ITestPlan) { this.plan = plan; } @@ -16,7 +17,7 @@ export class TestCase { } Object.keys(this.plan.suites).forEach((suiteName) => { // Run cases - this.plan.suites[suiteName].cases.forEach(async (c: any) => { + this.plan!.suites[suiteName].cases!.forEach(async (c: ITestCase) => { // Run the case - required to run like this because the // hooks need to be ran inside the Deno.test call. Deno.test seems to queue // the tests, meaning all hooks are ran, and **then** the tests are ran @@ -28,17 +29,17 @@ export class TestCase { this.plan.before_each_suite_hook(); } if (this.plan.suites[suiteName].before_all_case_hook) { - this.plan.suites[suiteName].before_all_case_hook(); + this.plan.suites[suiteName].before_all_case_hook!(); } if (this.plan.suites[suiteName].before_each_case_hook) { - this.plan.suites[suiteName].before_each_case_hook(); + this.plan.suites[suiteName].before_each_case_hook!(); } await c.testFn(); if (this.plan.suites[suiteName].after_each_case_hook) { - this.plan.suites[suiteName].after_each_case_hook(); + this.plan.suites[suiteName].after_each_case_hook!(); } if (this.plan.suites[suiteName].after_all_case_hook) { - this.plan.suites[suiteName].after_all_case_hook(); + this.plan.suites[suiteName].after_all_case_hook!(); } if (this.plan.after_each_suite_hook) { this.plan.after_each_suite_hook(); diff --git a/tests/integration/hooks/after_all_test.ts b/tests/integration/hooks/after_all_test.ts index 99820225..d0852717 100644 --- a/tests/integration/hooks/after_all_test.ts +++ b/tests/integration/hooks/after_all_test.ts @@ -26,8 +26,8 @@ Rhum.testPlan("app_test.ts", () => { }); Rhum.testCase("Returns false", () => { // Assert the value has changes as the hook should have ran - Rhum.asserts.assertEquals(case_val, 2) - }) + Rhum.asserts.assertEquals(case_val, 2); + }); }); // Run the second test suite @@ -45,4 +45,4 @@ Rhum.testPlan("app_test.ts", () => { }); }); -Rhum.run(); \ No newline at end of file +Rhum.run(); diff --git a/tests/integration/hooks/after_each_test.ts b/tests/integration/hooks/after_each_test.ts index f5f9393b..afdad43b 100644 --- a/tests/integration/hooks/after_each_test.ts +++ b/tests/integration/hooks/after_each_test.ts @@ -26,8 +26,8 @@ Rhum.testPlan("app_test.ts", () => { }); Rhum.testCase("Returns false", () => { // Assert the value has changes as the hook should have ran - Rhum.asserts.assertEquals(case_val, 2) - }) + Rhum.asserts.assertEquals(case_val, 2); + }); }); // Run the second test suite @@ -45,4 +45,4 @@ Rhum.testPlan("app_test.ts", () => { }); }); -Rhum.run(); \ No newline at end of file +Rhum.run(); diff --git a/tests/integration/hooks/before_all_test.ts b/tests/integration/hooks/before_all_test.ts index 05e5c858..360c9006 100644 --- a/tests/integration/hooks/before_all_test.ts +++ b/tests/integration/hooks/before_all_test.ts @@ -23,12 +23,12 @@ Rhum.testPlan("app_test.ts", () => { suite_val = "Ed"; // Assert the value has changed from 22 to 2 Rhum.asserts.assertEquals(case_val, 2); - case_val = 22 + case_val = 22; }); Rhum.testCase("Returns false", () => { // Assert the value has changed from 22 to 2 (after setting it to 22 in the above case) - Rhum.asserts.assertEquals(case_val, 2) - }) + Rhum.asserts.assertEquals(case_val, 2); + }); }); // Run the second test suite @@ -45,4 +45,4 @@ Rhum.testPlan("app_test.ts", () => { }); }); -Rhum.run(); \ No newline at end of file +Rhum.run(); diff --git a/tests/integration/hooks/before_each_test.ts b/tests/integration/hooks/before_each_test.ts index f8e0016b..4367cca6 100644 --- a/tests/integration/hooks/before_each_test.ts +++ b/tests/integration/hooks/before_each_test.ts @@ -20,11 +20,11 @@ Rhum.testPlan("app_test.ts", () => { Rhum.asserts.assertEquals(suite_val, "Eric"); suite_val = "Ed"; Rhum.asserts.assertEquals(case_val, 2); - case_val = 22 + case_val = 22; }); Rhum.testCase("Returns false", () => { - Rhum.asserts.assertEquals(case_val, 2) - }) + Rhum.asserts.assertEquals(case_val, 2); + }); }); // Run the second test suite @@ -40,4 +40,4 @@ Rhum.testPlan("app_test.ts", () => { }); }); -Rhum.run(); \ No newline at end of file +Rhum.run(); diff --git a/tests/unit/mod_test.ts b/tests/unit/mod_test.ts index f10ddc26..58999362 100644 --- a/tests/unit/mod_test.ts +++ b/tests/unit/mod_test.ts @@ -54,8 +54,12 @@ Deno.test({ Deno.test({ name: "Unit | Rhum | testCase() | Runs a test without failing", async fn(): Promise { - Rhum.testCase("Testing testCase", () => { - console.log("Running!"); + Rhum.testPlan("test plan", () => { + Rhum.testSuite("test suite", () => { + Rhum.testCase("Testing testCase", () => { + console.log("Running!"); + }); + }); }); }, }); diff --git a/tests/unit/test_case_test.ts b/tests/unit/test_case_test.ts index 5a54ac0f..d0c9c83d 100644 --- a/tests/unit/test_case_test.ts +++ b/tests/unit/test_case_test.ts @@ -1,19 +1,22 @@ import { asserts } from "../../deps.ts"; import { TestCase } from "../../src/test_case.ts"; +import { ITestPlan } from "../../src/interfaces.ts"; Deno.test({ name: "Unit | TestCase | run() | Runs the test without failing", async fn(): Promise { - const plan = { - "suite_1": { - cases: [{ - name: "case_1", - new_name: "123 case_1", - testFn: function () { - asserts.assertEquals(true, true); - }, - }], - }, + const plan: ITestPlan = { + suites: { + "suite_1": { + cases: [{ + name: "case_1", + new_name: "123 case_1", + testFn: function () { + asserts.assertEquals(true, true); + }, + }], + }, + } }; const testCase = new TestCase(plan); await testCase.run();