Home

Awesome

<p align="center"> <img src="http://pixelartmaker.com/art/b5da8523654c61c.png" width="130px" /> <h3 align="center">Testing and Benchmarking framework for deno šŸ§™ā€ā™‚ļø</h3> </p> <p align="center"> <a href="https://github.com/crewdevio/merlin/issues"> <img alt="GitHub issues" src="https://img.shields.io/github/issues/crewdevio/merlin"> </a> <a href="https://github.com/crewdevio/merlin/network"> <img alt="GitHub forks" src="https://img.shields.io/github/forks/crewdevio/merlin"> </a> <a href="https://github.com/crewdevio/merlin/stargazers"> <img alt="GitHub stars" src="https://img.shields.io/github/stars/crewdevio/merlin"> </a> <a href="https://github.com/crewdevio/merlin/blob/master/LICENSE"> <img alt="GitHub license" src="https://img.shields.io/github/license/crewdevio/merlin"> </a> <a href="https://deno.land"> <img src="https://img.shields.io/badge/deno-%5E1.10.2-green?logo=deno"/> </a> <a href="https://nest.land/package/merlin"> <img src="https://nest.land/badge.svg" /> </a> <a href="https://deno.land/x/merlin"> <img src="https://img.shields.io/badge/available%20on-deno.land/x-blue.svg?style=flat&logo=deno"/> </a> </p>

Merlin

Merlin is a Jest-inspired testing framework for deno.

Using Matchers

Common Matchers

All Matchers

Statics

Install Merlin

install merlin-cli (optional)

deno install --allow-run -n merlin https://deno.land/x/merlin/cli.ts

Mirrors

you can get Merlin from different url.

import { Merlin } from "https://deno.land/x/merlin/mod.ts";
import { Merlin } from "http://denopkg.com/crewdevio/merlin/mod.ts";

Basic Use

simple assertions.

example.test.ts

import { Merlin } from "https://deno.land/x/merlin/mod.ts";

const test = new Merlin();

test.assertEqual("two plus two is four", {
  expect() {
    return 2 + 2;
  },
  toBe() {
    return 4;
  },
});

run this test in deno.

merlin start

or

deno test

you should see this output on the console.

running 1 tests
test two plus two is four ... ok (17ms)

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

Parameters

all assertions have parameters that they can receive, these parameters can change the behavior of the tests.

about resources and ops sanitizers

Certain actions in Deno create resources in the resource table . These resources should be closed after you are done using them.

For each test definition, the test runner checks that all resources created in this test have been closed. This is to prevent resource 'leaks'. This is enabled by default for all tests, but can be disabled by setting the sanitizeResources boolean to false in the test definition.

The same is true for async operation like interacting with the filesystem. The test runner checks that each operation you start in the test is completed before the end of the test. This is enabled by default for all tests, but can be disabled by setting the sanitizeOps boolean to false in the test definition.

async function writeSomething(): Promise<string> {
  const decoder = new TextDecoder("utf-8");
  Deno.createSync("./texts.txt");
  const Package = await Deno.readFileSync("./text.txt");
  await Deno.writeTextFile("./text.txt", "test");
  return decoder.decode(Package);
}

test.assertEqual("Leak resources test", {
  expect: async () => await writeSomething(),
  toBe: () => "test",
  only: true,
  Ops: false,
  Resources: false,
});
merlin start

test Leak resources test ... ok (5ms)

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Multiple tests

example.test.ts

test.evalEquals([
  {
    label: "object assignment",
    expect() {
      const data: any = { one: 1 };
      data["two"] = 2;

      return data;
    },
    toBe() {
      return { one: 1, two: 2 };
    },
  },
  {
    label: "two plus two is four",
    expect() {
      return 2 + 2;
    },
    toBe() {
      return 4;
    },
  },
]);

output

merlin start

running 2 tests
test object assignment ... ok (10ms)
test two plus two is four ... ok (1ms)

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

notEqual

example.test.ts

test.assertNotEqual("two plus two not is five", {
  expect() {
    return 2 + 2;
  },
  notBe() {
    return 4;
  },
});

output

merlin start

running 1 tests
test two plus two not is five ... FAILED (2ms)

failures:

two plus two not is five
AssertionError: actual: 4 expected: 4
    at assertNotEquals (https://deno.land/std/testing/asserts.ts:195:5)
    at fn (merlin.ts:105:9)
    at async asyncOpSanitizer ($deno$/testing.ts:34:5)
    at async Object.resourceSanitizer [as fn] ($deno$/testing.ts:68:5)
    at async TestRunner.[Symbol.asyncIterator] ($deno$/testing.ts:276:11)
    at async Object.runTests ($deno$/testing.ts:364:20)

failures:

        two plus two not is five

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (2ms)

stringContains

example.test.ts

test.stringContains("hello world contains world", {
  Contains: () => "world",
  value: () => "Hello World",
});
merlin start

test hello world contains world ... ok (8ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

fetchEqual

test.fetchEqual("fetch data", {
  url: "https://jsonplaceholder.typicode.com/todos/1",
  type: "json",
  toBe() {
    return { userId: 1, id: 1, title: "delectus aut autem", completed: false };
  },
});
merlin start

test fetch data ... ok (1440ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

testRegExp

test.assertRegExp("regEx match", {
  expect: () => "https://google.com",
  toBe: () => new RegExp("^https?://[a-z.]+.com$"),
});
merlin start

test regEx match ... ok (6ms)

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

Using async code.

you can use asynchronous code by adding async in expect, toBe and value functions.

example

const test = new Merlin();

test.assertEqual("get error 404", {
  async expect() {
    const response = await fetch("https://deno.land/std/example/examples.ts");

    const data = response.text();

    return data;
  },
  toBe() {
    return "404: Not Found";
  },
});

Note: all the methods of the merlin class support async function since they have top level await

merlin gif

Create benchmarks using Maven

Maven is a benchmark tool for deno included in Merlin.

It's easy to use. example:

import { Maven } from "https://deno.land/x/merlin/mod.ts";

Maven.Bench({
  name: "Sorting arrays",
  fn: () => {
    new Array(10000).fill(Math.random()).sort();
  },
  steps: 1000,
});

Maven.runBench();

this is the terminal output

gif

Parameters

maven receives the following parameters.

you can see the details at the end of the benchmark using

import { Maven } from "https://deno.land/x/merlin/mod.ts";

Maven.Bench({
  name: "Sorting arrays",
  fn: () => {
    new Array(10000).fill(Math.random()).sort();
  },
  steps: 1000,
});

Maven.runBench().then(Maven.Result());

It has a table with the detailed values

ā–’ā–’ā–’ā–’ā–’ā–’ā–’ā–’ Benchmarking finished

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
ā”‚    Benchmark name:  Sorting array                                                         ā”‚
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
ā”‚    Total runs: 1000   ā”‚  Total time: 1099.6591 ms    ā”‚  Avg time: 1.0997 ms               ā”‚
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
ā”‚    min: 0.7768 ms     ā”‚ max: 9.9867 ms     ā”‚ mean: 5.3817 ms     ā”‚ median: 0.8511 ms      ā”‚
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
ā”‚    Thresholds:  0 ========== 70 ========== 90 ========== āˆž                                ā”‚
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
ā”‚                               ā”‚                                                           ā”‚
ā”‚    0.7768 ms _[   965][96.5%] ā”‚========================================================   ā”‚
ā”‚    2.6188 ms _[    33][ 3.3%] ā”‚==                                                         ā”‚
ā”‚    4.4608 ms _[     1][ 0.1%] ā”‚=                                                          ā”‚
ā”‚    6.3027 ms _[     0][   0%] ā”‚                                                           ā”‚
ā”‚    8.1447 ms _[     1][ 0.1%] ā”‚=                                                          ā”‚
ā”‚                               ā”‚                                                           ā”‚
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Contributing

contributions are welcome, create a pull request and send us your feature, first check the CONTRIBUTING GUIDELINES.

LICENSE MIT