VSCodeのJest拡張機能をmonorepo構成で使いたい

# VSCode の Jest 拡張機能 とは

[こちら](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) のMarket Placeでのページを見ていただくのが分かりやすいかと思いますが、  
VSCodeにてJestのテストを

- GUIから実行できる
(特定のテストファイルや、特定のdescribe, test(it) のみを実行することも可能)
- テストソースをデバッグできる
- カバレッジをソース上に出せる

などなど、便利な機能がそろっている拡張機能です。

# monorepo構成でうまく使えない。。

ただ少し問題があって、
VSCode上でいわゆる単発のプロジェクトを開発している際は特に問題なく動かせるのですが。。

monorepo構成のプロジェクトだと、この拡張機能を入れても 
上手く動作させることができませんでした。  

ここで想定しているのは以下のようなmonorepo構成です。
yarn workspaceで、packagesフォルダ配下に client, server といったモジュールを含み、  
node_modulesはルート階層にいるような状態です。

```
.
├── node_modules
├── packages
│   ├── client
│   │   ├── src
│   │   └── package.json
│   └── server
│       ├── src
│       └── package.json
├── package.json
└── yarn.lock
```

# 解決方法

先に解決方法を記載します。  
ポイントは  
**VSCodeで直接プロジェクトを開くのではなく、マルチルートワークスペースを使って開くようにする**
です。
それに伴って必要な設定ファイルの用意などもあるので順を追って説明していきたいと思います。  

また、サンプルプロジェクトでとりあえず動かしてみたい、という方のために  
以下にmonorepo構成でcode-workspaceの設定ファイルなどが込みのサンプルを用意しましたのでご利用ください。

https://github.com/uenok0108/vscode-jest-monorepo

## マルチルートワークスペース用のファイルの作成
root階層およびpackages配下のclient, serverをそれぞれマルチルートワークスペースで開けるように  
`.code-workspace` という名称のファイルをroot直下に作成します。  
内容は以下のようなものです。

```json
{
  "folders": [
    {
      "name": "root",
      "path": "."
    },
    {
      "name": "client",
      "path": "packages/client"
    },
    {
      "name": "server",
      "path": "packages/server"
    }
  ],
  "settings": {
    "jest.autoRun": "off",
    "jest.jestCommandLine": "yarn test",
    "jest.disabledWorkspaceFolders": ["root"]
  }
}
```

また、ここの `settings` にて Jest拡張機能にて必要な最低限の設定を入れます。  

`jest.autoRun` に関してはVSCodeでこのプロジェクト開いた際に自動でテストを流すか、  
もしくはwatchモードのようにファイルの変更があった場合に動かすか、  
はたまたすべて手動でやるようにするか、といった設定があるのでお好みで設定すれば良いと思います。  
ここではいったん手動のみにするために `off` を入れています。

`jest.jestCommandLine` に関しては実際にjestを実行する際のコマンドを入れておきます。  
ここでの記載内容は上記のサンプルの構成に従っており、  
各モジュールのpackage.jsonにてテスト実行用に `test` という script をそれぞれ持っている想定です。  

```json:client
{
  "name": "client",
  "scripts": {
    "test": "react-scripts test --watchAll=false",
  }
}
```
```json:server
{
  "name": "server",
  "scripts": {
    "test": "jest -c jest.config.ts"
  }
}
```
こうしておくことで、  
clientのテスト用には client/package.json の test コマンド  
serverのテスト用には server/package.json の test コマンド
がJestの拡張機能で使われるようになります。  

この `jest.jestCommandLine` には `node_modules/.bin/jest` のように  
ルート階層のnode_modulesにいるjestを直接呼ぶような記述もできるのですが、
今回のサンプルのようにclientがreact-scriptsを利用している場合は  
そちらを経由してjestのテストを実行しないといけないため、  
testコマンドを挟んであげるほうが良いと思います。

`jest.disableWorkspaceFolders` は Jest拡張機能でテスト実行対象と`しない`ワークスペースの指定です。  
root階層は一切ソースもなければテストソースもありませんので、rootを対象外とするように設定しています。

## 作成した .code-workspace ファイルを利用してVSCodeを開く 
VSCodeのメニューで File > Open Workspace from File から
上記で作成した `.code-workspace` ファイルを開きます。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192099/3240a489-3594-8783-0cd0-26976e23d273.png)

## Jest拡張機能を動かしてみる
開いた後は左メニューのJest拡張機能(フラスコのアイコン)を開いて、  
そこから全体、任意のファイル、任意のdescribe/test(it)のみテストを実行したりできます。  
左のメニューだけでなく、開いているファイルのほうで行番号が出ている横あたりにもボタンが出てきますので、  
そちらからの実行も可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192099/411d1a59-9c4c-6da7-d086-eb422e798145.png)


## デバッグもしたい
ここまででいったんそれぞれのpackageのテスト実行自体は出来るようになりました。  
加えて、テストのデバッグも行いたい場合はもう少し追加が必要です。

それぞれのpackage直下に `.vsocde/launch.json` を作成し、そこにデバッグ用の設定を入れていきます。  

```
.
└── packages
    ├── client
    │   └── .vscode
    │       └── launch.json
    └── server
        └── .vscode
            └── launch.json
```

```json:client
{
  "configurations": [
    {
      "type": "node",
      "name": "vscode-jest-tests",
      "request": "launch",
      "runtimeExecutable": "${workspaceFolder}/../../node_modules/.bin/react-scripts",
      "args": ["test", "--env=jsdom", "--runInBand", "--watchAll=false"],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "protocol": "inspector",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true
    }
  ]
}
```
```json:server
{
  "configurations": [
    {
      "type": "node",
      "name": "vscode-jest-tests",
      "request": "launch",
      "program": "${workspaceFolder}/../../node_modules/.bin/jest",
      "args": ["--runInBand", "--watchAll=false"],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
    }
  ]
}
```
これらのファイルを追加できたら、あとはJest拡張機能のメニュー内にてデバッグ実行ボタンを押す、  
もしくはテストファイルを開いた際に出てくる `Debug` のボタンを押してみましょう。
以下のようにブレークポイントを設定して止めてみるなど、無事にデバッグが行えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192099/096218ac-9ddd-92e2-2195-4ea67da10723.png)

# おわりに  
いかがだったでしょうか。  
実はこのマルチルートワークスペースを利用することについては  
[Jest拡張機能の公式ドキュメント](https://github.com/jest-community/vscode-jest#how-to-use-the-extension-with-monorepo-projects)でも言及されているのですが、  
実際にどうやったらいいのかよくわからなかったので少し調べて試してみました。  

また、調べた際には同プロジェクトにおけるGitHubの以下Issueが非常に参考になりましたので、  
こちらも参考として貼っておきます。

https://github.com/jest-community/vscode-jest/issues/129#issuecomment-569014819

同じようなmonorepo構成でJest拡張機能を使いたいけど使えない。。  
と思っていた方々の助けになれば幸いです。