Next.js × Auth0でアプリを開発しています。
Next.jsではServer Componentを採用しており、Playwrightでコンポーネント統合テスト1を実施しています。
しかし毎回ログイン画面に遷移して、IDとパスワードを入力するのは時間も手間もかかって大変でした。
そこで、nextjs-auth0のヘルパーメソッドを使って、ログイン状態をスキップできる方法を試してみることにしました。
nextjs-auth0のヘルパーでログイン状態を作る
nextjs-auth0にはテスト用のユーティリティとして、generateSessionCookie
というメソッドが提供されています。
これは、Auth0の認証フローにて、IDトークンとアクセストークンを疑似的に再現することで、ログイン後のセッション情報を作成できます。
※ Auth0の認証フローをもとに作成
このセッションCookieを用意することで、ログイン状態が必要なページ(middleware.tsなどで保護されているルート)に対しても、ログイン済みとしてアクセスできるようになります。
import { NextRequest, NextResponse } from "next/server"
import { auth0 } from "@/lib/auth0"
export async function middleware(request: NextRequest) {
const authRes = await auth0.middleware(request)
if (request.nextUrl.pathname.startsWith("/auth")) {
return authRes
}
// ここでログイン状態かを確認している
const session = await auth0.getSession(request)
if (!session) {
// user is not authenticated, redirect to login page
return NextResponse.redirect(new URL("/auth/login", request.nextUrl.origin))
}
// the headers from the auth middleware should always be returned
return authRes
}
※ nextjs-auth0のExamples.mdのAccessing the authenticated userのサンプルを記載
実装例
開発環境
- TypeScript : 5.8.3
- Next.js 15.2.4
- playwright/test 1.51.0
- nextjs-auth0 4.4.1
nextjs-auth0 4.4.1を活用しています。
最新版(4.4.2)では不具合2が発生しており、動作していません。
サンプルコード
Playwrightのfixtureにて、sessionを疑似生成し、playwrightでcookieに追加3します。
import { test as base, Page } from "@playwright/test";
export const test = base.extend<{ page: Page }>({
page: async ({ browser }, use) => {
const context = await browser.newContext();
// MEMO: ESModuleをサポートしていないため、Auth0のテスト用モジュールを動的にインポート
const { generateSessionCookie } = await import("@auth0/nextjs-auth0/testing");
const sessionCookieValue = await generateSessionCookie(
{
user: {
sub: `auth0|${Math.floor(Math.random() * 1000000).toString()}`,
name: "Sample",
email: "sample@example.com",
},
tokenSet: {
accessToken: Math.floor(Math.random() * 1000000).toString(),
expiresAt: Math.floor(Date.now() / 1000) + 3600,
},
},
{
secret: process.env.AUTH0_SECRET!,
},
);
// 疑似作成したセッションをCookieに追加
await context.addCookies([
{
name: "appSession",
value: sessionCookieValue,
domain: "localhost",
path: "/",
httpOnly: true,
secure: false,e
sameSite: "Lax",
},
]);
const page = await context.newPage();
await use(page);
await context.close();
},
});
export { expect } from '@playwright/test';
あとは作成したfixtureをテストで利用します。
import { test, expect } from './login';
test('sample test', async ({ page }) => {
await page.goto("/user"); // ログイン処理を飛ばしている
await expect(page.getByTestId('title')).toContainText("Sample Title);
});
この方法により、毎回IDとパスワードを入力せずにテストできるようになり、本来確認したい処理や画面遷移のテストに集中できます。
参考情報
-
コンポーネント間のインターフェース、および相互処理に焦点を当てる。コンポーネント統合テストは、ボトムアップ、トップダウン、ビックバンといった統合戦略のアプローチに大きく依存する(ISTQBテスト技術者資格制度
Foundation Level シラバス 日本語版 Version 2023V4.0.J02 2.2.1 テストレベル) ↩ -
https://playwright.dev/python/docs/next/api/class-browsercontext#browser-context-add-cookies ↩