import { expect, test } from "@playwright/test"; import { type Consent, installDevApiMock, makeClient, seedAuth, } from "./helpers/devfront-fixtures"; import { captureEvidence } from "./helpers/evidence"; import { installDevFrontStaticRoutes } from "./helpers/static-devfront"; test.describe("DevFront consents", () => { test.afterEach(async ({ page }, testInfo) => { if (testInfo.status === "passed") { await captureEvidence(page, testInfo, testInfo.title); } }); test.beforeEach(async ({ page }) => { await installDevFrontStaticRoutes(page); page.on("dialog", async (dialog) => { await dialog.accept(); }); await seedAuth(page); }); test("consent list and revoke flow", async ({ page }) => { const state = { clients: [ makeClient("client-consent", { name: "Consent app", metadata: { id_token_claims: [ { namespace: "rp_claims", key: "contract_date", valueType: "date", value: "2026-06-09", }, { namespace: "rp_claims", key: "approved_at", valueType: "datetime", value: "2026-06-09T09:30", }, { namespace: "rp_claims", key: "active_member", valueType: "boolean", value: "true", }, { namespace: "rp_claims", key: "score", valueType: "number", value: "1", }, ], }, }), ], consents: [ { subject: "user-1", userName: "Alice", clientId: "client-consent", clientName: "Consent app", grantedScopes: ["openid", "profile"], authenticatedAt: "2026-03-03T08:00:00.000Z", createdAt: "2026-03-02T08:00:00.000Z", status: "active", tenantId: "tenant-a", tenantName: "Tenant A", rpMetadata: { approvalLevel: "A", approvalLevel_permissions: { readPermission: "admin_only", writePermission: "admin_only", }, }, }, ] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.goto("http://devfront.test/clients/client-consent/consents"); await expect(page.getByText("Alice")).toBeVisible(); await expect(page.getByText("Tenant A")).toBeVisible(); await expect(page.getByText(/approvalLevel:\s*A/)).toBeVisible(); await page.getByRole("button", { name: /Claims|Claim/i }).click(); await expect(page.getByText("RP Custom Claims")).toBeVisible(); await expect(page.getByText("contract_date")).toBeVisible(); await expect(page.getByText("approved_at")).toBeVisible(); await expect(page.getByText("active_member")).toBeVisible(); await expect(page.locator('input[type="date"]')).toHaveValue("2026-06-09"); await expect( page.getByLabel(/contract_date.*timezone|timezone.*contract_date/i), ).toHaveValue( await page.evaluate( () => Intl.DateTimeFormat().resolvedOptions().timeZone, ), ); await page.locator('input[type="date"]').fill("2026-06-10"); await page.locator('input[type="datetime-local"]').fill("2026-06-09T10:30"); await page .getByLabel(/active_member.*boolean|boolean.*active_member/i) .selectOption("false"); await page.getByLabel(/score.*number|number.*score/i).fill("42"); await page .getByLabel(/쓰기 권한|Write permission/i) .first() .selectOption("user_and_admin"); await page.getByRole("button", { name: /Claim 저장|Save Claim/i }).click(); await expect .poll(() => state.consents[0]?.rpMetadata?.contract_date) .toBe(1781017200); await expect .poll(() => state.consents[0]?.rpMetadata?.approved_at) .toBe(1780968600); await expect .poll(() => state.consents[0]?.rpMetadata?.active_member) .toBe(false); await expect.poll(() => state.consents[0]?.rpMetadata?.score).toBe(42); await expect .poll( () => ( state.consents[0]?.rpMetadata?.contract_date_permissions as | Record | undefined )?.writePermission, ) .toBe("user_and_admin"); await page.getByRole("button", { name: /권한 철회|철회|Revoke/i }).click(); await expect(page.getByText(/Revoked|철회/i).first()).toBeVisible(); }); test("does not allow adding undefined RP claims from consents and claims", async ({ page, }) => { const state = { clients: [ makeClient("client-consent", { name: "Consent app", metadata: {}, }), ], consents: [ { subject: "user-1", userName: "Alice", clientId: "client-consent", clientName: "Consent app", grantedScopes: ["openid", "profile"], authenticatedAt: "2026-03-03T08:00:00.000Z", createdAt: "2026-03-02T08:00:00.000Z", status: "active", tenantId: "tenant-a", tenantName: "Tenant A", rpMetadata: {}, }, ] as Consent[], auditLogsByCursor: undefined, }; await installDevApiMock(page, state); await page.goto("http://devfront.test/clients/client-consent/consents"); await page.getByRole("button", { name: /Claims|Claim/i }).click(); await expect(page.getByText("RP Custom Claims")).toBeVisible(); await expect( page.getByRole("button", { name: /^추가$|^Add$/ }), ).toHaveCount(0); await expect(page.getByPlaceholder(/claim_key/i)).toHaveCount(0); }); });