TypeScript + Mocha/Chai 非同期テストコードメモ

## 非同期処理をテストするための動作するコード。
TypeScriptでMocha/Chaiを使ったテストを書こうとして、非同期処理の結果をテストするのに苦労したので、動作したコードをシンプルにして書き残しておきます。

### 実行環境
今回の環境のpackage.jsonの抜粋します。

```json
"dependencies": {
    "@types/chai": "^4.2.11",
    "@types/mocha": "^7.0.2",
    "@types/node": "^14.0.13",
    "chai": "^4.2.0",
    "mocha": "^8.0.1",
    "ts-node": "^8.10.2",
    "typescript": "^3.9.5"
}
```
---

### テストの終了時のthenやcatchでdone()を呼んで結果を報告するパターン。
* テストコードではpromiseはリターンしない。
* テストパスでdone(\<falsey値\>), テスト失敗でdone(\<falsey以外の値\>)を呼ぶことで結果を報告する。
* thenでパスのパターンと、catchでパスの2パターンをサンプルにした。

```typescript
describe("非同期テスト 1 - done()で結果を報告。", () => {
  it(`promise will be resolved 1000ms later`, (done) => {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("timed out");
      }, 1000);
    });
    promise
      .then((v) => {
        expect(v).equal("timed out");
        done();
      })
      .catch((e) => {
        done("TEST FAILED");
      });
  });
  it(`promise will be rejected 1000ms later`, (done) => {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject("timed out");
      }, 1000);
    });
    promise
      .then(() => {
        done("TEST FAILED");
      })
      .catch((e) => {
        expect(e).to.equal("timed out");
        done();
      });
  });
});
```
ちゃんと想定通りの結果になります。

```bash
  非同期テスト 1 - done()で結果を報告。
    ✓ promise will be resolved 1000ms later (1005ms)
    ✓ promise will be rejected 1000ms later (1000ms)
```
---
### テスト内でawaitにより非同期処理の終了を待つパターン。
* テストコードでpromiseはリターンしない。
* テストコードでdoneは呼ばない。
* assertやexpectで結果を検証・報告する。
* try節が成功してパスのケースと、catch節が実行されてパスとなる2ケースをサンプルにした。

```typescript
describe("非同期テスト 2 - awaitで待つ", () => {
  it(`await for 1000ms. awaiting success.`, async () => {
    try {
      const v = await timerToResolve();
      expect(v).to.equal("timed out");
    } catch (e) {
      assert.fail();
    }
  });
  it(`await for 1000ms. awaiting exception.`, async () => {
    try {
      await timerToReject();
      assert.fail();
    } catch (e) {
      expect(e).to.equal("timed out");
    }
  });
});

// 1秒後にresolveされるpromiseを返す関数。
function timerToResolve():Promise<string> {
  return new Promise((resolve, reject) => {
    setInterval(() => {
      resolve("timed out");
    }, 1000);
  });
}
// 1秒後にrejectされるpromiseを返す関数。
function timerToReject():Promise<string> {
  return new Promise((resolve, reject) => {
    setInterval(() => {
      reject("timed out");
    }, 1000);
  });
}
```
こちらも想定通りの結果になります。

```bash
  非同期テスト 2 - awaitで待つ
    ✓ await for 1000ms. awaiting success. (1002ms)
    ✓ await for 1000ms. awaiting exception. (1002ms)
```

---
### テストコードがpromiseを返すパターン。
* テストコードでpromiseをリターンする。
* テストコードでdoneは呼ばない。
* 返すpromiseの中でthenやcatchの中で、assertやexpectで結果を検証・報告する。

```typescript
escribe("非同期テスト 3 - promiseを返す", () => {
  it(`should resolve the promise.`, () => {
    return timerToResolve().then((v) => {
      expect(v).equals("timed out");
    }).catch(() => {
      assert.fail();
    });
  });
  it(`should reject the promise.`, () => {
    return timerToReject().then(() => {
      assert.fail();
    }).catch((e) => {
      expect(e).equals("timed out");
    });
  });
});
```

結果です。

```bash
 非同期テスト 3 - promiseを返す
    ✓ should resolve the promise. (1009ms)
    ✓ should reject the promise. (1002ms)
```