From fc46ffb3f4f34f8d62b9ada125068f77530ea0ff Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Sun, 21 Jun 2020 21:22:15 -0400 Subject: [PATCH 1/7] use iplan interface; fix errors --- mod.ts | 56 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/mod.ts b/mod.ts index c15ab4e0..173a340b 100644 --- a/mod.ts +++ b/mod.ts @@ -54,26 +54,24 @@ import { TestCase } from "./src/test_case.ts"; 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; - }; +interface IPlan { + suites: { + [key: string]: { // suite names + cases?: Array<{ + name: string; + new_name: string; + testFn: Function; + }>; + after_all_case_hook: Function | null; + after_each_case_hook: Function | null; + before_all_case_hook: Function | null; + before_each_case_hook: Function | null; }; - after_all_suite_hook?: Function; - after_each_suite_hook?: Function; - before_all_suite_hook?: Function; - before_each_suite_hook?: Function; }; + after_all_suite_hook: Function | null; + after_each_suite_hook: Function | null; + before_all_suite_hook: Function | null; + before_each_suite_hook: Function | null; } /** @@ -131,7 +129,13 @@ 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: IPlan = { + suites: {}, + after_all_suite_hook: null, + after_each_suite_hook: null, + before_all_suite_hook: null, + before_each_suite_hook: null, + }; // FILE MARKER - METHODS - CONSTRUCTOR /////////////////////////////////////// @@ -268,6 +272,9 @@ export class RhumRunner { * @return void */ public testCase(name: string, testFn: Function): void { + // @ts-ignore + // TODO(crookse) figure out why this still give sthe "Object is possibly + // undefined" error even though we check if the object exists this.plan.suites[this.passed_in_test_suite].cases.push({ name, new_name: this.formatTestCaseName(name), @@ -289,9 +296,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 +312,13 @@ 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: [], + after_all_case_hook: null, + after_each_case_hook: null, + before_all_case_hook: null, + before_each_case_hook: null, + }; testCases(); } From e21e0f8b439f5c2db88488a79bf6afba612b335a Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Sun, 21 Jun 2020 21:23:03 -0400 Subject: [PATCH 2/7] fix unit test --- tests/unit/mod_test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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!"); + }); + }); }); }, }); From 5f41185f61e2f190749b26c302150d3bb4b54dd1 Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Mon, 22 Jun 2020 06:42:12 -0400 Subject: [PATCH 3/7] use bang --- mod.ts | 42 ++++++++------------- tests/integration/hooks/after_all_test.ts | 6 +-- tests/integration/hooks/after_each_test.ts | 6 +-- tests/integration/hooks/before_all_test.ts | 8 ++-- tests/integration/hooks/before_each_test.ts | 8 ++-- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/mod.ts b/mod.ts index 173a340b..6b493368 100644 --- a/mod.ts +++ b/mod.ts @@ -62,16 +62,16 @@ interface IPlan { new_name: string; testFn: Function; }>; - after_all_case_hook: Function | null; - after_each_case_hook: Function | null; - before_all_case_hook: Function | null; - before_each_case_hook: Function | null; + 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 | null; - after_each_suite_hook: Function | null; - before_all_suite_hook: Function | null; - before_each_suite_hook: Function | null; + after_all_suite_hook?: Function; + after_each_suite_hook?: Function; + before_all_suite_hook?: Function; + before_each_suite_hook?: Function; } /** @@ -129,13 +129,7 @@ export class RhumRunner { protected passed_in_test_suite: string = ""; protected test_plan_in_progress: string = ""; protected test_suite_in_progress: string = ""; - protected plan: IPlan = { - suites: {}, - after_all_suite_hook: null, - after_each_suite_hook: null, - before_all_suite_hook: null, - before_each_suite_hook: null, - }; + protected plan: IPlan = { suites: {} }; // FILE MARKER - METHODS - CONSTRUCTOR /////////////////////////////////////// @@ -163,7 +157,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; @@ -184,7 +178,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; @@ -205,7 +199,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; @@ -226,7 +220,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; @@ -275,7 +269,7 @@ export class RhumRunner { // @ts-ignore // TODO(crookse) figure out why this still give sthe "Object is possibly // undefined" error even though we check if the object exists - 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, @@ -312,13 +306,7 @@ export class RhumRunner { */ public testSuite(name: string, testCases: Function): void { this.passed_in_test_suite = name; - this.plan.suites[name] = { - cases: [], - after_all_case_hook: null, - after_each_case_hook: null, - before_all_case_hook: null, - before_each_case_hook: null, - }; + this.plan.suites![name] = { cases: [] }; testCases(); } 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(); From 1eea61c3c4ba48dc8c9372056aa4fd3e4a87145d Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Mon, 22 Jun 2020 07:00:48 -0400 Subject: [PATCH 4/7] store all interfaces in interfaces.ts; add descriptions --- mod.ts | 75 +--------------------------- src/interfaces.ts | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 73 deletions(-) create mode 100644 src/interfaces.ts diff --git a/mod.ts b/mod.ts index 6b493368..43637214 100644 --- a/mod.ts +++ b/mod.ts @@ -1,78 +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 IPlan { - 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 @@ -129,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: IPlan = { suites: {} }; + protected plan: ITestPlan = { suites: {} }; // FILE MARKER - METHODS - CONSTRUCTOR /////////////////////////////////////// diff --git a/src/interfaces.ts b/src/interfaces.ts new file mode 100644 index 00000000..a1c37ece --- /dev/null +++ b/src/interfaces.ts @@ -0,0 +1,125 @@ +/** + * @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. + * + * 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; +} + From 45b08bf6b1d02bfc6c2cb63645b9c68c7a5de7cb Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Mon, 22 Jun 2020 07:08:01 -0400 Subject: [PATCH 5/7] add reference to formatTestCaseName() --- src/interfaces.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index a1c37ece..985b3c14 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -111,7 +111,8 @@ export interface ITestSuite { * 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. + * 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 From 5555752d2f34f5c4870ba0d6f1377c3ec54f880c Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Mon, 22 Jun 2020 07:18:01 -0400 Subject: [PATCH 6/7] make changes based on code review --- src/test_case.ts | 15 ++++++++------- tests/unit/test_case_test.ts | 23 +++++++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) 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/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(); From fbaaa59bf1d6f53c16e3b4cccdde9c367883ec72 Mon Sep 17 00:00:00 2001 From: Eric Crooks Date: Mon, 22 Jun 2020 07:19:37 -0400 Subject: [PATCH 7/7] don't ignore, use bang --- mod.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mod.ts b/mod.ts index 43637214..f7a2ec98 100644 --- a/mod.ts +++ b/mod.ts @@ -195,10 +195,7 @@ export class RhumRunner { * @return void */ public testCase(name: string, testFn: Function): void { - // @ts-ignore - // TODO(crookse) figure out why this still give sthe "Object is possibly - // undefined" error even though we check if the object exists - 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,