DEV Community

Craig Morten
Craig Morten

Posted on • Edited on

Testing Your Deno Apps With Mocha

Deno comes with it's own minimal testing framework built-in which is super handy for getting off the ground with testing.

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);
});
Enter fullscreen mode Exit fullscreen mode

However, if you are used to using popular testing frameworks such as Jest, Mocha 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 have browser support meaning that you can immediately pull Mocha into your Deno projects right now and it'll work as you're used to! 🎉

Here's a simple example to get you started:

/**
 * 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"])
Enter fullscreen mode Exit fullscreen mode

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

$ 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)
Enter fullscreen mode Exit fullscreen mode

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:

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

And the result is:

$ 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)
Enter fullscreen mode Exit fullscreen mode

And it's failed as expected 🎉

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.


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! 🦕 🚀

Top comments (8)

Collapse
 
ahugginsnhs profile image
Aaron Huggins

Hey Craig,

Thought you might be interested, you inspired me to write a library for this. Built out a super-simple CLI for it, too, and using for running deno tests on cbor-redux.

github.com/ahuggins-nhs/deno_mocha

Istanbul's nyc is probably next, if I can crack that or you know anyone who has.

Collapse
 
craigmorten profile image
Craig Morten

This is awesome! Nice one 😄

Collapse
 
terkwood profile image
Felix Terkhorn

Nice to see the successful transplant of a big name browser utility!

Collapse
 
leonardorocha profile image
Leonardo C.A.Rocha

Thanks so much, this is very useful. With powerful tests there's almost no need for a debugger!

Collapse
 
ynwd profile image
ynwd

any info on the use of code coverage in deno?

Collapse
 
craigmorten profile image
Craig Morten

Hey @ynwd 👋

I'm not 100% sure r.e. code coverage using Mocha - most people tend to use Istanbul for coverage with Mocha, but I'm not familiar with a browser-only compatible setup (i.e. no Node) - there appears to be an issue with some useful details on the Instanbul GitHub Issues with may be of use? There may be other 3rd party libs that can perform in browser code coverage that are compatible with Mocha which would then likely also work with Deno.

With respect to Deno itself, from what I've heard code coverage is currently being worked on - check out Deno GitHub Issue. Some PoCs have been done already (e.g. see here). There is also this PR which is still in draft and slated for the Deno 1.4.0 release which will add a --coverage flag to the deno test command so fingers crossed built-in coverage support may be released over the next few months.

Collapse
 
hardy613 profile image
Scott Hardy

deno test --coverage --unstable :)))

Collapse
 
lu4 profile image
Denis Yaremov