diff --git a/devfront/tests/clients.spec.ts b/devfront/tests/clients.spec.ts index fc08050b..134813f1 100644 --- a/devfront/tests/clients.spec.ts +++ b/devfront/tests/clients.spec.ts @@ -1,5 +1,6 @@ import { expect, test } from "@playwright/test"; import { + type DevAssignableUser, type AuditLog, type Consent, installDevApiMock, @@ -89,8 +90,118 @@ test("clients page shows recent RP changes", async ({ page }) => { }); await page.goto("/clients"); - await expect(page.getByText("최근 변경된 RP")).toBeVisible(); + await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible(); await expect(page.getByText("클라이언트 시크릿 재발급")).toBeVisible(); await expect(page.getByText("관계 추가")).toBeVisible(); - await expect(page.getByText("Recent RP")).toBeVisible(); + await expect( + page.getByRole("link", { name: "Recent RP", exact: true }).first(), + ).toBeVisible(); +}); + +test("clients page shows user-delete relation cleanup in recent changes", async ({ + page, +}) => { + await seedAuth(page, "super_admin"); + await installDevApiMock(page, { + clients: [ + makeClient("client-cleanup", { + name: "Cleanup RP", + }), + ], + consents: [] as Consent[], + users: [ + { + id: "cleanup-actor", + name: "Cleanup Actor", + email: "cleanup.actor@example.com", + } satisfies DevAssignableUser, + ], + auditLogs: [ + { + event_id: "evt-cleanup-1", + timestamp: "2026-03-03T09:00:00.000Z", + user_id: "cleanup-actor", + event_type: "CLIENT_RELATION_DELETE", + status: "success", + ip_address: "127.0.0.1", + user_agent: "playwright", + details: JSON.stringify({ + action: "REMOVE_RELATION", + target_id: "client-cleanup", + relation: "config_editor", + subject: "User:deleted-user", + before: { + relation: "config_editor", + subject: "User:deleted-user", + }, + }), + }, + ] as AuditLog[], + auditLogsByCursor: undefined, + }); + + await page.goto("/clients"); + await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible(); + await expect( + page.getByRole("link", { name: "Cleanup RP", exact: true }), + ).toBeVisible(); + await expect(page.getByText("관계 삭제", { exact: true })).toBeVisible(); + await expect(page.getByText(/관계:\s*config_editor/)).toBeVisible(); + await expect(page.getByText(/대상:\s*User:deleted-user/)).toBeVisible(); + await expect( + page.getByText("cleanup-actor", { exact: true }).first(), + ).toBeVisible(); +}); + +test("clients page expands recent changes with more button", async ({ page }) => { + await seedAuth(page, "super_admin"); + const clients = Array.from({ length: 6 }, (_, index) => + makeClient(`client-${index + 1}`, { + name: `Recent App ${index + 1}`, + }), + ); + const auditLogs = clients.map((client, index) => ({ + event_id: `evt-recent-${index + 1}`, + timestamp: `2026-03-03T09:${String(10 - index).padStart(2, "0")}:00.000Z`, + user_id: `actor-${index + 1}`, + event_type: "CLIENT_CREATE", + status: "success" as const, + ip_address: "127.0.0.1", + user_agent: "playwright", + details: JSON.stringify({ + action: "CREATE_CLIENT", + target_id: client.id, + after: { + name: client.name, + }, + }), + })); + + await installDevApiMock(page, { + clients, + consents: [] as Consent[], + auditLogs: auditLogs as AuditLog[], + auditLogsByCursor: undefined, + }); + + await page.goto("/clients"); + await expect(page.getByRole("heading", { name: "최근 변경된 앱" })).toBeVisible(); + await expect( + page.getByRole("link", { name: "Recent App 1", exact: true }), + ).toBeVisible(); + await expect( + page.getByRole("link", { name: "Recent App 5", exact: true }), + ).toBeVisible(); + await expect( + page.getByRole("link", { name: "Recent App 6", exact: true }), + ).not.toBeVisible(); + + const moreButton = page.getByRole("button", { name: "더 보기" }); + await expect(moreButton).toBeVisible(); + await moreButton.click(); + + await expect( + page.getByRole("link", { name: "Recent App 6", exact: true }), + ).toBeVisible(); + await expect(moreButton).toHaveCount(0); });