PlaywrightでGoogle認証をスキップ
当初は入力欄を見つけて入力する形式で認証を行なっていたのですが、何度かやっているとCAPTCHAが出るようになってしまった。
test('Google login', async ({ page }) => {
await page.click('text=Sign in with Google')
await page.fill('input[type="email"]', 'test@example.com')
await page.fill('input[type="password"]', 'password')
await page.click('button[type="submit"]')
// ここで画像認証が表示されテスト失敗
})
認証を「突破」ではなく「回避」する
Google認証を突破するのではなく、テスト時のみ認証をスキップする設計に変更。
1. NextAuth設定でテスト環境を分岐
// app/api/auth/[...nextauth]/options.ts
export const options: NextAuthOptions = {
callbacks: {
async jwt({ token }) {
// テスト環境では固定ユーザーを返す
if (process.env.SKIP_AUTH === 'true') {
return {
email: 'test@example.com',
name: 'Test User',
id: 'test-user-123',
}
}
return token // 本番は通常フロー
},
async session({ session }) {
if (process.env.SKIP_AUTH === 'true') {
return {
user: { email: 'test@example.com', name: 'Test User' },
expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
}
}
return session
},
},
}
2. Playwrightで認証状態を自動生成
// tests/auth.setup.ts
import { test as setup } from '@playwright/test'
import fs from 'fs'
setup('authenticate', async () => {
// 認証済み状態のJSONを生成
const authState = {
cookies: [
{
name: 'next-auth.session-token',
value: 'mock-session-token',
domain: 'localhost',
path: '/',
expires: Math.floor(Date.now() / 1000) + 3600,
},
],
}
fs.mkdirSync('playwright/.auth', { recursive: true })
fs.writeFileSync('playwright/.auth/user.json', JSON.stringify(authState))
})
3. Playwright設定
// playwright.config.ts
export default defineConfig({
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'chromium',
use: { storageState: 'playwright/.auth/user.json' }, // 認証状態を読み込み
dependencies: ['setup'],
},
],
webServer: {
command: 'npm run dev',
env: { SKIP_AUTH: 'true' }, // 認証をスキップ
},
})
本番環境ではスキップしないように
// middleware.ts
export async function middleware(req: NextRequest) {
if (process.env.APP_ENV === 'production') {
// 通常の認証チェック
}
}
まとめ
実際のプロジェクトではセキュアトークンの生成や詳細な検証をしていますが、核の部分は同じ構造です。
元々の形式だとログインに失敗するケースがあり、今回の改修はいずれやるべき対応だったので良い機会でした。