Unit test in typescript by jest
Tags: jest, typescript, unittest
Published: 2020-04-01 06:37:37

## Mục lục
0. Vấn đề
1. Chuẩn bị
2. Unit testing là gì?
3. Jest là gì?
4. Config jest 
5. Demo nhẹ 
6. Kết bài


## 0. Vấn đề

***Heyzo what's up***

Xin chào tất cả mọi người, làm developer thì ai cũng phải viết **unit test** (Định nghĩa phần 2) phải không nào, bài viết này mình xin giới thiệu một package hỗ trợ viết **unit test** trong **javascript** rất hay ho đó là **jest**, mọi người cùng theo dõi nhé

> Mình sẽ config và demo **jest** trong typescript nhé, mong mọi người chú ý theo dõi

## 1. Chuẩn bị

- Editor (Mình đề xuất **VScode** nhé vì mình xài cái này)
- Nodejs
- Có sẵn một project viết bằng **typescript + expressjs nhé**
- **Jest** plugin (Hôm nay mình demo cái này)

Giờ thì, **let's go !!!**

## 2. Unit testing là gì?

Unit Test là một loại kiểm thử phần mềm trong đó các đơn vị hay thành phần riêng lẻ của phần mềm được kiểm thử. Kiểm thử đơn vị được thực hiện trong quá trình phát triển ứng dụng. Mục tiêu của Kiểm thử đơn vị là cô lập một phần code và xác minh tính chính xác của đơn vị đó.

Một Unit là một thành phần PM nhỏ nhất mà ta có thể kiểm tra được như các hàm (Function), thủ tục (Procedure), lớp (Class), hoặc các phương thức (Method).

> Các bạn đọc thêm ở [đây](https://topdev.vn/blog/unit-test-la-gi/)

## 3. Jest là gì 

> Jest is a delightful JavaScript Testing Framework with a focus on simplicity.

> It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!


Định nghĩa trên lấy từ [đây](https://jestjs.io/). Nếu ai xài **Mocha** rồi thì biết **jest** này tương tự về cách giải quyết vấn đề nha, nhưng **jest** tích hợp đầy đủ hơn không như **mocha** phải cài thêm **chai và sinon** nữa, các bạn xem thêm trên [đây](https://www.npmtrends.com/mocha-vs-jest) để so sánh khách quan nhé  

## 4. Config jest 

Cài đặt các **package** bằng lệnh dưới đây 

```
npm install --save-dev @types/jest jest ts-jest 
```

- **@types/jest** **type jest** trong **typescript** 
- **jest** package hỗ trợ viết **unit testing** 
- **ts-jest** hỗ trợ **jest** trong **typescript**

Vào trong project có sẵn về **typescript** ở **root project** tạo file **jest.config.js**

**jest.config.js** 
```js
module.exports = {
  "roots": [
    "<rootDir>/src"
  ], 
  // Xác định nơi bỏ các file testing 
  // Thông thuòng ra sẽ bỏ các file typescript vào hết thư mục src
  "testMatch": [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)"
  ], 
  // Jest sẽ dựa định dạng này để phát hiện các file 
  // cần được testing nhé
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest"
  }, 
  // Thằng ts-jest sẽ xác định các file có dạng này
  // Sau đó sẽ biến đổi về dạng nó có thể hiểu được
  // Để chạy jest
  "verbose": true,
  // Báo cáo các bài test lúc đang chạy 
  "globals": {
    "ts-jest": {
      diagnostics: false
    }
  }
  // Ồ ồ cái này cần à nghe, cái này để các hàm
  // của thằng jest trở thành globals
  // không cần phải require hay import khi dùng nữa
}
```

Giờ trong file **tsconfig.json** sẽ thêm một ít
ở **exclude** nó trông như vậy nè

**tsconfig.json**

``` json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "es6"
    ],
    "outDir": "./build",
    "resolveJsonModule": true,
    "strict": true,
    "types": [
      "reflect-metadata",
      "jest"            // Chú ý ở đây phải có cài này không file .ts sẽ báo lỗi 
    ],
    "esModuleInterop": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "exclude": [
    "node_modules", "**/*.spec.ts", "**/*.test.ts"
  ],
  "include": [
    "./src/**/*"
  ]
}
```

Rồi giờ để chạy được **test** thì mình sẽ thêm  tý ở file **package.json**

**package.json**

```
 "scripts": {
      ...
      "test": "jest --detectOpenHandles"
    },
```


Khi nào muốn chạy thì gõ **npm run test** là được nha, như vậy là phần **config** như xong, cây thư mục sẽ nhìn giống dưới đây nè ^^

```
└─── node_modules
└─── jest.config.js
└─── tsconfig.json
└─── package.json
│ 
└─── src
    └─── test
    └─── app.ts
```

## 5. Demo nhẹ 

describe("Filter function", () => {
Tạo một file **app.spec.ts** (hoặc **app.test.ts**) trong thư mục **test**, các hàm **test**, **describe** đều là **global** nãy mình đã **config** rồi nhé @-@

**app.spec.ts**

``` ts
import { filterByTerm } from '../app'

describe("Filter function", () => {
  test("it should filter by a search term (link)", () => {
    const input = [
      { id: 1, url: "https://www.url1.dev" },
      { id: 2, url: "https://www.url2.dev" },
      { id: 3, url: "https://www.link3.dev" }
    ];

    const output = [{ id: 3, url: "https://www.link3.dev" }];

    expect(filterByTerm(input, "link")).toEqual(output);
  });
});
```

Coppy đoạn code dưới đây vào **app.ts**

**app.ts**
``` ts
export function filterByTerm(inputArr : any , searchTerm: string){
    return inputArr.filter(function(arrayElement :any) {
      return arrayElement.url.match(searchTerm);
    });
}
```

Cấu trúc thư mục sẽ trông như vầy nhé 
```
└─── node_modules
└─── jest.config.js
└─── tsconfig.json
└─── package.json
│ 
└─── src
    └─── test
          └─── app.spec.ts
    └─── app.ts
```

Kết quả:
[<img src="https://i.imgur.com/6ThkADR.jpg">](https://i.imgur.com/6ThkADR.jpg/)


## 6. Kết bài

Vậy cũng đã hết bài rồi, hy vọng bài viết này sẽ giúp các bạn cài đặt được **jest** trong **typescript** để sử dụng nhé, cảm ơn và xin chào


#### Link tham khảo:
- https://topdev.vn/blog/unit-test-la-gi
- https://jestjs.io/
- https://www.npmtrends.com/mocha-vs-jest