Testing Your Deno Apps With Mocha
Tags: deno, tutorial, typescript, testing
Published: 2020-06-04 08:42:52

[Deno](https://deno.land/) comes with it's own [minimal testing framework](https://deno.land/manual/testing) built-in which is super handy for getting off the ground with testing.

```ts
import add from "./add.ts";
import { expect } from "https://deno.land/x/expect@v0.2.1/mod.ts";

Deno.test("should add two numbers", () => {
  expect(add(1, 2)).toEqual(3);
});
```

However, if you are used to using popular testing frameworks such as [Jest](https://jestjs.io/), [Mocha](https://mochajs.org/) etc. then you are out of luck. The Deno testing API doesn't current support mainly of the rich testing features you are used to such as `beforeEach` hooks, `describe` blocks etc.

So while `Deno.test` is great for small PoCs and getting started, it might not be what you're looking for as your functionality becomes more complicated and evolved. It also isn't the easiest setup to convert tests to if you are looking to migrate an existing Node project.

This is where Deno's ability to run ESM browser code natively comes into it's own. The likes of [Mocha](https://mochajs.org/) have [browser support](https://mochajs.org/#running-mocha-in-the-browser) meaning that you can immediately pull Mocha into your Deno projects right now and it'll work as you're used to! :tada:

Here's a simple example to get you started:

```ts
/**
 * First we import Mocha and it's type definitions.
 */
// @deno-types="https://unpkg.com/@types/mocha@7.0.2/index.d.ts"
import "https://unpkg.com/mocha@7.2.0/mocha.js";
/**
 * Here I'm using the Deno `expect` library, but you can use
 * any assertion library - including Deno's std testing library.
 * See: https://deno.land/std/testing
 */
import { expect } from "https://deno.land/x/expect@v0.2.1/mod.ts";

/**
 * Callback on completion of tests to ensure Deno exits with
 * the appropriate status code. 
 */
function onCompleted(failures: number): void {
  if (failures > 0) {
      Deno.exit(1);
  } else {
      Deno.exit(0);
  }
}

/**
 * Browser based Mocha requires `window.location` to exist.
 */
(window as any).location = new URL("http://localhost:0");

/**
 * In order to use `describe` etc. we need to set Mocha to `bdd`
 * mode.
 * 
 * We also need to set the reporter to `spec` (though other options
 * are available) to prevent Mocha using the default browser reporter
 * which requires access to a DOM.
 */
mocha.setup({ ui: "bdd", reporter: "spec" });

/**
 * Ensure there are no leaks in our tests.
 */
mocha.checkLeaks();

/**
 * Our example function under test
 */
function add(a: number, b: number): number {
  return a + b;
}

/**
 * We write our tests as usual!
 */
describe("add", () => {
  it("should add two positive numbers correctly", () => {
    expect(add(2, 3)).toEqual(5);
  });
});

/**
 * And finally we run our tests, passing the onCompleted function
 * hook and setting some globals.
 */
mocha.run(onCompleted).globals(["onerror"])
```

And that's it! You can now run the file and you should see something like:

```console
$ deno run ./mocha.ts

This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.


  add
    ✓ should add two positive numbers correctly


  1 passing (3ms)
```

There's a small warning due to the most recent version of Mocha making use of buffer v5 which requires full typed array (Uint8Array) support which Deno does not yet have, but otherwise our test has run and passed as expected!

We can check that it fails as well by making the following change:

```ts
describe("add", () => {
  it("should add two positive numbers correctly", () => {
    expect(add(2, 3)).toEqual(10); // Should fail!
  });
});
```

And the result is:

```console
$ deno run ./mocha.ts

This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.


  add
    1) should add two positive numbers correctly


  0 passing (47ms)
  1 failing

  1) add
       should add two positive numbers correctly:
     AssertionError: expect(actual).toEqual(expected)

-   5
+   10
      at applyMatcher (https://deno.land/x/expect@v0.2.1/expect.ts:102:23)
      at Proxy.<anonymous> (https://deno.land/x/expect@v0.2.1/expect.ts:109:15)
```

And it's failed as expected :tada:

You're not just limited to Mocha, you can use exactly the same techniques to pull in [Chai](), [Sinon]() and any other library that has browser support. If you want to see an example of how this is used in a large Deno project, check out [denolib/typeorm](https://github.com/denolib/typeorm/tree/master/test/deps).

---

How are you testing your Deno code? Have any suggestions to improve test setup that are worth sharing? Share your comments, questions and ideas in the section below - great to hear what everyone is doing!

Happy testing! 🦕 🚀