JSX

a faster, safer, easier JavaScript
Powered by Oktavia

Unit Test

Introduction

JSX has a built-in test runner invoked by --test option and has an unit test framework test-case.jsx. The unit test framework is an xUnit style, running _Test#test*():void of the given file.

Here is a simple test file, which is typically placed in t/ of a project.

import "test-case.jsx";

class _Test extends TestCase {
  function testAdd() : void {
    this.expect(1 + 2).toBe(3);
    this.expect(1 + 3).toBe(4);
  }
}

To run the test file, invoke jsx --test test.jsx, and you will see a TAP output like:

1..1
  ok 1
  ok 2
  1..2
ok 1 - testAdd

NOTE: it is recommended to use prove(1) to run tests and parse TAP, which can run test files in parallel. See .proverc and and Makefile in the mizuki project.

Synchronous Test

Synchronous testing is really simple, where you just define test methods, which are invoked in serial.

For example, the folowing test class calls testFirst(), testSecond(), testThird() in this order.
import "test-case.jsx";

class _Test extends TestCase {
  function testFirst() : void {
    this.expect(1 + 2).toBe(3);
  }
  function testSecond() : void {
    this.expect(1 + 3).toBe(4);
  }
  function testThird() : void {
    this.expect(1 + 4).toBe(5);
  }
}

Asynchronous Test

test-case.jsx supports asynchronous tests to test callback-based methods, such as Timer.setTimeout().

An asynchronous test starts with this.async() method, taking a block with an AsyncContext instance, and telling it that the test is done.

import "test-case.jsx";

class _Test extends TestCase {
  function testSetTimeout() : void {
    this.async(function(async : AsyncContext) : void {
      var to = 200;
      var t0 = Date.now();
      Timer.setTimeout(function() : void {
        var t1 = Date.now();

        this.expect(t1 - t0, "setTimeout 200 ms.").toBeGE(to - 50);

        async.done(); // to tell this test is finished
      }, to);
    }, 1000 /* timeout in milliseconds */);
  }
}

Set Up / Tear Down

You can define setUp() / tearDown() which are called for each test method to manage test environments.

These methods take no arguments for synchronous test methods, while take an AsyncContext for asynchronous test methods.

import "test-case.jsx";

// for synchronous test
class _Test extends TestCase {
  override function setUp() : void {
    this.diag("setUp");
  }
  override function tearDown() : void {
    this.diag("tearDown");
  }

  function testFoo() : void {
    this.pass("foo");
  }
  function testBar() : void {
    this.pass("bar");
  }
}
import "test-case.jsx";
import "timer.jsx";

// for asynchronous test
class _Test extends TestCase {
  override function setUp(async : AsyncContext) : void {
    this.diag("setUp for " + async.name());
  }
  override function tearDown(async : AsyncContext) : void {
    this.diag("tearDown for " + async.name());
  }

  function testFooAsync() : void {
    this.async((async) -> {
      Timer.setTimeout(() -> {
        this.pass("foo");
        async.done();
      }, 1);
    }, 1000);
  }

  function testBarAsync() : void {
    this.async((async) -> {
      Timer.setTimeout(() -> {
        this.pass("bar");
        async.done();
      }, 1);
    }, 1000);
  }
}

Misc.

jsx --test can takes test method names to run specific tests in a file. When you use jsx.vim you can run the currently editing test method by \t.

See Also