Testing

Unit test

Installation

All following examples are based on mocha + chai testing framework. Obviously, you can use another framework like Jasmine ! To install mocha and chai just run these commands:

npm install --save-dev mocha chai @types/mocha @types/chai
1

Usage

Ts.ED are bundled with a testing module @tsed/testing. This module provide to create new context and inject function to inject your Services, Controllers, Middlewares, etc... registered with annotation like .

The process to test any components is the same things:

  • Create a new context for your unit test with TestContext.create,
  • Inject or invoke your component with TestContext.inject or TestContext.invoke,
  • Reset the context with TestContext.reset.

Here an example to test the ParseService:

import {ParseService} from "@tsed/common";
import {inject, TestContext} from "@tsed/testing";
import {expect} from "chai";

describe("ParseService", () => {
  before(TestContext.create);
  after(TestContext.reset);
  describe("eval()", () => {
    it("should evaluate expression with a scope and return value", inject([ParseService], (parseService: ParseService) => {
      expect(parseService.eval("test", {
        test: "yes"
      })).to.equal("yes");
    }));
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Async / Await

Testing asynchronous method is also possible using Promises (async/await):

import {inject, TestContext} from "@tsed/testing";
import {expect} from "chai";
import {DbService} from "../services/db";

describe("DbService", () => {
  let result: any;
  before(TestContext.create);
  after(TestContext.reset);

  it("should data from db", inject([DbService], async (dbService: DbService) => {
    result = await dbService.getData();
    expect(result).to.be.an("object");
  }));
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Mock dependencies

TestContext API provide an invoke method to create a new instance of your component with mocked dependencies.

import {TestContext} from "@tsed/testing";
import {expect} from "chai";
import {MyCtrl} from "../controllers/MyCtrl";
import {DbService} from "../services/DbService";

describe("MyCtrl", () => {

  // bootstrap your Server to load all endpoints before run your test
  before(TestContext.create);
  after(TestContext.reset);

  it("should do something", async () => {
    const locals = [
      {
        provide: DbService,
        use: {
          getData: () => {
            return "test";
          }
        }
      }
    ];

    // give the locals map to the invoke method
    const instance: MyCtrl = await TestContext.invoke(MyCtrl, locals);

    // and test it
    expect(!!instance).to.eq(true);
    expect(instance.getData()).to.equals("test");
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

TIP

TestContext.invoke() execute automatically the $onInit hook!

Test your Rest API

Installation

To test your API, I recommend you to use the supertest module.

To install supertest just run these commands:

npm install --save-dev supertest @types/supertest
1

Example

import {ExpressApplication} from "@tsed/common";
import {bootstrap, inject, TestContext} from "@tsed/testing";
import {expect} from "chai";
import * as SuperTest from "supertest";
import {Server} from "../Server";

describe("Rest", () => {
  // bootstrap your Server to load all endpoints before run your test
  let request: SuperTest.SuperTest<SuperTest.Test>;

  before(bootstrap(Server));
  before(inject([ExpressApplication], (expressApplication: ExpressApplication) => {
    request = SuperTest(expressApplication);
  }));

  after(TestContext.reset);

  describe("GET /rest/calendars", () => {
    it("should do something", async () => {
      const response = await request.get("/rest/calendars").expect(200);

      expect(response.body).to.be.an("array");
    });
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Disable Logs

If you like to disable log output for any reason, you can do it by calling $log.level or $log.stop(). It's useful to suppress logging during unit tests runs so that your passed/failed test summary does not get polluted with information.

import { $log } from "ts-log-debug";

describe('A test that will not print logs :', () => {

    before(() => {
        $log.level = "OFF"
    });

    /* you tests here */
});
1
2
3
4
5
6
7
8
9
10

In addiction, you can use some library like Sinon and Chai-promised for your unit test. To help you, here the tools.ts code used by the unit test for Ts.ED: