import { test, expect } from "@playwright/test"; const ADMIN_USER = process.env.ADMIN_TEST_USERNAME || "admin"; const ADMIN_PASS = process.env.ADMIN_TEST_PASSWORD || "admin123"; async function checkBackendAvailable(): Promise { try { const ctrl = new AbortController(); const id = setTimeout(() => ctrl.abort(), 2000); const res = await fetch("http://localhost:3001/api/health", { signal: ctrl.signal }); clearTimeout(id); return res.ok; } catch { return false; } } async function uiLogin(page: Parameters[0]): Promise { try { await page.goto("/login"); await page.fill("input#username", ADMIN_USER); await page.fill("input#password", ADMIN_PASS); await page.click('button[type="submit"]'); await page.waitForURL((url) => !url.toString().includes("/login"), { timeout: 8000 }); return true; } catch { return false; } } test.describe("Admin 用户 CRUD API", () => { test("GET /api/users/[id] 返回用户详情(含角色)", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const randomUser = `testuser_${Date.now()}`; const createRes = await page.request.post("/api/users", { data: { username: randomUser, password: "TestPass123!", roleIds: [] }, }); if (createRes.status() > 201) { test.skip(); } const created = await createRes.json(); const userId = created.user?.id; if (!userId) { test.skip(); } const res = await page.request.get(`/api/users/${userId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(data).toHaveProperty("username"); expect(data).toHaveProperty("roles"); expect(Array.isArray(data.roles)).toBe(true); expect(data).not.toHaveProperty("password_hash"); await page.request.delete(`/api/users/${userId}`); }); test("GET /api/users/[id] 不存在的用户返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/users/999999"); expect(res.status()).toBe(404); }); test("PUT /api/users/[id] 更新用户密码和状态", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const randomUser = `testuser_${Date.now()}`; const createRes = await page.request.post("/api/users", { data: { username: randomUser, password: "TestPass123!", roleIds: [] }, }); if (createRes.status() > 201) { test.skip(); } const created = await createRes.json(); const userId = created.user?.id; if (!userId) { test.skip(); } const res = await page.request.put(`/api/users/${userId}`, { data: { password: "NewPass123!", isActive: true }, }); expect(res.status()).toBe(200); await page.request.delete(`/api/users/${userId}`); }); test("PUT /api/users/[id] 更新用户角色", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const rolesRes = await page.request.get("/api/roles"); const roles = (await rolesRes.json()).roles || []; if (!roles.length) { test.skip(); } const roleId = roles[0].id; const randomUser = `testuser_${Date.now()}`; const createRes = await page.request.post("/api/users", { data: { username: randomUser, password: "TestPass123!", roleIds: [] }, }); if (createRes.status() > 201) { test.skip(); } const created = await createRes.json(); const userId = created.user?.id; if (!userId) { test.skip(); } const res = await page.request.put(`/api/users/${userId}`, { data: { roleIds: [roleId] }, }); expect(res.status()).toBe(200); await page.request.delete(`/api/users/${userId}`); }); test("PUT /api/users/[id] 不存在的用户返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.put("/api/users/999999", { data: { isActive: false }, }); expect(res.status()).toBe(404); }); test("DELETE /api/users/[id] 删除用户", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const randomUser = `testuser_${Date.now()}`; const createRes = await page.request.post("/api/users", { data: { username: randomUser, password: "TestPass123!", roleIds: [] }, }); if (createRes.status() > 201) { test.skip(); } const created = await createRes.json(); const userId = created.user?.id; if (!userId) { test.skip(); } const res = await page.request.delete(`/api/users/${userId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(data.success).toBe(true); }); test("DELETE /api/users/[id] 不存在的用户返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.delete("/api/users/999999"); expect(res.status()).toBe(404); }); test("DELETE /api/users/1 禁止删除超级管理员", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.delete("/api/users/1"); expect(res.status()).toBe(400); }); }); test.describe("Admin 角色 CRUD API", () => { test("GET /api/roles/[id] 返回角色详情(含权限)", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const rolesRes = await page.request.get("/api/roles"); const roles = (await rolesRes.json()).roles || []; if (!roles.length) { test.skip(); } const roleId = roles[0].id; const res = await page.request.get(`/api/roles/${roleId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(data).toHaveProperty("name"); expect(data).toHaveProperty("description"); }); test("GET /api/roles/[id] 不存在的角色返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/roles/999999"); expect(res.status()).toBe(404); }); test("PUT /api/roles/[id] 更新角色", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const rolesRes = await page.request.get("/api/roles"); const roles = (await rolesRes.json()).roles || []; const testRole = roles.find((r: { name: string }) => r.name !== "超级管理员"); if (!testRole) { test.skip(); } const res = await page.request.put(`/api/roles/${testRole.id}`, { data: { name: `${testRole.name}_updated`, description: "Updated description" }, }); expect(res.status()).toBe(200); }); test("PUT /api/roles/[id] 更新角色权限", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const rolesRes = await page.request.get("/api/roles"); const roles = (await rolesRes.json()).roles || []; const permsRes = await page.request.get("/api/permissions"); const perms = (await permsRes.json()).permissions || []; if (!roles.length || !perms.length) { test.skip(); } const testRole = roles.find((r: { name: string }) => r.name !== "超级管理员"); if (!testRole) { test.skip(); } const res = await page.request.put(`/api/roles/${testRole.id}`, { data: { permissionIds: [perms[0].id] }, }); expect(res.status()).toBe(200); }); test("PUT /api/roles/[id] 不存在的角色返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.put("/api/roles/999999", { data: { name: "Updated" }, }); expect(res.status()).toBe(404); }); test("DELETE /api/roles/[id] 删除角色", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const randomRole = `testrole_${Date.now()}`; const createRes = await page.request.post("/api/roles", { data: { name: randomRole, description: "Test role for CRUD" }, }); if (createRes.status() > 201) { test.skip(); } const created = await createRes.json(); const roleId = created.id; if (!roleId) { test.skip(); } const res = await page.request.delete(`/api/roles/${roleId}`); expect([200, 404]).toContain(res.status()); }); test("DELETE /api/roles/1 禁止删除超级管理员角色", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.delete("/api/roles/1"); expect(res.status()).toBe(400); }); });