/** * E2E 测试 — 登录流程。 * * 前置条件:后端 http://localhost:8000 + 前端 http://localhost:3000 已启动。 * 测试用户通过 API 注册接口在 beforeAll 中创建。 */ import { test, expect, type Page } from "@playwright/test"; const API_BASE = "http://localhost:8000/api/v1"; const TEST_EMAIL = `e2e_${Date.now()}@example.com`; const TEST_PASSWORD = "password123"; async function registerUser() { const resp = await fetch(`${API_BASE}/auth/register`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: TEST_EMAIL, password: TEST_PASSWORD, name: "E2E测试用户", tenant_name: "E2E测试机构", role: "investor", }), }); if (!resp.ok) { const body = await resp.text(); throw new Error(`注册失败: ${resp.status} ${body}`); } } test.describe("登录流程", () => { test.beforeAll(async () => { await registerUser(); }); test("应能登录并跳转到驾驶舱", async ({ page }: { page: Page }) => { await page.goto("/login"); // 填写登录表单 await page.fill('input[id="email"]', TEST_EMAIL); await page.fill('input[id="password"]', TEST_PASSWORD); // 提交登录 await page.click('button[type="submit"]'); // 应跳转到驾驶舱 await expect(page).toHaveURL(/\/dashboard/); // 驾驶舱标题应可见 await expect(page.locator("h1")).toContainText("投资机构驾驶舱"); }); test("登录失败应显示错误信息", async ({ page }: { page: Page }) => { await page.goto("/login"); await page.fill('input[id="email"]', "wrong@example.com"); await page.fill('input[id="password"]', "wrongpassword"); await page.click('button[type="submit"]'); // 应停留在登录页 await expect(page).toHaveURL(/\/login/); // 应显示错误提示 await expect(page.locator("p.text-\\[var\\(--destructive\\)\\]")).toContainText(/邮箱或密码错误|登录失败|密码错误|用户不存在/); }); test("未登录访问受保护页面应重定向到登录", async ({ page }: { page: Page }) => { // 清除 token await page.goto("/login"); await page.evaluate(() => { localStorage.removeItem("token"); localStorage.removeItem("refresh_token"); }); // 访问驾驶舱 await page.goto("/dashboard"); // 应重定向到登录页 await expect(page).toHaveURL(/\/login/); }); });