Jest の watch モードで Visual Studio Code のデバッガーを一瞬で再起動させる方法

![npm test の結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/650e20fb-2b80-1b08-b232-6cce26e23346.png)
![ブレーク](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/2bbe0ec6-c28a-b0ef-15a3-50857e394107.png)

  - [デバッガーを起動するのに時間がかかる問題](#デバッガーを起動するのに時間がかかる問題)
  - [Jest を速くする watch モードとデバッガーに接続するしくみ](#jest-を速くする-watch-モードとデバッガーに接続するしくみ)
  - [起動が早い Jest + TypeScript のテストコードのプロジェクトを作ってみる](#起動が早い-jest--typescript-のテストコードのプロジェクトを作ってみる)
    - [Node.js をインストールします](#nodejs-をインストールします)
    - [Visual Studio Code をインストールします](#visual-studio-code-をインストールします)
    - [プロジェクトを新規作成します](#プロジェクトを新規作成します)
      - [Visual Studio Code で新しいフォルダー try_jest を開きます](#visual-studio-code-で新しいフォルダー-try_jest-を開きます)
      - [__Project__/package.json ファイルを作ります](#projectpackagejson-ファイルを作ります)
      - [必要な Node モジュールをインストールします](#必要な-node-モジュールをインストールします)
      - [__Project__/tsconfig.json ファイルを作ります](#projecttsconfigjson-ファイルを作ります)
      - [__Project__/src/lib.ts ファイルを作ります](#projectsrclibts-ファイルを作ります)
      - [__Project__/src/lib.test.ts ファイルを作ります](#projectsrclibtestts-ファイルを作ります)
    - [Jest のウォッチモードを起動して Visual Studio Code と接続します](#jest-のウォッチモードを起動して-visual-studio-code-と接続します)
    - [デバッガーに接続して失敗したテストをデバッグします](#デバッガーに接続して失敗したテストをデバッグします)
    - [テストを再起動します](#テストを再起動します)
      - [プログラムがブレーク中のとき](#プログラムがブレーク中のとき)
      - [プログラムが実行中で終わらないとき](#プログラムが実行中で終わらないとき)
    - [１つのテストのみ実行します](#１つのテストのみ実行します)
      - [テストする関数を限定します](#テストする関数を限定します)
      - [テストするファイルを限定します](#テストするファイルを限定します)
  - [感想](#感想)

## デバッガーを起動するのに時間がかかる問題

Jest を使った JavaScript や TypeScript の テスト コード をデバッグするとき、
Visual Studio Code の Jest の拡張機能（Extension）を使うと、
テストコードに Run | Debug ボタンが表示されて便利なのですが、
デバッガーの起動に約6秒かかってしまいます。

![Run Debug ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/71585d7e-020d-179d-b2c2-dc0dd350ee9d.png)

たかが6秒なのですが、
デバッグするときは何度も再起動を行うため徐々にイライラが蓄積されていきます。
多いときは約10秒ごとに再起動することもあるのでほとんどが待ち時間になります。
早く直したいのに待たされるのは古いPCで作業しているようなものです。

ところで、Jest には watch モードがあります。
テストコードを編集して保存すると自動的にテストコードを実行してくれて
問題の早期発見につながります。
この watch モードからテストコードを呼び出していることは分かるのですが、
Debug ボタンを押すとなぜか別の Jest を起動しようとして約6秒もかかってしまいます。
すでに起動している Jest の watch モードとデバッガーを接続できたらいいのに
というのは誰しも思いつくことでしょうが、
具体的にどのようにすればできるのかがネットにあまり書いていないので
ここで紹介したいと思います。

その構成の場合、テストコードの起動が 0.1秒ぐらいなります。まさに一瞬です。


## Jest を速くする watch モードとデバッガーに接続するしくみ

Visual Studio Code の端末(Terminal)には、JavaScript Debug Terminal
という特殊な端末があることが分かりました。
この JavaScript Debug Terminal を開いて Jest の watch を起動すると、
自動的に Visual Studio Code のデバッガーと接続できます。

また、TypeScript の場合、ts-node や ts-jest の Node モジュールを使うことで
TypeScript のファイルを直接 Node.js や Jest からで実行できるようになります。

また、詳しくは分かっていませんが、Jest の maxWorkers という設定項目によって
ワーカーを適度に動かしておく必要があるようです。


## 起動が早い Jest + TypeScript のテストコードのプロジェクトを作ってみる

では、具体的にどのように設定すればいいかについて説明したいと思います。

ただ、設定ファイルのこことここの設定が必要という説明では成功しないことがよくあります。
成功したシンプルなプロジェクトを作り、それをリファレンスとして
徐々に使いたいプロジェクトとの違いを少なくしていくのがより成功しやすい手順になりますので、
ここではシンプルなプロジェクトを作っていこうと思います。

また例によってリセット状態の Windows からの手順の説明になります。

この記事を書いたときに使った各種モジュールの最新バージョンは以下のとおりです。

|  モジュール  |  バージョン  |
| ---- | ---- |
|  Windows  |  10 Pro 20H2  |
|  Node.js  |  14.16.1  |
|  Visual Studio Code  |  1.55.2  |
|  typescript  |  4.2.4  |
|  ts-jest  |  9.1.1  |
|  @types/node  |  14.14.41  |
|  jest  |  26.6.3  |
|  ts-jest  |  26.5.5  |
|  @types/jest  |  26.0.22  |


### Node.js をインストールします

- https://nodejs.org/ja/download/ >> Windows Installer (.msi) >> 64-bit
- ダウンロードしたファイル（例：node-v14.16.1-x64.msi）を開きます
- インストール オプションはデフォルトを使用

プロキシがある LAN に Windows がある場合:

- Windows スタート >> PowerShell （などのシェルを開きます）
- npm config -g set proxy       "http://＿.＿.＿.＿:＿＿"
- npm config -g set https-proxy "http://＿.＿.＿.＿:＿＿"

![Node.js のホームページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/2b543843-0b80-aa07-957d-2d68d45bad73.png)


### Visual Studio Code をインストールします

- https://code.visualstudio.com/
- ダウンロードしたファイル（例：VSCodeUserSetup-x64-1.55.2.exe）を開きます
- インストール オプションはデフォルトを使用
- 拡張機能（Extensions）は不要です
- （推奨）VSCode (Visual Studio Code をタスクバーにピン止めします
- （推奨）Ctrl + S キーを押したときに全てのファイルを保存するように設定します
    - VSCode >> File >> Preferences >> Keyboard Shortcuts >> save all （と入力） >>
        File: Save All （をダブルクリック） >> Ctrl + S キー >> Enter キー

![Visua Studio Code のホームページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/35c46a7c-be57-28bf-1d71-a475de065ee2.png)


### プロジェクトを新規作成します

Visual Studio Code で新しいフォルダー try_jest を開きます。
このフォルダー名はコード上でのプロジェクト名に相当します。
try_jest から変えることもできますが、変えたときは以後の try_jest を読み替えてください。


#### Visual Studio Code で新しいフォルダー try_jest を開きます

- VSCode >> File >> Open Folder >> デスクトップ >> 新しいフォルダー >>
    try_jest >> フォルダーの選択


#### __Project__/package.json ファイルを作ります

package.json ファイルは、npm コマンドや Node モジュールの設定ファイルです。

__Project__ は try_jest フォルダーを表します。
内容は下記をコピー＆ペーストしてください。
すぐに保存も行ってください。

- VSCode の EXPLORER（の中を右クリック）>> New File >> package.json

__Project__/package.json

    {
        "name": "try_jest",
        "version": "0.0.1",
        "description": "",
        "scripts": {
            "setup": "npm ci",
            "test":  "jest --watchAll",
            "clean": "powershell rm -r -fo node_modules"
        },
        "author": "",
        "license": "ISC",
        "private": false,
        "dependencies": {},
        "devDependencies": {},
        "jest": {
            "roots": [
                "<rootDir>/src"
            ],
            "testMatch": [
                "**/__tests__/**/*.+(ts|tsx|js)",
                "**/?(*.)+(spec|test).+(ts|tsx|js)"
            ],
            "transform": {
                "^.+\\.(ts|tsx)$": "ts-jest"
            },
            "maxWorkers": 1
        }
    }

上記の内容は変更しなくてもそのまま使えます。

内容を少し説明します。

| シンボル | 説明 |
| ---- | ---- |
| name | プロジェクト名 |
| scrips/test | npm test を実行したときのコマンド。 Jest の watch モードを起動します |
| jest/roots | Jest が対象とするフォルダー |
| jest/testMatch | Jest が対象とするファイル |
| jest/transform | Jest が対象とする TypeScript のファイル |
| jest/maxWorkers | Jest のワーカーを動かす割合 |


#### 必要な Node モジュールをインストールします

- VSCode >> Terminal >> New Terminal

Terminal

    npm install  typescript  ts-node  @types/node  jest  ts-jest  @types/jest  --save-dev


#### __Project__/tsconfig.json ファイルを作ります

tsconfig.json ファイルは TypeScript の設定ファイルです。


__Project__/tsconfig.json

    {
        "compilerOptions": {
            "declaration": true,
            "strict": true,
            "lib": [ "es2015", "dom" ],
            "inlineSourceMap": true,
            "inlineSources": true,
            "outDir": "build"
        }
    }

上記の内容は変更しなくてもそのまま使えます。

内容を少し説明します。

| シンボル | 説明 |
| ---- | ---- |
| outDir | TypeScript ファイルを JavaScript にトランスパイルしたファイルを格納する場所 |


#### __Project__/src/lib.ts ファイルを作ります

＿＿.ts ファイルは TypeScript のファイルです。
テスト対象のサンプルとして src フォルダーを作ってから lib.ts ファイルを作ってください。

__Project__/src/lib.ts

    export function  add(a: number, b: number): number {
        return  a + b;
    }


#### __Project__/src/lib.test.ts ファイルを作ります

＿＿.test.ts ファイルは TypeScript で書かれたテストコードです。

__Project__/src/lib.test.ts

    import { add } from './lib';

    test('add', () => {
        const  a = 2;
        const  b = 3;
        const  answer = 5;

        const  result = add( a, b );
        expect(result).toBe(answer);
    });

内容を少し説明します。

| シンボル | 説明 |
| ---- | ---- |
| test | Jest にテストケースであることを設定します。it というシンボルでも構いません |
| expect | テストケースを実行した結果の期待値をチェックします |


### Jest のウォッチモードを起動して Visual Studio Code と接続します

- VSCode >> Terminal >> 1: powershell（Terminal の上）>> Create JavaScript Debug Terminal

![Create JavaScript Debug Terminal](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/71a3a342-4782-4863-6b3a-703645adca1c.png)

Terminal

    npm test

実行結果と Jest の watch のメニュー

![npm test の結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/9ec0f82e-6bd0-60f4-4204-f963adb9b829.png)

以上の操作により、Visual Studio Code のデバッガーと Jest の watch を接続し、
テストを実行し、Jest の watch のメニューを表示します。
テストコードを実行した後でも、Jest の watch は
デバッガーと接続しながら動き続けています。

npm test コマンドによって npm の scripts 環境の中で
package.json#scripts/test に書かれた
jest --watchAll コマンドが実行されます。

Jest の watch が動いている状態では、
ファイルを編集して保存すると自動的にテストを再実行します。
また、テストの結果が表示されている Terminal（端末）をクリックして
f キーなどを押すことで、Jest の watch のメニュー項目を選択することもできます。
メニュー項目の内容については、以下で説明していきます。


### デバッガーに接続して失敗したテストをデバッグします

デバッグを試すために、テストが失敗するコードに変更してみます。
add 関数の内容をたとえば以下のように変更します。

__Project__/src/lib.ts

- 変更前: a + b
- 変更後: a + a

Jest の watch のメニューが選択されるのを待っている状態でファイルを変更して保存すると、
自動的にテストコードが呼ばれます。
テストが失敗するように変更したのでテストが失敗したと表示されます。
ちなみに、Expected: に期待値、Received: に実行結果、失敗したチェック内容も表示されるので、
デバッグするときの参考になるでしょう。
テストコードを再実行したときは、Jest の watch のメニューの項目が表示されませんが、
w キーを押すと表示されます（と英語で表示されます）。

![テストが失敗](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/74b42a2a-1a4a-032f-2fec-365894f56ee4.png)

ブレークポイントを張ります。
たとえば __Project__/src/lib.test.ts の
add 関数を呼び出すコードにブレークポイントを張るために、
add 関数を呼び出しているコードの行番号の左をクリックして赤い丸を表示させます。
そして、失敗したテストコードを実行させる Jest の watch の f メニューを選択すると、
ブレークポイントで一時停止します。

- ブレークポイントを張ります（行番号の左をクリックします）
- Terminal をクリックしてアクティブにします
- f キーを押します

![ブレーク](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/ad9f7ad4-1c4d-6a59-036a-75b30fdcd4b2.png)

一瞬でブレークポイントに到達しました。すごいですね。
もちろん、F10 キーで ステップ オーバー、F11 キーで ステップ イン しますし、
ウォッチして変数の値やオブジェクトの内容をツリー表示することもできます。


### テストを再起動します

テストの実行中やブレーク中には、Jest の watch メニューが表示されていません。
その状態でテストを再実行する方法を説明します。


####  プログラムがブレーク中のとき

プログラムがブレーク中のときは、F5 キーまたは Continue ボタン（下記の左端）を押します。

![デバッグ用ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/9e17ebca-76d6-4ca2-2295-e4f9dbc65a72.png)

最後まで実行したら、Jest の watch メニューが表示されます。
そして、失敗したテストコードを実行させる Jest の watch のメニューを選択すると、
テストコードが再実行され、ブレークポイントで一時停止します。

- Terminal をクリックしてアクティブにします
- f キーを押します

最後まで実行するまでに何度もブレークポイントで一時停止してしまうときは、
ブレークポイントを一時的にすべて無効にするとよいでしょう。

- Run and Debug ボタン（左上）
- BREAKPOINTS（左下）の Toggle Active Breakpoints ボタン

![Run and Debug ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/353f1c3d-61c0-2789-f2f3-041960be4cbd.png)
![Toggle Active Breakpoints ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/22ea37de-ca84-fe8c-8737-89774c28aa37.png)

Jest の watch モードでは、
Visual Studio Code の Restart ボタン（右から２番目）を押しても
テストを再実行することはできません。
また、Disconnect ボタン（右端）を押すと、テストの最後まで実行しますが
デバッガーとの接続が切れてしまいます。
ですので、この２つのボタンは使えません。


#### プログラムが実行中で終わらないとき

テストコードやプログラムの実行が終わるまで Jest の watch のメニューは表示されないのですが、
無限ループやタイムアウト待ちで実行が終わらないときにテストコードを再実行するときは、
Jest の watch を強制終了して再起動します。

試しに、しばらく実行が終わらないように、テストコードを下記のように変えてみます。
テストコードの関数の最初の左に async を追加し、
テスト関数の最後のほうで 5秒待つコードを追加してみます。

    import { add } from './lib';

    test('add', async () => {  // async を追加
        const  a = 2;
        const  b = 3;
        const  answer = 5;

        const  result = add( a, b );
        await new Promise(resolve => setTimeout(resolve, 5000));  // 追加
        expect(result).toBe(answer);
    });

このテストコードを実行すると、5秒間実行してから Jest の watch に戻ることを
確認してみてください。
プログラムがブレークしない状況にするため、ブレークポイントは削除してください。

テストコードが実行中に再起動するには、まず、JavaScript Debug Terminal を強制終了します。

- Terminal タブ（下）>> ゴミ箱アイコン（右）

![強制終了ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/c470e919-9a6c-51dc-00e7-5e44d600562e.png)

テストコードを再実行して、実行中に強制終了させると、すぐに終了します。

そして、Jest の watch を再起動させます。

- Terminal >> 1: powershell（Terminal の上）>> Create JavaScript Debug Terminal

![Create JavaScript Debug Terminal](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/71a3a342-4782-4863-6b3a-703645adca1c.png)

しかし、すぐに Terminal の入力待ちにはなりません。
約5秒後に右下に応答しないというエラーが表示されるので、
Restart pty host ボタンを押してください。

![Terminal ホストの再起動](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/95a2e498-9158-904a-38c8-ebe8844e8531.png)

それでも Terminal の入力待ちにはなりませんが、
もう一度 JavaScript Debug Terminal を強制終了して再起動すると入力待ちになるので、
npm test コマンドを実行してください。
テストコードの実行が再開されます。

![強制終了ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/c470e919-9a6c-51dc-00e7-5e44d600562e.png)

![Create JavaScript Debug Terminal](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/71a3a342-4782-4863-6b3a-703645adca1c.png)

Terminal

    npm test


### １つのテストのみ実行します

１つのコードの変更で多くテストが失敗したときは、
１つのテストのみに集中してデバッグするとよいでしょう。


#### テストする関数を限定します

test 関数を呼び出すコードを test.only 関数を呼び出すコードに変更すると、
その関数のテストコードだけ実行するように限定することができます。

変更前:

    test(＿＿

変更後:

    test.only(＿＿


#### テストするファイルを限定します

Jest の watch メニューの p コマンドで
テストするテストコードがあるファイルを限定することができます。

- Terminal をクリックして Jest の watch メニューの端末をアクティブにします
- p キーを押します
- ファイル名（例： lib.test.ts）またはその一部にマッチする正規表現のパターンを入力します

![テスト ファイル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427559/8edc65ed-dc56-5357-5972-b41428b149eb.png)


## 感想

Jest の拡張機能をインストールして Debug ボタンを押すことに比べると
あまりスマートではありませんが、Debug ボタンがあるファイルを開かなくても、
f キーを押すだけで一瞬で再実行できるのでデバッグがかなり快適になりました。

そのうち、一瞬で再実行できる Jest の拡張機能が登場するかもしれないので、
それも期待しています。