はじめに
playwrightの実験的機能であるコンポーネントテストでの、ログイン状態の再現について他に類似する記事が存在しなかったため、備忘録として残させていただきます。
以下の内容はclient componentでのみ動作の確認が取れています。
環境
- React 19.0.0
- Next.js 15.1.6
- Auth.js 5.0.0-beta.25
- @playwright/experimental-ct-react 1.50.1
- @playwright/test 1.50.1
client componentでのsessionの取得例
セッションを取得したいコンポーネントをSessionProviderで囲む
layout
/app/layout.tsx
import { SessionProvider } from "next-auth/react";
import { ClientComponent } from "@/app/ui/ClientComponent"
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<SessionProvider>
<html lang="ja">
<body>
<ClientComponent />
{children}
</body>
</html>
</SessionProvider>
);
}
client components
app/ui/ClientComponent.tsx
"use client"
import { useSession } from "next-auth/react"
export default function ClientComponent() {
const { data: session } = useSession()
// ログイン状況に応じて、Sessionもしくはnullが返却される
if (session) {
return <p>under signin</p>
}
return <p>You are not authenticated</p>
}
上記のようなコンポーネントにおいてセッションを取得する際、/api/auth/sessionへのリクエストが発生し、json形式にてsession情報が返却されます
component testにおける対応
以下の2点の対応が必要です
-
/api/auth/sessionへのリクエストへのモック実装 -
/playwright/index.tsxへのSessionProviderの追加
モック実装
playwirghtのモック機能を利用し対応
複数のテストファイル間で利用するためヘルパーとして実装
tests/__helpers__/signin.ts
import { Page } from "@playwright/test";
import type { Session } from "next-auth";
export const mockClientSession = async (page: Page, json: Session | null) => {
await page.route("*/**/api/auth/session", async (route) => {
await route.fulfill({ json, contentType: "application/json" });
});
};
/playwright/index.tsx
/playwright/index.tsx
import { beforeMount } from "@playwright/experimental-ct-react/hooks";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
import theme from "@/theme";
import { SessionProvider } from "next-auth/react";
beforeMount(({ App }) => {
return Promise.resolve(
<SessionProvider>
<App />
</SessionProvider>,
);
});
実際のテストでの利用
tests/ClinentComponent.spec.tsx
import { test, expect } from "@playwright/experimental-ct-react";
import ClientComponent from "@/app/ui/ClientComponent";
import { mockClientSession } from "./__helpers__/signin";
test.describe("Drawer", () => {
test.describe("before login", () => {
test.beforeEach(async ({ page }) => {
// ログアウト状態の場合はnullを渡す
await mockClientSession(page, null);
});
test("should allow me to show not authenticated text", async ({ mount }) => {
const component = await mount(<ClientComponent />);
const text = await page.getByRole("paragraph", {
name: "You are not authenticated"
});
await expect(text).toBeVisible();
});
});
test.describe("after login", () => {
test.beforeEach(async ({ page }) => {
const json = {
user: {
name: "testuser",
email: "test_user@example.com",
picture: "https://avatars.githubusercontent.com/u/000000",
nickname: "test nickname",
},
expires: "dummy",
idToken: "dummy",
};
await mockClientSession(page, json);
});
test("should allow me to show authenticated text", async ({ mount }) => {
const component = await mount(<ClientComponent />);
const text = await page.getByRole("paragraph", {
name: "under signin"
});
await expect(text).toBeVisible();
});
});
});
上記のように対応することでコンポーネントテストにおいてログイン、ログアウト状態それぞれのテストを実施することができました