ESLint × Vitest/Playwright:テスト環境のグローバルと型を正しく設定
テストコードを書く際に「describe is not defined」「test が見つかりません」といったエラーに遭遇したことはありませんか?
Vitest や Playwright のようなテストフレームワークでは、グローバル関数や変数が暗黙的に提供されますが、ESLint や TypeScript がこれらを認識できないために、コードは正常に動作するのにエディタ上でエラー表示が消えないという状況が発生します。
本記事では、ESLint と TypeScript における Vitest および Playwright のグローバル環境設定と型定義の正しい構成方法を、実例を交えて徹底解説いたします。
背景
テストフレームワークとグローバル API
Vitest や Playwright といったモダンなテストフレームワークは、テストコードの記述を簡潔にするため、グローバルスコープに多くの関数や変数を自動的に注入します。
以下はテストフレームワークが提供する代表的なグローバル関数です。
| # | フレームワーク | グローバル関数・変数の例 |
|---|---|---|
| 1 | Vitest | describe, test, it, expect, vi, beforeEach, afterEach |
| 2 | Playwright | test, expect, page, context, browser |
| 3 | Jest | describe, test, it, expect, jest, beforeAll, afterAll |
これらの関数は実行時には問題なく動作しますが、静的解析ツールである ESLint や TypeScript はデフォルトではこれらのグローバル変数を認識できません。
ESLint と TypeScript の静的解析
ESLint と TypeScript は、コードの品質と型安全性を保つために静的解析を行います。
以下の図は、テストコード作成時の静的解析の流れを示したものです。
mermaidflowchart TD
code["テストコード<br/>(*.test.ts)"] -->|解析| eslint["ESLint"]
code -->|型チェック| tsc["TypeScript<br/>Compiler"]
eslint -->|グローバル未定義| err1["no-undef エラー"]
tsc -->|型情報なし| err2["型エラー"]
err1 & err2 --> problem["エディタに<br/>エラー表示"]
図のポイント:
- テストコードは実行時に正常動作するが、静的解析時にエラーが発生する
- ESLint は未定義のグローバル変数を検出し、TypeScript は型情報の欠如を指摘する
設定不足によって発生する問題
適切な設定がない場合、以下のような問題が発生します。
| # | 問題の種類 | 具体的な症状 | 影響 |
|---|---|---|---|
| 1 | ESLint エラー | 'describe' is not defined (no-undef) | エディタに赤波線が表示される |
| 2 | TypeScript エラー | Cannot find name 'test' (TS2304) | 型チェックが失敗し、ビルドエラーになる |
| 3 | IntelliSense 未動作 | 自動補完が効かない | 開発効率が低下する |
| 4 | CI での失敗 | Lint チェックが通らない | デプロイがブロックされる |
これらの問題を解決するには、ESLint の環境設定と TypeScript の型定義を正しく構成する必要があります。
課題
ESLint における課題
ESLint は、未定義のグローバル変数を参照すると no-undef ルールによってエラーを報告します。
以下は、Vitest のテストコードにおける典型的なエラー例です。
typescript// src/utils/math.test.ts
describe('Math utilities', () => {
// ❌ ESLint Error: 'describe' is not defined (no-undef)
test('should add two numbers', () => {
// ❌ ESLint Error: 'test' is not defined (no-undef)
expect(1 + 1).toBe(2);
// ❌ ESLint Error: 'expect' is not defined (no-undef)
});
});
これらのエラーは、ESLint がテストフレームワークのグローバル環境を認識していないために発生するものです。
TypeScript における課題
TypeScript は型情報を元にコードを解析しますが、テストフレームワークのグローバル関数の型定義が読み込まれていないと型エラーが発生します。
typescript// src/components/Button.test.ts
describe('Button component', () => {
// ❌ TypeScript Error: Cannot find name 'describe'. TS2304
it('should render correctly', () => {
// ❌ TypeScript Error: Cannot find name 'it'. TS2304
const result = expect(true).toBe(true);
// ❌ TypeScript Error: Cannot find name 'expect'. TS2304
});
});
このエラーを解決するには、TypeScript に対してテストフレームワークの型定義を明示的に読み込ませる必要があります。
Playwright 固有の課題
Playwright は、テストファイル内で page や context といった Fixture を暗黙的に提供しますが、これらも ESLint と TypeScript に認識させる必要があります。
typescript// e2e/login.spec.ts
test('user can login', async ({ page }) => {
// ❌ ESLint Error: 'test' is not defined (no-undef)
// ❌ TypeScript Error: Cannot find name 'test'. TS2304
await page.goto('/login');
// TypeScript は page の型を認識できない
});
以下は、課題をまとめた図解です。
mermaidflowchart LR
testCode["テストコード"] --> eslintCheck["ESLint 解析"]
testCode --> tsCheck["TypeScript<br/>型チェック"]
eslintCheck -->|環境未設定| eslintErr["no-undef<br/>エラー"]
tsCheck -->|型定義未導入| tsErr["TS2304<br/>エラー"]
eslintErr --> devExp["開発体験<br/>の低下"]
tsErr --> devExp
図のまとめ:
- 環境設定と型定義の両方が不足している場合、ESLint と TypeScript の両方でエラーが発生する
- これらのエラーは開発体験を著しく低下させる要因となる
解決策
Vitest の ESLint 環境設定
Vitest のグローバル API を ESLint に認識させるには、eslint-plugin-vitest を使用します。
プラグインのインストール
bashyarn add -D eslint-plugin-vitest
このプラグインは、Vitest 専用のルールと環境設定を提供します。
ESLint Flat Config での設定
ESLint 9.x 以降の Flat Config 形式での設定例です。
javascript// eslint.config.js
import vitest from 'eslint-plugin-vitest';
上記では、Vitest プラグインをインポートしています。
javascriptexport default [
{
files: ['**/*.test.ts', '**/*.spec.ts'],
plugins: {
vitest,
},
rules: {
...vitest.configs.recommended.rules,
},
languageOptions: {
globals: {
...vitest.environments.env.globals,
},
},
},
];
この設定では、以下のポイントを押さえています。
| # | 設定項目 | 役割 |
|---|---|---|
| 1 | files | テストファイルのみに適用する |
| 2 | plugins | Vitest プラグインを登録 |
| 3 | rules | Vitest 推奨ルールを適用 |
| 4 | languageOptions.globals | Vitest のグローバル変数を定義 |
レガシー Config での設定
ESLint 8.x 以前の .eslintrc.js 形式での設定例です。
javascript// .eslintrc.js
module.exports = {
overrides: [
{
files: ['**/*.test.ts', '**/*.spec.ts'],
extends: ['plugin:vitest/recommended'],
env: {
'vitest/env': true,
},
},
],
};
この設定により、テストファイル内で describe、test、expect などのグローバル関数が認識されるようになります。
Vitest の TypeScript 型設定
Vitest のグローバル API を TypeScript に認識させるには、tsconfig.json で型定義を読み込む必要があります。
グローバル API モードの有効化
まず、Vitest 側でグローバル API モードを有効にします。
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
設定ファイルの型定義をインポートします。
typescriptexport default defineConfig({
test: {
globals: true,
},
});
globals: true を設定することで、グローバル API が有効になります。
TypeScript での型定義読み込み
次に、tsconfig.json で Vitest の型定義を読み込みます。
json{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
この設定により、describe、test、expect、vi などの型が自動的に利用可能になります。
複数の環境に対応する場合
テスト用とアプリケーション用で異なる型定義を使用する場合は、tsconfig を分離します。
json// tsconfig.test.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"types": ["vitest/globals"]
},
"include": ["**/*.test.ts", "**/*.spec.ts"]
}
アプリケーションコードとテストコードで型定義を明確に分離することで、型の競合を防げます。
Playwright の ESLint 環境設定
Playwright のグローバル API を ESLint に認識させるには、eslint-plugin-playwright を使用します。
プラグインのインストール
bashyarn add -D eslint-plugin-playwright
このプラグインは、Playwright 専用のルールと環境設定を提供します。
Flat Config での設定
javascript// eslint.config.js
import playwright from 'eslint-plugin-playwright';
Playwright プラグインをインポートします。
javascriptexport default [
{
files: ['e2e/**/*.spec.ts', 'tests/**/*.spec.ts'],
...playwright.configs['flat/recommended'],
},
];
この設定では、E2E テストファイルに対して Playwright の推奨設定を適用しています。
レガシー Config での設定
javascript// .eslintrc.js
module.exports = {
overrides: [
{
files: ['e2e/**/*.spec.ts'],
extends: ['plugin:playwright/recommended'],
},
],
};
この設定により、test、expect、page などのグローバル変数が認識されます。
Playwright の TypeScript 型設定
Playwright の型定義を TypeScript に認識させる設定です。
Playwright 型定義の読み込み
json{
"compilerOptions": {
"types": ["@playwright/test"]
}
}
この設定により、Playwright のテスト API とフィクスチャの型が利用可能になります。
E2E テスト専用の tsconfig
E2E テスト用に独立した tsconfig を作成する方法です。
json// e2e/tsconfig.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["@playwright/test"]
},
"include": ["**/*.spec.ts"]
}
これにより、E2E テストコードとアプリケーションコードの型定義を完全に分離できます。
以下は、解決策の全体像を示す図です。
mermaidflowchart TB
subgraph eslintConfig["ESLint 設定"]
plugin["プラグイン<br/>インストール"]
flatConfig["eslint.config.js<br/>で環境設定"]
end
subgraph tsConfig["TypeScript 設定"]
vitestConfig["vitest.config.ts<br/>globals: true"]
tsConfigTypes["tsconfig.json<br/>types 指定"]
end
plugin --> flatConfig
vitestConfig --> tsConfigTypes
flatConfig --> resolved["グローバル認識<br/>完了"]
tsConfigTypes --> resolved
resolved --> noError["エラー解消<br/>快適な開発"]
図で理解できる要点:
- ESLint と TypeScript の両方で設定が必要
- プラグインと型定義を組み合わせることで完全な認識が可能になる
具体例
Vitest の完全設定例
ここでは、Vitest を使用したプロジェクトの完全な設定例を示します。
ディレクトリ構造
textproject/
├── src/
│ ├── utils/
│ │ ├── math.ts
│ │ └── math.test.ts
│ └── components/
│ ├── Button.tsx
│ └── Button.test.tsx
├── vitest.config.ts
├── tsconfig.json
├── eslint.config.js
└── package.json
この構造では、テストファイルをソースコードと同じディレクトリに配置しています。
Vitest 設定ファイル
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
必要なプラグインをインポートします。
typescriptexport default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
},
});
主な設定項目の説明:
| # | 設定項目 | 説明 |
|---|---|---|
| 1 | globals: true | グローバル API を有効化 |
| 2 | environment: 'jsdom' | DOM 環境をシミュレート |
| 3 | setupFiles | テスト実行前の初期化処理 |
ESLint 設定(Flat Config)
javascript// eslint.config.js
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import vitest from 'eslint-plugin-vitest';
必要なプラグインとパーサーをインポートします。
javascriptexport default [
js.configs.recommended,
// TypeScript ファイル用の基本設定
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json',
},
},
plugins: {
'@typescript-eslint': typescript,
},
rules: {
...typescript.configs.recommended.rules,
},
},
TypeScript ファイル全般に適用される基本設定です。
javascript // テストファイル専用の設定
{
files: ['**/*.test.ts', '**/*.test.tsx'],
plugins: {
vitest,
},
rules: {
...vitest.configs.recommended.rules,
},
languageOptions: {
globals: {
...vitest.environments.env.globals,
},
},
},
];
テストファイルにのみ Vitest の環境とルールを適用します。
TypeScript 設定
json{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"strict": true,
"moduleResolution": "bundler",
"types": ["vitest/globals"]
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
重要なポイント:
| # | 設定項目 | 役割 |
|---|---|---|
| 1 | types: ["vitest/globals"] | Vitest のグローバル型を読み込む |
| 2 | lib: ["DOM"] | DOM 型定義を含める |
| 3 | strict: true | 厳格な型チェックを有効化 |
テストコード例
typescript// src/utils/math.test.ts
describe('Math utilities', () => {
// ✅ 'describe' が正しく認識される
test('should add two numbers correctly', () => {
// ✅ 'test' と 'expect' が型安全に使える
const result = 1 + 1;
expect(result).toBe(2);
});
test('should multiply two numbers correctly', () => {
const result = 3 * 4;
expect(result).toBe(12);
});
});
この設定により、ESLint エラーも TypeScript エラーも発生せず、自動補完も正常に動作します。
Playwright の完全設定例
次に、Playwright を使用した E2E テストの完全な設定例を示します。
ディレクトリ構造
textproject/
├── src/
│ └── pages/
│ └── index.tsx
├── e2e/
│ ├── login.spec.ts
│ ├── navigation.spec.ts
│ └── tsconfig.json
├── playwright.config.ts
├── tsconfig.json
├── eslint.config.js
└── package.json
E2E テストは専用のディレクトリに分離しています。
Playwright 設定ファイル
typescript// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
Playwright の設定に必要な関数と定義をインポートします。
typescriptexport default defineConfig({
testDir: './e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
主な設定項目:
| # | 設定項目 | 説明 |
|---|---|---|
| 1 | testDir | テストファイルの場所 |
| 2 | fullyParallel | テストの並列実行 |
| 3 | baseURL | テスト対象の URL |
| 4 | projects | テスト対象のブラウザ |
ESLint 設定(Flat Config)
javascript// eslint.config.js
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import playwright from 'eslint-plugin-playwright';
Playwright プラグインを含む必要なモジュールをインポートします。
javascriptexport default [
js.configs.recommended,
// TypeScript 基本設定
{
files: ['**/*.ts'],
languageOptions: {
parser: tsParser,
},
plugins: {
'@typescript-eslint': typescript,
},
rules: {
...typescript.configs.recommended.rules,
},
},
TypeScript ファイル全般の基本設定です。
javascript // E2E テスト専用の設定
{
files: ['e2e/**/*.spec.ts'],
...playwright.configs['flat/recommended'],
},
];
E2E テストファイルに Playwright の推奨設定を適用します。
E2E テスト用 TypeScript 設定
json// e2e/tsconfig.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["@playwright/test"],
"moduleResolution": "bundler"
},
"include": ["**/*.spec.ts"]
}
E2E テスト専用の型定義を読み込みます。
E2E テストコード例
typescript// e2e/login.spec.ts
import { test, expect } from '@playwright/test';
明示的にインポートする方法(推奨)です。
typescripttest('user can login with valid credentials', async ({
page,
}) => {
// ✅ 'test'、'page'、'expect' が正しく認識される
await page.goto('/login');
await page.fill(
'input[name="email"]',
'user@example.com'
);
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
});
この設定により、Playwright の Fixture(page、context など)が型安全に利用できます。
以下は、設定の適用範囲を示す図です。
mermaidflowchart TB
subgraph testFiles["テストファイル"]
vitest["src/**/*.test.ts<br/>(Vitest)"]
pw["e2e/**/*.spec.ts<br/>(Playwright)"]
end
subgraph configs["設定ファイル"]
eslintConfig["eslint.config.js"]
vitestConfig["vitest.config.ts"]
pwConfig["playwright.config.ts"]
tsMain["tsconfig.json"]
tsE2E["e2e/tsconfig.json"]
end
vitest -->|適用| eslintConfig
vitest -->|適用| vitestConfig
vitest -->|適用| tsMain
pw -->|適用| eslintConfig
pw -->|適用| pwConfig
pw -->|適用| tsE2E
eslintConfig --> result["型安全で<br/>エラーのない<br/>テストコード"]
vitestConfig --> result
pwConfig --> result
tsMain --> result
tsE2E --> result
図で理解できる要点:
- テストファイルの種類によって適用される設定が異なる
- ESLint、TypeScript、テストフレームワークの設定が連携して動作する
- 各設定ファイルが適切に構成されることで、快適な開発環境が実現できる
複数のテストフレームワークを共存させる場合
プロジェクトによっては、Vitest と Playwright を同時に使用するケースがあります。
ESLint での共存設定
javascript// eslint.config.js
import vitest from 'eslint-plugin-vitest';
import playwright from 'eslint-plugin-playwright';
export default [
// Vitest 用の設定
{
files: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
plugins: { vitest },
rules: { ...vitest.configs.recommended.rules },
languageOptions: {
globals: { ...vitest.environments.env.globals },
},
},
// Playwright 用の設定
{
files: ['e2e/**/*.spec.ts'],
...playwright.configs['flat/recommended'],
},
];
ファイルパターンを明確に分けることで、それぞれのテストフレームワークに適した設定を適用できます。
TypeScript での共存設定
json// tsconfig.json(メイン)
{
"compilerOptions": {
"types": ["vitest/globals"]
},
"include": ["src/**/*"],
"exclude": ["e2e"]
}
メインの設定では Vitest の型のみを読み込みます。
json// e2e/tsconfig.json(E2E テスト用)
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["@playwright/test"]
},
"include": ["**/*.spec.ts"]
}
E2E テスト用の設定では Playwright の型を読み込みます。
この設計により、型の競合を防ぎつつ、両方のテストフレームワークを快適に使用できます。
まとめ
本記事では、ESLint と TypeScript において Vitest および Playwright のグローバル環境と型を正しく設定する方法を解説しました。
重要なポイントをまとめます。
| # | 項目 | 設定内容 |
|---|---|---|
| 1 | ESLint | 専用プラグインをインストールし、グローバル環境を設定 |
| 2 | TypeScript | tsconfig.json の types でフレームワークの型定義を指定 |
| 3 | ファイル分離 | テストの種類ごとに設定を分けることで型の競合を防ぐ |
| 4 | Flat Config | ESLint 9.x 以降では Flat Config 形式を使用 |
これらの設定を適切に行うことで、以下のメリットが得られます。
no-undefや TypeScript の型エラーが解消される- エディタの自動補完と IntelliSense が正常に機能する
- CI での Lint チェックがスムーズに通過する
- 開発体験が大幅に向上し、生産性が高まる
テストコードを書く際には、実行時の動作だけでなく、静的解析ツールとの連携も重要です。
本記事で紹介した設定方法を参考に、快適なテスト環境を構築していただければ幸いです。
関連リンク
articleESLint × Vitest/Playwright:テスト環境のグローバルと型を正しく設定
articleESLint パーサ比較:espree と @typescript-eslint/parser の互換性と速度
articleESLint が遅い時の処方箋:--cache/並列化/ルール絞り込みの実践
articleESLint の内部構造を覗く:Parser・Scope・Rule・Fixer の連携を図解
articleESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化
articleESLint シェアラブル設定の設計術:単一ソースで Web/Node/React をカバー
articleAstro でレイアウト崩れが起きる原因を特定する手順:スロット/スコープ/スタイル隔離
articleESLint × Vitest/Playwright:テスト環境のグローバルと型を正しく設定
articleDify を Kubernetes にデプロイ:Helm とスケーリング設計の実践
articleApollo のキャッシュ思想を俯瞰する:正規化・型ポリシー・部分データの取り扱い
articleZod で“境界”を守る設計思想:IO バリデーションと型推論の二刀流
articleYarn vs npm vs pnpm 徹底比較:速度・メモリ・ディスク・再現性を実測
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来