diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..6e4ce184 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contributing to Rhum + +## Bug Reports + +A bug is a *demonstrable problem* that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks! +If you want to report a bug, click [here](https://github.com/drashland/rhum/issues/new?assignees=&labels=bug&template=bug_report.md&title=). + +## Feature Requests +Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project developer of the merits of this feature. Please provide as much detail and context as possible. If you want to request a feature, click [here](https://github.com/drashland/rhum/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=). + +## Pull Requests + +Please **ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. + +1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork, and configure the remotes: + ```bash + # Clone your fork of the repo into the current directory + git clone https://github.com//rhum.git + # Navigate to the newly cloned directory + cd rhum + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/drashland/rhum.git + ``` +2. If you cloned a while ago, get the latest changes from upstream: + ```bash + git checkout master + git pull upstream master + ``` +3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix: + ```bash + git checkout -b + ``` +4. Push your topic branch up to your fork: + ```bash + git push origin + ``` +5. [Open a Pull Request](https://help.github.com/articles/about-pull-requests/) with a clear title and description against the `master` branch. + +***Note:*** It is recommended that you *"clean up"* your commits before opening a pull request. Maybe take a look at `git rebase --interactive` to do this. + +## Code Guidelines +- Code should follow [Deno Style Guide](https://deno.land/manual/contributing/style_guide). + +- As a rule of thumb, always format your code using `deno fmt` before opening your pull request. Run this as your last single commit. If you forgot to correctly format it, just add a commit with the message *deno fmt* (`git commit -m "deno fmt"`). + +## License +By submitting a patch, you agree to allow the project owners to license your work under the terms of the [MIT License](../LICENSE). + + diff --git a/.github/workflows/bumper.yml b/.github/workflows/bumper.yml new file mode 100644 index 00000000..8189ddc0 --- /dev/null +++ b/.github/workflows/bumper.yml @@ -0,0 +1,30 @@ +name: bumper +on: + schedule: + - cron: '0 0 * * *' + +jobs: + update-dep: + strategy: + matrix: + deno: ["1.1.1"] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Deno + uses: denolib/setup-deno@master + with: + deno-version: ${{ matrix.deno }} + + - name: Update Dependencies + run: deno run --allow-net --allow-read --allow-write https://deno.land/x/dmm/mod.ts update + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v2 + with: + token: ${{ secrets.CI_USER_PAT }} + commit-message: Update dependencies + title: Update dependencies + body: This was auto-generated by GitHub Actions. + branch: update-dependencies \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 03a6ac8d..1bb34d2d 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - deno: ["1.1.0"] + deno: ["1.1.1"] runs-on: ${{ matrix.os }} steps: @@ -27,6 +27,9 @@ jobs: - name: Unit run: deno test tests/unit + - name: Integration + run: deno test --allow-run tests/integration + linter: strategy: matrix: diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ee1cb515 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2020 the Rhum authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md index 1321307f..29ae0440 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Allows a test plan, suite, or case to be skipped when the tests run. ```typescript Rhum.testPlan("app_test.ts", () => { - Rhum.skip("run()", () => { // Will not run this block + Rhum.skip("run()", () => { // will not run this block Rhum.testCase("Returns true", () => { ... }); @@ -186,6 +186,9 @@ Rhum.testPlan("app_test.ts", () => { Rhum.testCase("Returns true", () => { ... }); + Rhum.skip("Returns true", () => { // will not run this block + ... + }); }); }); ``` @@ -312,9 +315,9 @@ A variety of hooks that can be run before or after test suites and cases. ## Why Use Rhum? -Rhum allows you to write tests in a very descriptive way, this could be from a code perspective, or output perspective. +Rhum allows you to write tests in a very descriptive way -- from a code perspective or output perspective. -Rhum is designed to aid in testing your projects, providing many utilities as wrappers around Deno's existing `Deno.test`. Rhum is meant to improve the user experience when it comes to writing tests, such as: +Rhum is designed to aid your testing efforts -- providing many utilities as wrappers around Deno's existing `Deno.test`. Rhum is meant to improve the user experience when it comes to writing tests, such as: - Readability for test cases - Features that aren't available in Deno yet (hooks) @@ -324,7 +327,7 @@ Rhum takes concepts from the following: * Mocha — For how you write tests in Rhum, and the use of hooks * Baretest — Being minimalistic -Rhum can be added directly into any project. All you need to do is import Rhum and you are ready to either start writing tests, and bring your existing tests under Rhum. +Rhum can be added directly into any project. All you need to do is import Rhum and you are ready to start writing tests or bring your existing tests under Rhum. ## Contributing diff --git a/deps.ts b/deps.ts index 9681a7a3..71c0d158 100644 --- a/deps.ts +++ b/deps.ts @@ -1,5 +1,7 @@ -export { ServerRequest } from "https://deno.land/std@v0.57.0/http/server.ts"; +export { ServerRequest } from "https://deno.land/std@v0.58.0/http/server.ts"; -export { BufReader } from "https://deno.land/std@v0.57.0/io/bufio.ts"; +export { BufReader } from "https://deno.land/std@v0.58.0/io/bufio.ts"; -export * as asserts from "https://deno.land/std@v0.57.0/testing/asserts.ts"; +export * as asserts from "https://deno.land/std@v0.58.0/testing/asserts.ts"; + +export * as colors from "https://deno.land/std@0.58.0/fmt/colors.ts"; diff --git a/mod.ts b/mod.ts index e38c2eac..340481a9 100644 --- a/mod.ts +++ b/mod.ts @@ -261,7 +261,7 @@ export class RhumRunner { if (this.test_plan_in_progress != this.passed_in_test_plan) { this.test_plan_in_progress = this.passed_in_test_plan; this.test_suite_in_progress = this.passed_in_test_suite; - newName = `${"\u0008".repeat(name.length + extraChars)}` + + newName = `${"\u0008".repeat(name.length + extraChars)}` + // strip "test " `${" ".repeat(name.length + extraChars)}` + `\n${this.passed_in_test_plan}` + `\n ${this.passed_in_test_suite}` + diff --git a/tests/integration/basic_test.ts b/tests/integration/basic_test.ts index 839c4698..02c9e42f 100644 --- a/tests/integration/basic_test.ts +++ b/tests/integration/basic_test.ts @@ -1,7 +1,7 @@ -import { asserts } from "../../deps.ts"; +import { asserts, colors } from "../../deps.ts"; /** - * To be clear, we are making sure that when a user runs their tests using Rhum, that everything works correctly, + * To be clear, we are making sure that when a user runs their tests using Bourbon, that everything works correctly, * and the output is correct */ @@ -10,21 +10,78 @@ Deno.test({ "Integration | basic_test.ts | Tests correctly pass and display the correct output", async fn(): Promise { const p = await Deno.run({ - cmd: [ - "deno test --allow-run example_tests/basic/tests_pass.ts", - ], + cmd: ["deno", "test", "--allow-run", "example_tests/basic/tests_pass.ts"], stdout: "piped", stderr: "piped", - cwd: ".", + env: { "NO_COLOR": "false" }, }); const status = await p.status(); p.close(); - const stdout = new TextDecoder().decode(await p.output()); const stderr = new TextDecoder().decode(await p.stderrOutput()); asserts.assertEquals(status.success, true); asserts.assertEquals(status.code, 0); - asserts.assertEquals(stderr, "TODO"); - asserts.assertEquals(stdout, "TODO"); + /** + * Due to the nature of this testing (running tests that run tests), the stderr is showing "Compiling .../.deno.ts.ts" - + * there doesn't seem be a way around it (yet), so what we are doing is just asserting it only contains that line, + * that way we can get these tests to work, and make sure no errors are thrown + */ + const splitStderr = stderr.split("\n"); // ["compiling ...", ""] + asserts.assertEquals(splitStderr.length, 2); + asserts.assertEquals(splitStderr[1], ""); + /** + * Because the timing for each test is dynamic, we can't really test it ("... ok (3ms)"), so strip all that out + */ + let stdout = new TextDecoder("utf-8") + .decode(await p.output()) + .replace(/\(\d+ms\)/g, ""); // (*ms) + /** + * There are also some odd empty lines at the end of the stdout... so we just strip those out + */ + stdout = stdout.substring(0, stdout.indexOf("filtered out") + 12); + const expectedResult = "running 22 tests\n" + + // Test plan 1 + "test test_case_1a1 ...  \n" + + "test_plan_1\n" + + " test_suite_1a\n" + + " test_case_1a1 ... ok \n" + + "test test_case_1a2 ...  test_case_1a2 ... ok \n" + + "test test_case_1a3 ...  test_case_1a3 ... ok \n" + + "test test_case_1b1 ...  test_suite_1b \n" + + " test_case_1b1 ... ok \n" + + "test test_case_1b2 ...  test_case_1b2 ... ok \n" + + "test test_case_1b3 ...  test_case_1b3 ... ok \n" + + // Test plan 2 + "test test_case_2a1 ...  \n" + + "test_plan_2\n" + + " test_suite_2a\n" + + " test_case_2a1 ... ok \n" + + "test test_case_2a2 ...  test_case_2a2 ... ok \n" + + "test test_case_2a3 ...  test_case_2a3 ... ok \n" + + "test test_case_2b1 ...  test_suite_2b \n" + + " test_case_2b1 ... ok \n" + + "test test_case_2b2 ...  test_case_2b2 ... ok \n" + + "test test_case_2c1 ...  test_suite_2c \n" + + " test_case_2c1 ... ok \n" + + "test test_case_2c2 ...  test_case_2c2 ... ok \n" + + "test test_case_2c3 ...  test_case_2c3 ... ok \n" + + "test test_case_2d1 ...  test_suite_2d \n" + + " test_case_2d1 ... ok \n" + + "test test_case_2d2 ...  test_case_2d2 ... ok \n" + + // Test plan 3 + "test test_case_3a1 ...  \n" + + "test_plan_3\n" + + " test_suite_3a\n" + + " test_case_3a1 ... ok \n" + + "test test_case_3a2 ...  test_case_3a2 ... ok \n" + + "test test_case_3b1 ...  test_suite_3b \n" + + " test_case_3b1 ... ok \n" + + "test test_case_3b2 ...  test_case_3b2 ... ok \n" + + "test test_case_3c1 ...  test_suite_3c \n" + + " test_case_3c1 ... ok \n" + + "test test_case_3c2 ...  test_case_3c2 ... ok \n" + + "\n" + + "test result: ok. 22 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out"; + asserts.assertEquals(stdout, expectedResult); }, }); @@ -36,14 +93,133 @@ Deno.test({ cmd: ["deno", "test", "--allow-run", "example_tests/basic/tests_fail.ts"], stdout: "piped", stderr: "piped", + env: { "NO_COLOR": "true" }, }); const status = await p.status(); p.close(); - const stdout = new TextDecoder().decode(await p.output()); const stderr = new TextDecoder().decode(await p.stderrOutput()); asserts.assertEquals(status.success, false); asserts.assertEquals(status.code, 1); - asserts.assertEquals(stderr, ""); - asserts.assertEquals(stdout, ""); + /** + * Due to the nature of this testing (running tests that run tests), the stderr is showing "Compiling .../.deno.ts.ts" - + * there doesn't seem be a way around it (yet), so what we are doing is just asserting it only contains that line, + * that way we can get these tests to work, and make sure no errors are thrown + */ + const splitStderr = stderr.split("\n"); // ["compiling ...", ""] + asserts.assertEquals(splitStderr.length, 2); + asserts.assertEquals(splitStderr[1], ""); + /** + * Because the timing for each test is dynamic, we can't really test it ("... ok (3ms)"), so strip all that out + */ + let stdout = new TextDecoder("utf-8") + .decode(await p.output()) + .replace(/\(\d+ms\)/g, ""); // (*ms) + /** + * There are also some odd empty lines at the end of the stdout... so we just strip those out + */ + stdout = stdout.substring(0, stdout.indexOf("filtered out") + 12); + /** + * And because the stdout is of the following format: + * + * running X tests + * ... + * + * failures: + * + * ... + * + * ... + * + * at Module.assertEquals(...) + * + * We can just break this up into segments, because we can't assert the filepaths in the error stack + */ + let splitStdout = stdout.split("failures:"); // [0] = the test case results, [1] = the start of the failures + const testCaseResults = splitStdout[0]; + const firstFailureResult = + splitStdout[1].split("at Module.assertEquals")[0]; // Output of failing on first test + const secondFailureResult = + splitStdout[1].split("at Object.runTests")[1].split( + "at Module.assertEquals", + )[0]; + const expectedTestCaseResult = "running 22 tests\n" + + // Test plan 1 + "test test_case_1a1 ...  \n" + + "test_plan_1\n" + + " test_suite_1a\n" + + " test_case_1a1 ... FAILED \n" + + "test test_case_1a2 ...  test_case_1a2 ... ok \n" + + "test test_case_1a3 ...  test_case_1a3 ... ok \n" + + "test test_case_1b1 ...  test_suite_1b \n" + + " test_case_1b1 ... ok \n" + + "test test_case_1b2 ...  test_case_1b2 ... ok \n" + + "test test_case_1b3 ...  test_case_1b3 ... FAILED \n" + + // Test plan 2 + "test test_case_2a1 ...  \n" + + "test_plan_2\n" + + " test_suite_2a\n" + + " test_case_2a1 ... ok \n" + + "test test_case_2a2 ...  test_case_2a2 ... ok \n" + + "test test_case_2a3 ...  test_case_2a3 ... ok \n" + + "test test_case_2b1 ...  test_suite_2b \n" + + " test_case_2b1 ... ok \n" + + "test test_case_2b2 ...  test_case_2b2 ... ok \n" + + "test test_case_2c1 ...  test_suite_2c \n" + + " test_case_2c1 ... ok \n" + + "test test_case_2c2 ...  test_case_2c2 ... ok \n" + + "test test_case_2c3 ...  test_case_2c3 ... ok \n" + + "test test_case_2d1 ...  test_suite_2d \n" + + " test_case_2d1 ... ok \n" + + "test test_case_2d2 ...  test_case_2d2 ... ok \n" + + // Test plan 3 + "test test_case_3a1 ...  \n" + + "test_plan_3\n" + + " test_suite_3a\n" + + " test_case_3a1 ... ok \n" + + "test test_case_3a2 ...  test_case_3a2 ... ok \n" + + "test test_case_3b1 ...  test_suite_3b \n" + + " test_case_3b1 ... ok \n" + + "test test_case_3b2 ...  test_case_3b2 ... ok \n" + + "test test_case_3c1 ...  test_suite_3c \n" + + " test_case_3c1 ... ok \n" + + "test test_case_3c2 ...  test_case_3c2 ... ok \n" + + "\n"; + asserts.assertEquals(testCaseResults, expectedTestCaseResult); + asserts.assertEquals( + firstFailureResult, + "\n" + + "\n" + + "test_case_1a1\n" + + "AssertionError: Values are not equal:\n" + + "\n" + + "\n" + + " [Diff] Actual / Expected\n" + + "\n" + + "\n" + + "- true\n" + + "+ false\n" + + "\n ", + ); + asserts.assertEquals( + secondFailureResult, + " ($deno$/testing.ts:358:20)\n" + + "\n" + + "test_case_1b3\n" + + "AssertionError: Values are not equal:\n" + + "\n" + + "\n" + + " [Diff] Actual / Expected\n" + + "\n" + + "\n" + + "- true\n" + + "+ false\n" + + "\n ", + ); + asserts.assertEquals( + stdout.indexOf( + "test result: FAILED. 20 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out", + ) >= 0, + true, + ); }, });