Playwright 認証(Authentication)
この章では、Playwright で認証を処理し、各テストでログインを繰り返すことを避けつつ、テストの分離性を維持する方法を紹介します。
認証の核心的な問題
ほとんどの Web アプリケーションのテストでは、ユーザーログインが必要です。
各テストで最初からログインプロセスを実行すると、テスト速度が大幅に遅くなります。
Playwright の解決策は次のとおりです:一度認証し、状態を保存し、すべてのテストで再利用する。
準備作業:.auth ディレクトリ
例
# 認証状態の保存ディレクトリを作成
mkdir -p playwright/.auth
# .gitignore に追加(認証状態には機密情報が含まれる)
echo 'playwright/.auth' >> .gitignore
mkdir -p playwright/.auth
# .gitignore に追加(認証状態には機密情報が含まれる)
echo 'playwright/.auth' >> .gitignore
.authファイルには機密の Cookie と認証 Token が含まれるため、決してコードリポジトリにコミットしてはいけません。
基本方式:共有アカウント + Setup プロジェクト
これは Playwright が推奨する認証方式で、すべてのテストが同じテストアカウントを共有するシナリオに適しています。
ステップ1:認証 Setup を作成
例
// ファイルパス:tests/auth.setup.ts
import { test as setup } from '@playwright/test';
// 認証状態の保存パスを指定
const authFile = 'playwright/.auth/user.json';
setup('authenticate', async ({ page }) => {
// ログイン操作を実行
await page.goto('https://www.example.com/login');
await page.getByLabel('ユーザー名').fill('testuser');
await page.getByLabel('パスワード').fill('password123');
await page.getByRole('button', { name: 'ログイン' }).click();
// ログイン完了を待機(ページ遷移またはユーザー情報の表示を確認)
await page.waitForURL(/dashboard/);
// 現在の認証状態(Cookie、localStorage)をファイルに保存
await page.context().storageState({ path: authFile });
});
import { test as setup } from '@playwright/test';
// 認証状態の保存パスを指定
const authFile = 'playwright/.auth/user.json';
setup('authenticate', async ({ page }) => {
// ログイン操作を実行
await page.goto('https://www.example.com/login');
await page.getByLabel('ユーザー名').fill('testuser');
await page.getByLabel('パスワード').fill('password123');
await page.getByRole('button', { name: 'ログイン' }).click();
// ログイン完了を待機(ページ遷移またはユーザー情報の表示を確認)
await page.waitForURL(/dashboard/);
// 現在の認証状態(Cookie、localStorage)をファイルに保存
await page.context().storageState({ path: authFile });
});
ステップ2:Setup プロジェクトを設定
例
// ファイルパス:playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
// Setup プロジェクト —— 一度だけ実行し、認証状態ファイルを生成
{
name: 'setup',
testMatch: /auth\.setup\.ts/,
},
// 実際のテストプロジェクト —— 認証状態を再利用
{
name: 'chromium',
use: {
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'], // setup プロジェクトに依存し、setup が先に実行されることを保証
},
],
});
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
// Setup プロジェクト —— 一度だけ実行し、認証状態ファイルを生成
{
name: 'setup',
testMatch: /auth\.setup\.ts/,
},
// 実際のテストプロジェクト —— 認証状態を再利用
{
name: 'chromium',
use: {
storageState: 'playwright/.auth/user.json',
},
dependencies: ['setup'], // setup プロジェクトに依存し、setup が先に実行されることを保証
},
],
});
ステップ3:テストで認証状態を直接使用
例
// ファイルパス:tests/dashboard.spec.ts
import { test, expect } from '@playwright/test';
test('ダッシュボードを表示', async ({ page }) => {
// ログインが必要なページに直接アクセス。page はすでに認証状態を持っている
await page.goto('/dashboard');
await expect(page.getByText('おかえりなさい、testuser')).toBeVisible();
});
import { test, expect } from '@playwright/test';
test('ダッシュボードを表示', async ({ page }) => {
// ログインが必要なページに直接アクセス。page はすでに認証状態を持っている
await page.goto('/dashboard');
await expect(page.getByText('おかえりなさい、testuser')).toBeVisible();
});
複数アカウントのシナリオ
テストごとに異なるアカウントが必要な場合は、複数の認証状態ファイルを作成できます。
例
// 管理者テスト
test.describe('管理者機能', () => {
test.use({ storageState: 'playwright/.auth/admin.json' });
test('ユーザー管理', async ({ page }) => {
// 管理者として操作
});
});
// 一般ユーザーテスト
test.describe('一般ユーザー機能', () => {
test.use({ storageState: 'playwright/.auth/user.json' });
test('コンテンツを閲覧', async ({ page }) => {
// 一般ユーザーとして操作
});
});
test.describe('管理者機能', () => {
test.use({ storageState: 'playwright/.auth/admin.json' });
test('ユーザー管理', async ({ page }) => {
// 管理者として操作
});
});
// 一般ユーザーテスト
test.describe('一般ユーザー機能', () => {
test.use({ storageState: 'playwright/.auth/user.json' });
test('コンテンツを閲覧', async ({ page }) => {
// 一般ユーザーとして操作
});
});
API リクエストによる認証(推奨)
UI によるログインプロセスは遅いため、より効率的な方法はログイン API を直接呼び出すことです。
例
// ファイルパス:tests/auth.setup.ts
import { test as setup } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';
setup('API による認証', async ({ request }) => {
// ブラウザ UI を介さず、ログイン API を直接呼び出す
const response = await request.post('https://www.example.com/api/login', {
data: {
username: 'testuser',
password: 'password123',
},
});
// ログイン成功を確認
const json = await response.json();
console.log('ログイン成功、Token:', json.token);
// Token を Cookie として保存(ブラウザの認証状態をシミュレート)
// 注意:storageState はブラウザ Context に保存する必要がある
});
import { test as setup } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';
setup('API による認証', async ({ request }) => {
// ブラウザ UI を介さず、ログイン API を直接呼び出す
const response = await request.post('https://www.example.com/api/login', {
data: {
username: 'testuser',
password: 'password123',
},
});
// ログイン成功を確認
const json = await response.json();
console.log('ログイン成功、Token:', json.token);
// Token を Cookie として保存(ブラウザの認証状態をシミュレート)
// 注意:storageState はブラウザ Context に保存する必要がある
});
API 認証は UI 認証より高速で信頼性が高く、実際のプロジェクトで優先的に使用することをお勧めします。
認証方式の適用シナリオまとめ
| シナリオ | 推奨方式 |
|---|---|
| すべてのテストで同じテストアカウントを使用 | Setup プロジェクト + storageState |
| 異なるタイプのテストで異なるアカウントが必要 | 複数の storageState + test.use |
| 各テストで独立したアカウントが必要 | 各テスト内で API によりアカウントを作成してログイン |
| アカウントリソースが限られている | Setup プロジェクトで一度認証し、すべて再利用 |