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("平台房间消息 API", () => { test("GET /api/platform/rooms/[id]/messages 返回消息列表", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const roomsRes = await page.request.get("/api/platform/rooms?pageSize=1"); const roomsData = await roomsRes.json(); const roomId = roomsData.rooms?.[0]?.id; if (!roomId) { test.skip(); } const res = await page.request.get(`/api/platform/rooms/${roomId}/messages`); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.messages)).toBe(true); expect(data).toHaveProperty("total"); expect(data).toHaveProperty("page"); expect(data).toHaveProperty("pageSize"); }); test("GET /api/platform/rooms/[id]/messages 支持分页", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const roomsRes = await page.request.get("/api/platform/rooms?pageSize=1"); const roomsData = await roomsRes.json(); const roomId = roomsData.rooms?.[0]?.id; if (!roomId) { test.skip(); } const res = await page.request.get(`/api/platform/rooms/${roomId}/messages?page=1&pageSize=5`); expect(res.status()).toBe(200); const data = await res.json(); expect(data.messages.length).toBeLessThanOrEqual(5); }); test("GET /api/platform/rooms/[id]/messages 不存在的房间返回空列表", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/platform/rooms/nonexistent-room-id/messages"); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.messages)).toBe(true); }); test("DELETE /api/platform/rooms/[id]/messages/[msgId] 撤回消息", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const roomsRes = await page.request.get("/api/platform/rooms?pageSize=1"); const roomsData = await roomsRes.json(); const roomId = roomsData.rooms?.[0]?.id; if (!roomId) { test.skip(); } const msgRes = await page.request.get(`/api/platform/rooms/${roomId}/messages?pageSize=1`); const msgData = await msgRes.json(); const msgId = msgData.messages?.[0]?.id; if (!msgId) { test.skip(); } const res = await page.request.delete(`/api/platform/rooms/${roomId}/messages/${msgId}`); expect([200, 404]).toContain(res.status()); if (res.status() === 200) { const data = await res.json(); expect(data.success).toBe(true); } }); test("DELETE /api/platform/rooms/[id]/messages/[msgId] 不存在的消息返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const roomsRes = await page.request.get("/api/platform/rooms?pageSize=1"); const roomsData = await roomsRes.json(); const roomId = roomsData.rooms?.[0]?.id; if (!roomId) { test.skip(); } const res = await page.request.delete(`/api/platform/rooms/${roomId}/messages/nonexistent-msg-id`); expect(res.status()).toBe(404); }); }); test.describe("平台房间列表 API", () => { test("GET /api/platform/rooms 支持分页", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/platform/rooms?page=1&pageSize=5"); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.rooms)).toBe(true); expect(data.rooms.length).toBeLessThanOrEqual(5); expect(data).toHaveProperty("total"); }); test("GET /api/platform/rooms 支持搜索", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/platform/rooms?search=general"); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.rooms)).toBe(true); }); test("GET /api/platform/rooms 支持按项目筛选", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const roomsRes = await page.request.get("/api/platform/rooms?pageSize=1"); const roomsData = await roomsRes.json(); const projectId = roomsData.rooms?.[0]?.projectId; if (!projectId) { test.skip(); } const res = await page.request.get(`/api/platform/rooms?projectId=${projectId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.rooms)).toBe(true); }); }); test.describe("平台仓库 API", () => { test("GET /api/platform/repos 支持分页", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/platform/repos?page=1&pageSize=5"); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.repos)).toBe(true); expect(data.repos.length).toBeLessThanOrEqual(5); }); test("GET /api/platform/repos 支持搜索", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/platform/repos?search=test"); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.repos)).toBe(true); }); test("GET /api/platform/repos 支持按项目筛选", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const reposRes = await page.request.get("/api/platform/repos?pageSize=1"); const reposData = await reposRes.json(); const projectId = reposData.repos?.[0]?.projectId; if (!projectId) { test.skip(); } const res = await page.request.get(`/api/platform/repos?projectId=${projectId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data.repos)).toBe(true); }); test("GET /api/admin/repos/[id] 返回仓库详情含分支和提交", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const reposRes = await page.request.get("/api/platform/repos?pageSize=1"); const reposData = await reposRes.json(); const repoId = reposData.repos?.[0]?.id; if (!repoId) { test.skip(); } const res = await page.request.get(`/api/admin/repos/${repoId}`); expect(res.status()).toBe(200); const data = await res.json(); expect(data).toHaveProperty("repo"); expect(data).toHaveProperty("branches"); expect(data).toHaveProperty("commits"); expect(Array.isArray(data.branches)).toBe(true); expect(Array.isArray(data.commits)).toBe(true); }); test("GET /api/admin/repos/[id] 不存在的仓库返回404", async ({ page }) => { if (!await checkBackendAvailable()) { test.skip(); } if (!await uiLogin(page)) { test.skip(); } const res = await page.request.get("/api/admin/repos/nonexistent-repo-id"); expect(res.status()).toBe(404); }); });