mocha-typescript
Decorator based wrapper over mocha's interface.
It will read your decorators and call the appopriate
describe
, it
, timeout
, slow
, it.only
or it.skip
calls for you.
A class decorated with @suite
is considered suite.
Static before
and after
methods will be called before and after all tests.
A class instance will be created for each test.
Instance before
and after
methods will be called before and after each test.
A method decorated with @test
is considered a test.
Methods accepting done
callback or returning a Promise
instance are considered async.
For more information check the playground:
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
declare var Promise: any;
@suite("mocha typescript")
class Basic {
@test("should pass when asserts are fine")
asserts_pass() {
}
@test("should fail when asserts are broken")
asserts_fail() {
var error = new Error("Assert failed");
(<any>error).expected = "expected";
(<any>error).actual = "to fail";
throw error;
}
@test("should pass async tests")
assert_pass_async(done: Function) {
setTimeout(() => done(), 1);
}
@test("should fail async when given error")
assert_fail_async(done: Function) {
setTimeout(() => done(new Error("Oops...")), 1);
}
@test("should fail async when callback not called")
@timeout(100)
assert_fail_async_no_callback(done: Function) {
}
@test("should pass when promise resolved")
promise_pass_resolved() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 1);
});
}
@test("should fail when promise rejected")
promise_fail_rejected() {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Ooopsss...")), 1);
});
}
}
@suite class CuteSyntax {
@test testNamedAsMethod() {
}
@test "can have non verbose syntax for fancy named tests"() {
}
@test "and they can be async too"(done) {
done();
}
}
@suite class LifeCycle {
static tokens = 0;
token: number;
constructor() {
console.log(" - new LifeCycle");
}
before() {
this.token = LifeCycle.tokens++;
console.log(" - Before each test " + this.token);
}
after() {
console.log(" - After each test " + this.token);
}
static before() {
console.log(" - Before the suite: " + ++this.tokens);
}
static after() {
console.log(" - After the suite" + ++this.tokens);
}
@test one() {
console.log(" - Run one: " + this.token);
}
@test two() {
console.log(" - Run two: " + this.token);
}
}
@suite class Times {
@test @slow(10) "when fast is normal"(done) {
setTimeout(done, 0);
}
@test @slow(15) "when average is yellow-ish"(done) {
setTimeout(done, 10);
}
@test @slow(15) "when slow is red-ish"(done) {
setTimeout(done, 20);
}
@test @timeout(10) "when faster than timeout passes"(done) {
setTimeout(done, 0);
}
@test @timeout(10) "when slower than timeout fails"(done) {
setTimeout(done, 20);
}
}
@suite class ExecutionControl {
@skip @test "this won't run"() {
}
@test "this however will"() {
}
@test "add @only to run just this test"() {
}
}
class ServerTests {
connect() {
console.log(" connect(" + ServerTests.connection + ")");
}
disconnect() {
console.log(" disconnect(" + ServerTests.connection + ")");
}
static connection: string;
static connectionId: number = 0;
static before() {
ServerTests.connection = "shader connection " + ++ServerTests.connectionId;
console.log(" boot up server.");
}
static after() {
ServerTests.connection = undefined;
console.log(" tear down server.");
}
}
@suite class MobileClient extends ServerTests {
@test "client can connect"() { this.connect(); }
@test "client can disconnect"() { this.disconnect(); }
}
@suite class WebClient extends ServerTests {
@test "web can connect"() { this.connect(); }
@test "web can disconnect"() { this.disconnect(); }
}