import { expect, request, type APIRequestContext, type Page } from "@playwright/test" import path from "node:path" export const MEDIA = path.resolve(process.cwd(), "../.devdata/testmedia") const BASE = process.env.E2E_BASE_URL ?? "https://localhost:8443" const H = { "X-Requested-With": "mediahub" } export async function adminApi(): Promise { const ctx = await request.newContext({ baseURL: BASE, ignoreHTTPSErrors: true, extraHTTPHeaders: H }) const r = await ctx.post("/api/auth/login", { data: { username: "admin", password: process.env.E2E_ADMIN_PASSWORD } }) expect(r.ok(), await r.text()).toBeTruthy() return ctx } export async function newInvite(): Promise { const admin = await adminApi() const r = await admin.post("/api/admin/invitations", { data: { note: "playwright" } }) const token = (await r.json()).token as string await admin.dispose() return token } let counter = 0 export function uniqueName(prefix: string) { return `${prefix}${Date.now().toString(36)}${(counter++).toString(36)}${Math.floor(Math.random() * 1e4)}` } /** Register a brand-new user through the UI and land on Home. */ export async function registerUser(page: Page): Promise<{ username: string; password: string }> { const token = await newInvite() const username = uniqueName("u") const password = "playwright-pass-123" await page.goto(`/register?token=${token}`) await expect(page.getByText("邀請有效")).toBeVisible() await page.getByLabel("使用者名稱").fill(username) await page.getByLabel("顯示名稱").fill("測試使用者") await page.getByLabel("密碼", { exact: true }).fill(password) await page.getByLabel("確認密碼").fill(password) await page.getByRole("button", { name: "建立帳號" }).click() await expect(page.getByRole("heading", { level: 1, name: "首頁" })).toBeVisible() return { username, password } } /** Fail if the page scrolls horizontally (layout overflow). */ export async function expectNoHorizontalOverflow(page: Page) { const { sw, iw } = await page.evaluate(() => ({ sw: document.documentElement.scrollWidth, iw: window.innerWidth })) expect(sw, `page is ${sw}px wide in a ${iw}px viewport`).toBeLessThanOrEqual(iw + 1) } export function isMobile(page: Page) { return (page.viewportSize()?.width ?? 1200) < 768 } /** Navigate using the sidebar on desktop or the tab bar on mobile. */ export async function navTo(page: Page, label: "首頁" | "照片" | "影片" | "檔案" | "設定") { const nav = page.getByRole("navigation", { name: "主要導覽" }).filter({ visible: true }) const desktopLabel = { 首頁: "首頁", 照片: "圖庫", 影片: "影片庫", 檔案: "我的檔案", 設定: "設定" }[label] await nav.getByRole("link", { name: isMobile(page) ? label : desktopLabel, exact: true }).first().click() }