Git Product home page Git Product logo

rhum's People

Contributors

crookse avatar drashbot avatar ebebbington avatar github-actions[bot] avatar guergeiro avatar littletof avatar lucacasonato avatar ze0tron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rhum's Issues

chore(v2): DRY fakes and mocks logic

Summary

What:

There is common logic between fakes and mocks. For example, they both use the PreProgrammedMethod class to allow .method(...).willReturn(...) and .method(...).willThrow(...).

Let's see if we can move the common logic to a common place so that we can DRY the fakes and mocks. Possible introduce another mixin that provides the common logic for both fakes and mocks? Idk how feasible that would be since fakes and mocks are already mixins, so we would have a mixin extend a mixin (insert xzibit meme here).

Why:

The common logic should be the same between fakes and mocks. The main difference between them is mocks can receive expectations and throw errors if those expectations aren't met. The common logic (e.g., pre-programmed methods, init call) can be DRY (I think).

Acceptance Criteria

All unit tests should pass without making any changes to them.

beforeAll() executes after each test case

Summary

Maybe I just don't understand the functionality of Rhum.beforeAll because I'm stupid, but it seems that the the function input into Rhum.beforeAll gets executed for every test case instead of just once before all testcases. If this really is how Rhum.beforeOnly, then I would like for this to be changed to having the function that is input into Rhum.beforeAll be executed once before all test cases, as this is the convention of most other Javascript/Typescript testing frameworks. beforeAll vs beforeEach

Steps To Reproduce The Bug

Consider the following typescript file:

// blah.ts
import { Rhum } from 'https://deno.land/x/[email protected]/mod.ts';

Rhum.testPlan('foo', () => {
    Rhum.testSuite('bar', () => {
        let i = 0;
        Rhum.beforeAll(() => {
            console.log('In beforeAll, the value of i is ' + i);
            i++;
        });

        Rhum.testCase('inch', () => {
            Rhum.asserts.assertEquals(1, 1);
        });

        Rhum.testCase('time', () => {
            Rhum.asserts.assertEquals(1, 1);
        });

        Rhum.testCase('foot', () => {
            Rhum.asserts.assertEquals(1, 1);
        });

        Rhum.testCase('gem', () => {
            Rhum.asserts.assertEquals(1, 1);
        });
    });
});

Rhum.run();

If we run the command deno test --allow-env blah.ts, how many times does the function input into Rhum.beforeAll get executed?
blah

Expected Behavior

I would like the function input into Rhum.beforeAll to be executed ONE time before all test cases, not once for every test case.

ServerRequest Mock: Incorrectly Setting Content Length

Describe the bug
When setting a FormData object to the body, mocks.ServerRequest tries to get the length (assumes it's a string) of it to set as the content type.

To Reproduce
Steps to reproduce the behavior:

const request = Rhum.mocks.ServerRequest("/", "get", {
  body: new FormData
})

See error when compiled

Expected behavior
Should not error and (ideally) set the content length another way

Suggested Solution(s)
Unsure

feat(v2): mock.expects(...).toBeCalledWith(...)

Summary

What:

Add method to mocks where we can do the following:

const mock = Mock(MyClass).create();

mock.expects("someMethod").toBeCalled(1).toBeCalledWith("hello");

mock.verifyExpectations(); // Should verify the following:
// 1. someMethod() was called once
// 2. someMethod() was called with "hello". For example, someMethod("hello")

Why:

Users should be able to verify that a method was called with specific arguments to further verify correct behavior.

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

  • Write documentation
  • Write unit tests
  • Write integration tests

Suggestion: Make it QUnit API

Summary

Hi there, I've just had a look into this project and I'm maintaining a different testing tool in node.js. I'll soon investigate moving the tool to deno. I've also read the blog post to see your motivation on building this tool. Thank you for building it, I might also use your code as reference/example.

I highly suggest that you move the library API to QUnit API: https://api.qunitjs.com/QUnit/module/#hooks-on-nested-modules . I suspect this achieves the same thing and would really help rest of the community to use a shared testing API/tools eventually.

Also, another suggestion: you can make the tool output in TAP - Test Anything Protocol by default so people can write their own custom reporters.

Rhum.mock doesn't track nested method calls

Summary

See comment from Discord:

Screen Shot 2022-02-21 at 7 53 02 PM

Root Cause

The issue is with this block of code in mock_builder.ts#create():

        mock[method] = function (...args: unknown[]) {
          mock.calls[method]++;
          return (original[method as keyof T] as unknown as (
            ...params: unknown[]
          ) => unknown)(...args);
        };

The above code turns every method in an object into a method that can track itself. For example:

add(number: string) { ... }

becomes

function(...args: unknown) {
  mock.calls["add"]++;
  return add(...args);
}

In the problematic block, there is this:

          return (original[method as keyof T] as unknown as (
            ...params: unknown[]
          ) => unknown)(...args);

This makes each method being mocked call the ORIGINAL object's method. So, what's happening in this issue is:

  1. <real object>.add() is replaced with the wrapper function that can track calls via mock.calls[method]++
  2. mock.add() is called
  3. mock.add() calls mock.calls["add"]++ and mock.calls.add === 1 now
  4. mock.add() calls the original version of itself
  5. the original version of mock.add() calls the original version of realAdd()
  6. the original version of realAdd() doesn't have mock.calls["realAdd"]++, so mock.calls.realAdd === 0

Example test code

import { Rhum } from "https://deno.land/x/[email protected]/mod.ts";

class MathService {
  realAdd(num1: number, num2: number): number {
    return num1 + num2;
  }
  add(num1: number, num2: number): number {
    return this.realAdd(num1, num2);
  }
}

const mock = Rhum.mock(MathService).create();

Rhum.asserts.assertEquals(mock.calls.realAdd, 0);

// Since this calls `.readAdd()`, we expect `mock.calls.realAdd` to be `1` below, but it is not
mock.add(1, 1);

// Should be 1, not 0
Rhum.asserts.assertEquals(mock.calls.realAdd, 1);

Rhum.run()

Video Tutorial - Stubs/Mocks

Summary

What: Video tutorial (acts of visual documentation) for how to use Rhum mocks and stubs, what they are - essentially the documentation but in a video. Though it's open to whoever takes on this issue how they'd like to do the video and what content it will have.

Could be useful to include in the description of the video, times of topics, eg:

0:00 - introduction
0:23 - what are rhum stubs
5:10 - creating a. stub

Why: Supports visual learners, and thus creates another platform for people to understand Rhum stubs and mocks and how to use it - further enforcing "documentation driven"

Information

  • OBS can be used as the software to screenshare and video recording

  • Includes the drashland introduction? (speak to @crookse)

  • Includes the Rhum logo with the greenish background as the thumbnail

  • Video can be added to a "Rhum" playlist (can also be created if it doesn't exist)

  • Make it chill :)

feat(v2): support node

Summary

What:

We have 0 deno std deps now. We can compile down to JS and have Rhum be usable in Node. We can take Accio and Moogle as guides to compile types and to compile down to ESM and CJS. Might need to use a combination of deno bundle and tsc. Not sure yet, but I know supporting Node is doable now.

Why:

Make Rhum available to a wider audience

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

Hooks

What

Develop the following hooks:

  • Rhum.beforeAll
  • Rhum.beforeEach
  • Rhum.afterAll
  • Rhum.afterEach
  • Rhum.before?
  • Rhum.after?

All methods should be public

Why
This is a testing framework dammit!

Checklist

  • Update README where needed

  • Unit & integration tests

Resources

Use the following issue as a guideline if possible

Pseudo-code for Implementation

Nothing to provide as of yet

After hooks aren't ran if test case fails

NOTE: Because we wrap the test case in a try/catch, if it errors, that assetion error is never actually thrown, we may need to save it and call it after the hooks

Summary

When using after hooks, and a test case fails, the after hooks are not executed

Steps To Reproduce The Bug

  1. Create a test plan and suite
  2. Create a test case that throws an error
  3. Create an afterAll hook that logs a message
  4. Run test, the message from the hook wont be logged

Expected Behavior

The after hooks should be ran because they are cleanup functions, they should be ran even if the test case fails

Suggested Solution(s)

The hook attached fn in test_case.ts should do something like

// all the before hook logic as usual

let errorMsg = ""
try {
  await t.testCase()
} catch (_e) {
  errorMessage = _e.message
}
  
// after hooks logic as usual

// And because we caught any assertion errors, we need to throw them
if (errorMessage) {
  throw new AssertionError(errorMessage)
}

afterAll runs after first test case, not after last

Summary

Rhum.afterAll defined in a test suite seems to run after the first Rhum.testCase in a suite, rather than after the last.

Steps To Reproduce The Bug

  1. Run deno test --allow-env https://gist.githubusercontent.com/lucacasonato/e7dfab6be1575e30d559fc416eb3b45e/raw/2e412062e972dcb53693770924f664fb84edd26b/rhum_test.ts
  2. See that following output is output:
running 3 tests
           
rhum_test.ts
    suite 1
        a ... Running beforeAll
initalized
Running afterAll
ok (205ms)
        b ... torn down
ok (102ms)
        c ... torn down
ok (103ms)

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (411ms)

Expected Behavior

running 3 tests
           
rhum_test.ts
    suite 1
        a ... Running beforeAll
initalized
ok (205ms)
        b ... initalized
ok (102ms)
        c ... initalized
Running afterAll
ok (103ms)

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (411ms)

Ability to test non-public members

Summary

What: I've found in testing that there is sometimes a need to invoke a non-public member. We should make a function that makes non-public members public.

Why: Sometimes I'll find that I need to test a non-public method or check a non-public property. Adding the ability to "rewire" a class and make its members public would be useful in testing. For example, you could test that a public method calls a protected method. The public method basically covers the protected method, but what if you want to test protected method as its own unit?

Acceptance Criteria

  • New Rhum function to make protected members public
  • Tests
  • Documentation

Video Tutorial - General

Summary

What: Video tutorial (acts of visual documentation) for how to use Rhum, and how it works on certain level. It's open to whoever takes on this issue how they'd like to do the video and what content it will have. But there will be other issues to address hooks, and stubs/mocks

Could be useful to include in the description of the video, times of topics, eg:

0:00 - introduction
0:23 - what is Rhum
5:10 - creating tests

Why: Supports visual learners, and thus creates another platform for people to understand Rhum and how to use it - further enforcing "documentation driven"

Information

  • OBS can be used as the software to screenshare and video recording

  • Includes the drashland introduction? (speak to @crookse )

  • Includes the Rhum logo with the greenish background as the thumbnail

  • Video can be added to a "Rhum" playlist (can also be created if it doesn't exist)

  • Make it chill :)

feat: mock.toBeCalledWithArgs(...)

Summary

What:

Spies have .verify(...).toBeCalledWithArgs(...). Mocks should use this logic in the .expects(...) method chaining.

Why:

Would be nice to create an expectation on a mock that a method was called with args.

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

  • Write documentation
  • Write unit tests
  • Write integration tests

Example Pseudo Code (for implementation)

const mock = Mock(...).create();

mock.expects("someMethod").toBeCalledWithArgs(...);

mock.verifyExpectations();

feat: mock.toBeCalledWithoutArgs()

Summary

What:

Spies have .verify(...).toBeCalledWithoutArgs(). Mocks should use this logic in the .expects(...) method chaining.

Why:

Would be nice to create an expectation on a mock that a method was called with args.

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

  • Write documentation
  • Write unit tests
  • Write integration tests

Example Pseudo Code (for implementation)

const mock = Mock(...).create();

mock.expects("someMethod").toBeCalledWithoutArgs();

mock.verifyExpectations();

CLI --ignore option

Summary

What: Add --ignore option that takes in directories or files

Why: If someone had a tests/data directory and wanted to run all tests in their tests/ directory, then currently the rhum command would try to test the files in tests/data, which would throw errors. It'd be nice to ignore any directories or files that shouldn't be tested.

Acceptance Criteria

  • Add --ignore subcommand option
    • Ignores files
    • Ignores directories
    • Should be usable as follows: --ignore=dir,dir, --ignore=dirs, --ignore=test1.ts,test2.ts, --ignore=test1.ts
  • Tests
  • Documentation

Mocking object with constructorArgs as non-primitive value crashes MockBuilder

Summary

Following Rhum docs (Mock Constructor Arguments) it seems that providing array as a parameter to withConstructorArgs crashes MockBuilder.

Steps To Reproduce The Bug

When mocking

export class Logger {
  public constructor(types: string[] = []) {
    ...
  }
}

so that:
const logger = Rhum.mock(Logger).withConstructorArgs('types', ['info']).create()

throws the following error:

TypeError: Cannot read property 'value' of undefined
    at https://deno.land/x/[email protected]/src/mock_builder.ts:57:30
    at Array.forEach (<anonymous>)
    at MockBuilder.create (https://deno.land/x/[email protected]/src/mock_builder.ts:55:37)
    at Object.testFn (file:///home/gwozniak/SIMPLY/simply-careers-mono/src/server/__tests__/services/logger.test.ts:18:79)

Rhum:

   // Attach all of the original's properties to the mock
    this.getAllProperties(original).forEach((property: string) => {
      const desc = Object.getOwnPropertyDescriptor(original, property);
      mock[property] = desc!.value; // Line marked <<<
    });

Expected Behavior

Rhum.mock() builds an instance of the mocked object.

Ability to assert what arguments a method was called with

Summary

What: Now, that there are stubs and mocks, it would be great if we could check with what argument they were called with.

Why: It helps to check correct behaviour and it exists in other frameworks too. eg: Jasmine's toHaveBeenCalledWith

Acceptance Criteria

  • Ability to check and test arguments of a previously called stub and/or mock method

Example Pseudo Code (for implementation)

Will have to figure out where it should be accessed from.

Maybe mock.calls.methodToTest should return an object with { count: number, lastArgs: any[]}, but it would change current signature.

Or maybe mock.calls.args.methodToTest but than if there is a method named args it would cause problems

Rhum.testPlan("My Plan", () => {
  Rhum.testSuite("My Suite", () => {
    Rhum.testCase("My Test Case", () => {
      const mock = Rhum
        .mock(Server)
        .withConstructorArgs("arg1", "arg2", "arg3") // this call optional
        .create();

      mock.methodToTest("arg1", 15, null);
      Rhum.asserts.assertEquals(mock.calls.methodToTest.count, 1);
      Rhum.asserts.assertEquals(mock.calls.methodToTest.lastArgs, ["arg1", 15, null]);
    });
  });
});

feat(fake/mock): allow pre-programming methods with callbacks

Summary

What:

Allow the following ...

describe("...", () => {
  it("...", () => {
    const mockFiveService = Mock(TestObjectFiveServiceMultipleArgs)
      .create();

    const mockFive = Mock(TestObjectFiveMultipleArgs)
      .withConstructorArgs(mockFiveService)
      .create();

    assertEquals(mockFive.is_mock, true);
    assertEquals(mockFiveService.is_mock, true);

    mockFiveService
      .method("get")
      .willReturn((key: string, defaultValue: number | string) => {
        if (key == "host" && defaultValue == "localhost") {
          return null;
        }

        if (key == "port" && defaultValue == 5000) {
          return 4000;
        }

        return undefined;
      });

    // `false` because `mockFiveService.get("port") == 3000`
    assertEquals(mockFive.send(), false);

    mockFiveService
      .method("get")
      .willReturn((key: string, defaultValue: string | number) => {
        if (key == "host" && defaultValue == "localhost") {
          return "locaaaaaal";
        }

        if (key == "port" && defaultValue == 5000) {
          return 4000;
        }

        return undefined;
      });

    // `true` because `mockFiveService.get("port") != 3000`
    assertEquals(mockFive.send(), true);
  });
});


class TestObjectFiveMultipleArgs {
  private readonly service: TestObjectFiveServiceMultipleArgs;

  public constructor(service: TestObjectFiveServiceMultipleArgs) {
    this.service = service;
  }

  public send(): boolean {
    const host = this.service.get<string>("host", "localhost");
    const port = this.service.get<number>("port", 5000);

    if (host == null) {
      return false;
    }

    if (port === 3000) {
      return false;
    }

    return true;
  }
}

class TestObjectFiveServiceMultipleArgs {
  #map = new Map<string, unknown>();
  public get<T>(key: string, defaultValue: T): T {
    return this.#map.get(key) as T ?? defaultValue;
  }
}

Why:

Screen Shot 2022-12-11 at 00 48 42

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

Example Pseudo Code (for implementation)

// Add example pseudo code for implementation

How do I mock database calls in my endpoint

Summary

I have the following method that is used for an endpoint. It looks something like this:

export const endpointMethod: HandlerFunc = async (c: Context): Promise<any> => {
    const database = db.getDatebase("database");

    const collection = database.collection<Collection>("collection");

    const insertedEntry = await collection.insertOne({
      timestamp: new Date()
    });
};

What is the best way to mock the functions used here? Therefore, db.getDatebase(), database.collection(), and collection.insertOne(); From the docs it seems like I can only mock the methods if I pass e.g. the db object to the endpointMethod, but this isn't really an option here since the endpoint can't take additional arguments. And that would but a bit ugly ๐Ÿ˜…

Real-time results

Summary

What: Currently, Rhum doesn't display PASS / SKIP / FAIL results in real time.

Why: Debugging works best if the results are displayed in real time especially for async ops so that console.log() calls can be used and seen without having to wait for a test plan to finish running.

Acceptance Criteria

  • Results are in real time or close to real time

Script to Generate Test file

Summary

What: A script that would generate a test file, with the basic structure to start writing a test, using https://laravel.com/docs/7.x/dusk#generating-tests as the inspiration for this idea

Why: Think it would be a good idea, to provide some sort of CLI for Rhum?

Acceptance Criteria

  • Add acceptance criteria as bulleted list

Example Pseudo Code (for implementation)

// Add example pseudo code for implementation

Skip: Show Ignored in Output?

Note: it might not be possible with how. we use Deno.test. Maybe we could add custom output outselves to say it was skipped (but it might still show as OK), or (and i really dont want to do this), change our Deno.test signature to Deno.test({name: ..., ignore: ..., async fn() ...})

Summary

What: Modify the skip method in RhumRunner so it stills calls Deno.test, but ignore: true is passed in. This would probably require a change to ITestCase to set if a test should be ignored. Defaults to false

Why: I think it would be good that the user would see the test is being ignored (like now deno test currently displays it)

Acceptance Criteria

  • Skipped tests would show as ignored in the output (all tests inside a skipped suite, all tests inside a skipped plan, etc)
  • Unit tests for .skip method
  • Integration test for using skip: tests/integration/skip.ts

Example Pseudo Code (for implementation)

// run()

Deno.test(..., { ignore: test.ignore })

// skip
public skip (name, fn) {
  if (this.is_a_test) {
    this.tests.push(..., ignore: true)
  else if this.passed_in_test_suite // skipped a suite
    this.skipped_suites.push(name)
  else // plan
    this.skip_plan = true

// somewhere else
this.plan.suites.foreach
  suite.cases.foreach
    if this.skipped_suites.indexOf(suite.name)
      case.ignore =. true
    if this.skip_plan === true
      cas.eignore = true

Rhum.only()

What

Develop the following method:

  • Rhum.only

Method should be public and should tell Rhum to only run that test plan/suite/case under the parent. For example:

  • If 1 suite of 2 is set to only under a plan, then the suite that doesnt have only should be skipped

Why
This is a testing framework dammit!

Checklist

  • Update README where needed

  • Unit & integration tests

Resources

Use the following issue as a guideline if possible

Pseudo-code for Implementation

All we have for information at the moment

Needs to account for plan/suite/case, and Rhum/RhumRunner should know that there is only one to test

Rhum.only: function (name: string, fn: Function) {
}

Rhum v2.0 (Release Date: TBD)

Tasks

  • CLI options (#74)
  • Script to generate test file (#44)
  • Mock not taking arguments (#28)
  • Ability to assert what arguments a method was called with (#21)
  • Skip functionality (#16)
  • real-time results (#78)
  • make subcommand (#44)
  • Ability to test non-public members (#19) (Won't do. Users should use the Reflect API.)
  • --ignore option (#82) (Logic is no longer needed. run command checks files for Rhum namespace now.)
  • Rhum lifecycle diagram (#81)
  • Documentation (https://github.com/drashland/website/issues/227)
    • Add v2.0 docs
    • Add migration guide
    • Archive v1.0 docs, but let it be accessible through an Archive section

Turn rhum into purely a mocking module

Summary

Because of how the testrunner for deno is changing, they offer 90% of what rhum does, meaning Rhum will soon become obsolete

It's also worth checking if theres already mocking libraries out there. If there is, can we do it better? if not, is it worth keeping rhum (sad face)?

Cannot use a tsconfig.json with Rhum

Summary

Unable to use a tsconfig with rhum, using the following lib options: dom, deno.ns

Steps To Reproduce The Bug

  1. Import rhum into a file
  2. Create a ttsconfig with:
{
  "compilerOptions": {
    "lib": ["dom", "deno.ns"]
  }
}
  1. Run file with config
  2. See errors
  3. Remove rhum dep
  4. Run again
  5. See no errors

Expected Behavior

Should be able to use a tsconfig

Suggested Solution(s)

Update std dependencies (master is updated, it just needs to be released)

Change JSDoc to TSDoc

Summary

What: Convert JSDoc blocks (though we use a mix of JSDoc and Deno's standard), to TSDoc blocks in Typescript files

Why: We primarily use TypeScript so it makes sense to use TSDoc. Types are already documented in the method/property anyways.

Acceptance Criteria

  • All doc blocks converts to TSDoc

Example Pseudo Code (for implementation)

* @param string filename
*        The filename to do something with

* @param filename - The filename to do something with

Resources

TSDoc is very similar, there is really only a few minor changes to make to each doc block

https://github.com/microsoft/tsdoc

Mocked object doesn't process mixin class getter/setter

Summary

The getter and setter defined in the mixin class is not processed.
The mock see that property as undefined.

Steps To Reproduce The Bug

import { Rhum } from "https://deno.land/x/[email protected]/mod.ts";
import { assertInstanceOf } from "https://deno.land/[email protected]/testing/asserts.ts";

export interface IGame {}

export class NullGame implements IGame {}

function WithGameProperty() {
  return <T extends new (...args: any[]) => any>(GameProperty: T) => {
    return class extends GameProperty {
      private game: IGame = new NullGame();

      public set Game(game: IGame) {
        this.game = game;
      }

      public get Game() {
        return this.game;
      }
    };
  };
}

const PlayersEngine = WithGameProperty()(
  class PlayersEngine {
    onNextGenerationReady(listener: () => void): void {
      // add listener to react on an event
    }

    prepareNextGeneration(): void {
      // do some stuff and trigger an event
    }
  },
);

const pe = new PlayersEngine();
const mpe = Rhum.mock(PlayersEngine).create();

assertInstanceOf(pe.Game, NullGame);
assertInstanceOf(mpe.Game, NullGame);

Expected Behavior

It will pass last line in the code above without an error.

Mock Not Taking Arguments

Describe the bug
Need to investigate this further and replicated, but mocking an object doesn't seem to return function with the params. See screenshot below

To Reproduce
Steps to reproduce the behavior:

  1. See screenshot below. Update this section once investigated

Expected behavior
A mock should be returned that acts the same as the method that was mocked

Suggested Solution(s)
A list of suggested solutions to try/implement.

Screenshots

From discord:

image

Rhum.asserts has no autocompletion

Description

When using the "shortcut" Rhum.asserts to build assertions we don't get intellisense support.

To Reproduce

Steps to reproduce the behavior:

  1. Import Rhum v1.1.4
  2. Attempt to access auto completion for Rhum.asserts
  3. Notice nothing relevant will show up
  4. If you type the correct function name the assertion will still work as expected

Expected behavior

I expected to get autocompletion support, the same we have for all Rhum ๐Ÿ˜…

Suggested Solution(s)

I've been able to "export" functions with autocompletion by using a interface + a const that complied to that interface.

This is the snippet that worked for me. However those functions are declared inside my module so I'm not sure if this would work for mapping Deno.test calls.

/**
 * Default functions for creating primitives with Dixture.
 */
export const dixtureFns: GenerationFunctions = {
  BigInt: createBigInt,
  Bool: createBoolean,
  Number: createNumber,
  String: createString,
  NamedString: <T>(prefix: keyof T) => createString(prefix.toString()),
  Int: () => createNumber(true),
  FutureDate: () => createDate(),
  PastDate: () => createDate(false),
};

The whole snippet can be found here

The following test suites also replicate the error (as of version v1.1.4 at least): dixture unit tests. Note: I attempted to get that autocompletion to work on deps.ts and on the other files as well. No such luck.

Screenshots

The following show my attempts to get some suggestions for Rhum.asserts

rhum asserts
Code_1QnTwHE7Z3
Code_Tr1GabVEKy
Code_yKemxoFi3p

Desktop

  • OS: Windows 10 2004
  • Version v1.1.4
  • IDE: VsCode 1.49.1 w/ Deno.Land extension
  • Deno Version: 1.4.0

Mocked Class with Request param (Fetch Request Interface) throws TypeError for undefined method

Given a Class that takes a Request object as param :

export class Router {
  constructor() {}

  async handle(request: Request): Promise<string|Error> {
    const method = request.method.toLowerCase();
    const contentType = request.headers.get("Content-Type")

    if (method !== "post")
      throw TypeError(`Must use Post method only, found ${method} instead.\n\n`);

    if (contentType !== "application/json") 
      throw TypeError(`content-type must be application/json, found ${contentType} instead`);

    ......

And a test...

Rhum.testCase("should validate request body with json schema validator", async () => {
      const req = new Request("http://localhost:8080", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify(fakeData)
      })

      const router = Rhum.mock(Router).create()

      Rhum.asserts.assertEquals(router.calls.handle, 0)
      Rhum.asserts.assertEquals(await router.handle(req), true)

I get the following TypeError and I do not understand why:

TypeError: Cannot read properties of undefined (reading 'method')
    at Router.handle (file:///home/rags2riches-prog/artbanx/shipment-service/x-shipment-service/router.ts:11:28)
    at Object.mock.<computed> [as handle] (https://deno.land/x/[email protected]/src/mock_builder.ts:84:24)
    at Object.testFn (file:///home/rags2riches-prog/artbanx/shipment-service/x-shipment-service/test/router.test.ts:113:46)
    at hookAttachedTestFn (https://deno.land/x/[email protected]/src/test_case.ts:74:21)
    at https://deno.land/x/[email protected]/src/test_case.ts:112:21
    at asyncOpSanitizer (deno:runtime/js/40_testing.js:35:15)
    at resourceSanitizer (deno:runtime/js/40_testing.js:72:13)
    at exitSanitizer (deno:runtime/js/40_testing.js:99:15)
    at runTest (deno:runtime/js/40_testing.js:232:13)
    at Object.runTests (deno:runtime/js/40_testing.js:317:28)
  • Notice that it isn't my guard against the method or content-type that throws
  • I have tried to test the request itself (for thuthyness) in my class method but it does not change much; I still get a TypeError (this time is from my code) as if the Request object passed in the Mocked Class loses the context of the Request and does not attach the properties "method" and "content-type" to it.

Is this the expected behaviour or is it a bug?

I expect the test to fail but because of the characterization here:

Rhum.asserts.assertEquals(await router.handle(req), true) // <= true should give me the output of the request as failed test

chore: After verifying the calls the counts don't decreased

Verifying the calls doesn't decreased the counts

Hello there I'm really fan of your library and I wish I help you improving it,
So I found this problem

What is the problem

I was writing unit test,
and while writing the first test it works fine and as expected,
but after writing the second test it was behaving wrongly, I got confused, and I did some the debug and found that the counts doesn't decreased after passing the first unit test

let me explain with the code

const mock = Mock(Collection).create(); // create a mock
const userDao = new UserDAO(mock);

Deno.test("test saving user throws UnAbleToWriteDatabase",
    async () => {
        mock.method("insertOne").willReturn(Promise.reject("saS"));

        try {
            await userDao.addUser(userMockObject);
            throwExceptionIfTestReachHere();
        } catch (e) {
            assertOfType(e, UnableToWriteOnDatabase);
        }
        mock.expects("insertOne").toBeCalled(1);
        mock.verifyExpectations();
    }
);

the previous code works fine

but If I write another test EVEN IT'S THE SAME CODE IT WILL FAILS

Deno.test("test saving user throws UnAbleToWriteDatabase",
    async () => {
        mock.method("insertOne").willReturn(Promise.reject("saS"));

        try {
            await userDao.addUser(userMockObject);
            throwExceptionIfTestReachHere();
        } catch (e) {
            assertOfType(e, UnableToWriteOnDatabase);
        }
        mock.expects("insertOne").toBeCalled(1); // HERE THE ERROR WILL HAPPENED 
        mock.verifyExpectations();
    }
);

The exception will be
error: Error: Method "insertOne" expected 1 call(s), but received 2 call(s).
throw new MockError(

that means that the counts doesn't decreased after verifying (I tried the other verifying way and it's the same)

As I said I'm really big fan of your library. All Lucks

chore(v2): clean up mock tests

Summary

What:

The mock tests have some unit tests that aren't grouped (the last 3 or something). They should be put into a group for better test result output. There is a TODO in mock_test.ts line 283.

Why:

Because the test output is ugly IMHO and we should make it somewhat pretty ๐Ÿ’€

Acceptance Criteria

No changes in behavior. Just move the tests.

[v2] Rhum Lifecycle Diagram

Summary

What: Make a Rhum Lifecycle Diagram like the Drash Lifecycle Diagram.

Why: Drash's internals are pretty transparent through documentation and the lifecycle diagram. It'd be good to keep this practice up for Rhum.

Acceptance Criteria

  • Lifecycle diagram showing how the internals work in Rhum (there may need to be multiple diagrams showing --filter-test-case and --filter-test-suite options being used)
  • Add lifecycle diagram to documentation
  • Should use Lucid Chart so that the diagram theme matches Drash's

test: error classes

Summary

What:

Test that the error classes are being thrown as expected and show their names/stack traces as expected.

Why:

Stabilization effort

feat(v2): spies

Summary

What:

Add Spy() to mod.ts

Definition from https://martinfowler.com/bliki/TestDouble.html:

Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

Why:

So we can have all five test doubles.

Acceptance Criteria

See #162 TODO list

feat: set arg expectations on methods

Summary

What:

Test double methods that can set up to return values should have arg expectations defined as well.

Why:

It's common to set up a method like "expect this method to take in this arg and return this value"

Acceptance Criteria

Below is a list of tasks that must be completed before this issue can be closed.

  • Write documentation
  • Write unit tests
  • Write integration tests

Example Pseudo Code (for implementation)

fake.method("blah").withArgs("hello").willReturn("world");

Stubs

What

Develop the following method:

  • Rhum.Stub

Method should be public and should return a stubbed method (like the one passed in) that should be able to tell the user if it was called

Why
This is a testing framework dammit!

Checklist

  • Update README where needed

  • Unit tests

  • Maybe integration tests? Feel unit tests cover it fully

Resources

Use the following issue as a guideline if possible

Pseudo-code for Implementation

Stub: function (fn: Function): Function {
}

// Maybe used like so:
// Maybe something along the lines of:
let functionWasCalled = false;
function testFn() {
  functionWasCalled = true;
  return "Hello world!";
}
const copyTestFn = testFn;
Rhum.TestPlan("Testing TestCase", copyTestFn);
asserts.assertEquals(functionWasCalled, true);

Make `deno lint` pass

Summary

What: If you run deno lint, we will most likely have a whole bunch of errors. This issue to fix these errors by correctly formatting code, and abiding by Deno's standards

Why: It would be good to make sure the code follows either: Deno's best practices, coding standards, or general best practices. It's a Deno project so it makes sense to utilise their tools on making the code Deno-like

Acceptance Criteria

  • deno lint is added to the master.yml CI, as a new block (similar to how we use deno fmt --check)
  • deno lint produces no errors

Resources

Deno Lint Documentation

Video Tutorial - Hooks

Summary

What: Video tutorial (acts of visual documentation) for how to use Hooks in Rhum. Though it's open to whoever takes on this issue how they'd like to do the video

Could be useful to include in the description of the video, times of topics, eg:

0:00 - introduction
0:23 - what are hooks
5:10 - creating hooks

Why: Supports visual learners, and thus creates another platform for people to understand Rhum hooks and how to use it - further enforcing "documentation driven"

Information

  • OBS can be used as the software to screenshare and video recording

  • Includes the drashland introduction? (speak to @crookse)

  • Includes the Rhum logo with the greenish background as the thumbnail

  • Video can be added to a "Rhum" playlist (can also be created if it doesn't exist)

  • Make it chill :)

v2.0: CLI options

Summary

What: The CLI should accept options

Why: Options are useful when using a CLI, especially a --help option when using the CLI.

Acceptance Criteria

  • --help: Shows a help menu on how to use the CLI
  • --filter-type: Tells --filter what to execute. Defaults to case.
    • Accepts "suite"
    • Accepts "case"
    • Example: rhum --filter-type suite --filter myTestSuite
  • --filter: Executes a single test suite or test case based on --filter-type
    • Example: rhum --filter myTestCase
  • --filter-test-case="someTestCase" {dir/file}
  • --filter-test-suite="someTestSuite" {dir/file}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.