Jest v27にバージョンを上げたら mount / shallowMount でエラーが出るようになったので対処する

# 初めに
自分の趣味プロジェクトは、vue-test-utils + Jestの構成でテストを書いています。
そろそろJestのバージョンを上げようかなと思い、Jest v27にバージョンを上げてみたところ、mount / shallowMount で下記のエラーが出てテストが落ちるようになりました。
`[vue-test-utils]: window is undefined, vue-test-utils needs to be run in a browser environment. You can run the tests in node using jsdom See https://vue-test-utils.vuejs.org/guides/#browser-environment for more details.`

vue-test-utils + Jestの構成にしている場合、Jest v27にすると同じエラーになる可能性が高いため、対処法をまとめておこうと思います。
もし、同じエラーになった場合は参考にしていただけると幸いです。

# 先に結論
とりあえず対処法を早く知りたい！という方もいると思うので、先に結論から。
vue-test-utils + Jestの構成であれば、`jest.config.js` に下記の設定を追記することでエラーを解消できます。

```javascript:jest.config.js
module.exports = {
  ...
  // 下記を追加
  testEnvironment: "jsdom",
  ...
```

# エラーになった原因を調べる
## まずはエラーメッセージを見てみる
mount / shallowMount しているところで発生するエラーは以下です。
`[vue-test-utils]: window is undefined, vue-test-utils needs to be run in a browser environment. You can run the tests in node using jsdom See https://vue-test-utils.vuejs.org/guides/#browser-environment for more details.`

このエラーメッセージから、jsdom を使うとテスト実行できるが、バージョンを上げたことで jsdom が使われなくなったのかも？というぼんやりとした仮説を立てました。（正直この辺りはあまり詳しくない・・）
他にもエラーメッセージの中にページ内リンクも記載されていますが、遷移してみても該当箇所を見つけられませんでした。（スクロールされなかった）

## Jest v27で何が変わった？
Jest v27で jsdom の扱いが変わった？と思い、「jest 27 jsdom」で検索してみたところ、下記のドキュメントを見つけました。
https://jestjs.io/ja/blog/2021/05/25/jest-27#flipping-defaults

>we are changing the default test environment from "jsdom" to "node"

どうやら、testEnvironment のデフォルトが jsdom から node に変わったようです。

>Running tests in a JSDOM environment incurs a significant performance overhead. Because this was the default behavior of Jest unless otherwise configured up until now, users who are writing Node apps, for example, may not even know they are given an expensive DOM environment that they do not even need.

変えた理由は、jsdom にするとパフォーマンスが悪くなる & Node.jsのアプリでは、jsdom は不要なはずだがデフォルトが jsdom なので、パフォーマンスが悪くなっていることに気づけないかもしれないから。確かに気付かけなそう。。
とはいえ、フロント側のテストでは、jsdom が必要になります。
上記のドキュメントには、jsdom を指定する方法も記載されており、`"testEnvironment": "jsdom"`のように明示的に指定すればこれまでと同じ挙動にできそうです。

# エラーを解消する
エラーの対処法が分かったので、実際に対応していきます。
ファイルごとに対応する方法と、テスト全体で設定する方法の2通りあるのでそれぞれ見ていきます。（どちらの方法でもテストが通るようになることを確認できた）

## ファイルごとに適用する方法
先ほど記載したドキュメントには、下記のファイルごとに適用する方法がリンクされていました。
https://jestjs.io/ja/docs/configuration#testenvironment-string

下記のようにファイルの先頭に`docblock`を追加することで、jsdom を設定した状態でテストを実行することができます。ファイルによって、DOMが必要なテストと必要ではないテストがある場合は、ファイルごとに適用するのが良いと思います。

```typescript
/**
 * @jest-environment jsdom
 */

import { mount } from '@vue/test-utils';
...
```

## 全体に適用する方法
次に全体に適用する方法です。
`jest.config.js`に以下を追記することで、jsdom を設定した状態で全てのテストを実行できます。

```javascript:jest.config.js
module.exports = {
  ...
  // 下記を追加
  testEnvironment: "jsdom",
  ...
```

## どちらの方法で設定すべき？
[vue-test-utilsのドキュメント](https://vue-test-utils.vuejs.org/ja/installation/#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E7%92%B0%E5%A2%83)を見ていると、下記のような記述を見つけました。

>vue-test-utils はブラウザ環境に依存します。技術的には、実際のブラウザで実行することはできますが、異なるプラットフォーム上で実際のブラウザを起動するという複雑さのため、お勧めできません。代わりに、JSDOM を使用して仮想ブラウザ環境で Node.js でテストを実行することをお勧めします。

どうやら、vue-test-utils は jsdom で実行することを推奨しているようです。
純粋な関数であれば、jsdom を設定しなくてもテストが通るため、jsdom ではなく、node にした方がテストが速くなりそうですが、ファイルごとに設定するのは辛いので、最終的には[全体に適用する方法](https://qiita.com/k_2929/items/5090d5590307b265b256#%E5%85%A8%E4%BD%93%E3%81%AB%E9%81%A9%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)で修正することにしました。

# 参考
- https://jestjs.io/ja/blog/2021/05/25/jest-27
- https://jestjs.io/ja/docs/configuration
- https://vue-test-utils.vuejs.org/ja/