The modern TypeScript testing framework.

What is Testy.Ts?

Testy.Ts is a modern TypeScript testing framework.

Installation

To install Testy.Ts, run one of the following lines.
$ npm i --save-dev testyts // To install locally
$ npm i -g testyts // To install globally

Setup

To generate a testy.json configuration file, use the following command.
$ testyts init
Testy.Ts requires experimentalDecorators. To use breakpoints while debugging in Visual Studio Code, you must enable sourceMap.
{
  "compilerOptions": {
      "target": "es5",
      "experimentalDecorators": true,
      "sourceMap": true
  }
}

Writing your first test

Writing tests with Testy.Ty is simple. Don't forget to export your test suites. Otherwise, they won't be discovered by the test runner.
@TestSuite()
export class MyTestSuite { 

    @Test()
    quickMaths() {
        expect.toBeEqual(1 + 1, 2);
    }
}

Run those tests

To run your Testy.Ts tests, simply run the following command. Testy.Ts uses the "testy.json" file contained in the current directory by default. Testy.Ts will fail if there is no such file.
$ testyts
$ testyts --config ./config.json // Custom config file

Setup and teardown methods

Testy.Ts provides setup and teardown hooks.
@TestSuite()
export class MyTestSuite {
  
    @BeforeAll()
    beforeAll() {
        // This is executed before all the tests
    }
  
    @BeforeEach()
    beforeEach() {
        // This is executed before each test
    }
  
    @AfterEach()
    afterEach() {
        // This is executed after each test
    }
    
    @AfterAll()
    afterAll() {
        // This is executed after all the tests
    }
}

Base test suites

This is where stuff gets interesting. Testy.Ts lets you use inheritance. This means you don't have to duplicate complex setup, teardown and helper functions. You also don't have to put all of your tests in the same class.
class MyBaseTestSuite {
    // Setup, teardown and helpers extravaganza
}
  
@TestSuite()
class MyTestSuite extends MyBaseTestSuite {
    // My tests
}

Asynchronous stuff

Asynchronous tests, setup and teardown methods are supported out of the box. Just make your method async.
@TestSuite()
export class MyTestSuite {

    @Test()
    async asyncTest() {
        // Asynchronous stuff       
    }
}

Timeouts

If a test is taking too long to complete, it will fail automatically. The default timeout it 2000 ms, but you can configure it.
@TestSuite()
export class MyTestSuite {
    @Test(undefined, undefined, 10000) // Really slow test
    slowTest() {
        // Some test
    }
}

Testcases

Testy.Ts allows you to run the same test multiple times with different inputs and expectations. Just pass an array of TestCase to the Test decorator.

A TestCase consists of a name and one or more arguments. The arguments are passed to your test method.
@TestSuite()
export class MyTestSuite {

    @Test('My test', [
          new TestCase('Two plus two is four', 2, 2, 4),
          new TestCase(`Minus one that's three`, 4, -1, 3)
    ])
    onePlusOne(a: number, b: number, result: number) {
        expect.toBeEqual(a + b, result);
    }
}

Asserting

Testy.Ts comes with a whole bunch of assertion methods and also a dash of syntactic sugar sexyness.
expect.toBeTrue(2 > 1);
expect.toBeEqual('a', 'a');
expect.not.toBeEqual('p', 'np');
expect.toThrow(() => someNastyMethod());
expect.toBeSorted.inAscendingOrder([0, 1, 1, 2, 3, 5, 8]);
// More!

Focusing and ignoring tests

You can ignore tests by adding an X before a test suite or a specific Test decorator. Ignored tests will still show up in the test report, but they will be marked as ignored.
@XTestSuite() // This test suite will be ignored
export class MyTestSuite { 
  // My tests
}
  
@TestSuite()
export class MyTestSuite {

    @XTest() // This test will be ignored
    onePlusOne() {
        // Some test
    }
}
You can also focus tests by adding an F before a test suite or a specific Test decorator. If one or more test or test suites are focused, only those will be ran. The others will be reported as ignored.
  @FTestSuite() // This test suite will be focused
  export class MyTestSuite { 
    // My tests
  }
    
  @TestSuite()
  export class MyTestSuite {
  
      @FTest() // This test will be focused
      onePlusOne() {
          // Some test
      }
  }

Custom test names

The tests and test suites names are inferred from the method or class name by default. You can specify a custom name if you're into that.
@TestSuite('My glorious test suite')
export class MyTestSuite {
  
    @Test('Adding one plus one, should equal two')
    onePlusOne() {
        // Assert
        expect.toBeEqual(1 + 1, 2);
    }
}

Still not convinced?

Here's a REPL you can use to play around with Testy.Ts online, no strings attached.