Vitest + Biome の設定でハマった noUndeclaredVariables エラーの対処法

本記事は、株式会社 HRBrain Advent Calendar 2024 の 25 日目の記事です。

https://qiita.com/advent-calendar/2024/hrbrain

## はじめに
こんにちは、株式会社 HRBrain でフロントエンドエンジニアをしている @Mozu1206 です。
今年のふるさと納税は、うなぎを試してみたら大当たりでした。

先日テスト入門したのですが、[Vitest](https://vitest.dev/) と [Biome](https://biomejs.dev/ja/) の設定ファイルを調整している時に `noUndeclaredVariables` エラー解消に手間取ったので対処法を記事にまとめてみます。

サンプルコードを用意したので、お手元で試したい方はお使いください。
https://github.com/Mozu1206/vitest-biome-demo

## 今回のエラー原因
Vitest で `globals: true` を設定すると、テストコード内で test や expect などのグローバル変数が利用できるようになります。しかし、Biome はこの設定を認識しないため、これらの変数が宣言されていないという `noUndeclaredVariables` エラーが発生しました。

## 先にざっくりとした結論
`biome.json` の設定ファイル内で、`noUndeclaredVariables` エラーが引っかからないようなオーバーライド設定をテストファイルのみに適用しました。
以下に、実際の実行ファイル・設定ファイルの記述を含めてもう少し細かく書いていきます。

## 検証用ファイル
Vitest の公式とほぼ同じものですが、以下を検証用に用意しました。
``` sum.ts
export function sum(a: number, b: number): number {
  return a + b;
}
```
``` sum.test.ts
import { sum } from "./sum";

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(3);
});
```

## `vite.config.ts` と `biome.json` それぞれの中身とエラー画面
基本的にテンプレートのままですが、`vite.config.ts` にはAPIをグローバルで使えるようにする記述をしています。また、`biome.json` にはルールをいくつか追加しています。

``` vite.config.ts
/// <reference types="vitest/config" />
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";

// https://vite.dev/config/
export default defineConfig(() => {
  return {
    plugins: [react()],
    test: {
      globals: true, //この設定することで、Vitest の API をグローバルで利用できるようになります。
    },
  };
});
```

``` jsonc:biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": []
  },
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "formatWithErrors": false,
    "enabled": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUndeclaredVariables": "error", // ここのエラーに該当してしまいました
        "noUnusedVariables": "error",
        "useExhaustiveDependencies": "error",
        "useHookAtTopLevel": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  }
}
```

この状態で `yarn biome ci .` を実行すると、下記のエラーが出てしまいました。（画像では `yarn ci` を実行）
![スクリーンショット 2024-12-19 21.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1980374/6a46ea99-96aa-4593-498f-705d6a728519.png)

## 対処法1
`biome.json` の設定ファイルに `overrides` 設定を追加して、テストファイルのみ `noUndeclaredVariables` のルールを無効化します。今回は、ディレクトリ構成に依存せずに全てのテストファイルを対象にします。お好みでスコープを絞ってください。

以下が変更後の `biome.json` の記述です。
``` jsonc:biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": []
  },
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "formatWithErrors": false,
    "enabled": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUndeclaredVariables": "error",
        "noUnusedVariables": "error",
        "useExhaustiveDependencies": "error",
        "useHookAtTopLevel": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  },
  "overrides": [ // ここから下の記述追加
    {
      "include": ["*.test.*"],
      "linter": {
        "rules": {
          "correctness": {
            "noUndeclaredVariables": "off"
          }
        }
      }
    }
  ]
}
```

この変更を加えて再度 `yarn biome ci .` を実行すると、エラーが出ずに成功します。（画像では `yarn ci` を実行）
![スクリーンショット 2024-12-19 21.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1980374/dd36f63d-2738-f4f0-9e5c-cf065eb32e75.png)

:::note warn
ちょっとそれは大雑把だからもう少し絞った書き方したいなーという方もいらっしゃると思います。
そんな方は次の対処法2を参考にしてください。
:::

## 対処法2
`biome.json` の設定ファイルに `overrides` 設定を追加して、テストファイル中の`expect`や`test`などのテスト用変数をグローバル変数として認識させます。
``` jsonc:biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": []
  },
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "formatWithErrors": false,
    "enabled": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "noUndeclaredVariables": "error",
        "noUnusedVariables": "error",
        "useExhaustiveDependencies": "error",
        "useHookAtTopLevel": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  },
  "overrides": [ // ここから下の記述追加
    {
      "include": ["*.test.*"],
      "javascript": {
        "globals": ["expect", "test"]
      }
    }
  ]
}
```

こちらの手法だと、設定ファイルに内変数は引き続き`noUndeclaredVariables` エラーを出すことができるので、より丁寧な方法ですね。

プロジェクトにより、お好みの方を選んで設定してみてください。

## まとめ
今回の変更を加えることで、VitestのAPIを毎回importせずに使っても、Biomeでエラーが出ることがなくなりました。
オーバーライドは、適切に使用することで各プロジェクトに合ったルールを整備するときに役立ちそうですね。
これで来年からは、しっかりテストを書いてフロントエンド実装を進められそうです。

## PR
株式会社HRBrainでは、一緒に働く仲間を募集しています！
興味を持っていただけた方はぜひ弊社の採用ページをご確認ください！

https://www.hrbrain.co.jp/recruit