import { expect, test } from "@playwright/test"; test.describe("User Schema Dynamic Form", () => { test.beforeEach(async ({ page }) => { await page.addInitScript(() => { const authority = "http://localhost:5000/oidc"; const client_id = "adminfront"; const key = `oidc.user:${authority}:${client_id}`; const authData = { access_token: "fake-token", token_type: "Bearer", profile: { sub: "admin-user", name: "Admin", role: "super_admin" }, expires_at: Math.floor(Date.now() / 1000) + 36000, }; window.localStorage.setItem(key, JSON.stringify(authData)); window.localStorage.setItem("admin_session", "fake-token"); window.localStorage.setItem("locale", "ko"); ( window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean } )._IS_TEST_MODE = true; }); await page.route("**/oidc/**", async (route) => { await route.fulfill({ json: { issuer: "http://localhost:5000/oidc" } }); }); await page.route(/.*\/api\/v1\/.*/, async (route) => { const url = route.request().url(); if (url.includes("/user/me")) { console.log("Mocking ME"); return route.fulfill({ json: { id: "admin-user", name: "Admin", role: "super_admin", manageableTenants: [], }, }); } if (url.includes("/admin/tenants/t-1")) { return route.fulfill({ json: { id: "t-1", name: "Test Tenant", slug: "test-tenant", config: { userSchema: [ { key: "emp_id", label: "Employee ID", required: true, validation: "^E[0-9]{3}$", }, { key: "salary", label: "Salary", adminOnly: true, type: "number", }, ], }, }, }); } if (url.includes("/admin/users/u-1")) { return route.fulfill({ json: { id: "u-1", name: "John Doe", email: "john@test.com", tenantSlug: "test-tenant", tenant: { id: "t-1", name: "Test Tenant", slug: "test-tenant" }, joinedTenants: [ { id: "t-1", name: "Test Tenant", slug: "test-tenant" }, ], metadata: { "t-1": { emp_id: "E123", salary: 1000 } }, }, }); } if (url.includes("/admin/tenants")) { return route.fulfill({ json: { items: [{ id: "t-1", slug: "test-tenant", name: "Test Tenant" }], total: 1, }, }); } return route.fulfill({ json: { items: [], total: 0 } }); }); }); test("should render custom fields from schema in user detail", async ({ page, }) => { await page.goto("/users/u-1"); await page.waitForLoadState("networkidle"); // 섹션 헤더 확인 const header = page .getByText(/테넌트별 프로필 관리|Per-tenant Profile/i) .first(); await header.waitFor({ state: "visible" }); // 커스텀 필드 레이블 확인 await expect(page.getByText("Employee ID")).toBeVisible(); // input 값 확인 (id에 t-1.emp_id가 포함됨) const empIdInput = page.locator('input[id*="emp_id"]'); await expect(empIdInput).toHaveValue("E123"); const salaryInput = page.locator('input[id*="salary"]'); await expect(salaryInput).toHaveValue("1000"); await expect(page.getByText(/Admin Only/i).first()).toBeVisible(); }); test("should show regex validation error for custom field", async ({ page, }) => { await page.goto("/users/u-1"); await page.waitForLoadState("networkidle"); const empIdInput = page.locator('input[id*="emp_id"]'); await empIdInput.waitFor({ state: "visible" }); await empIdInput.fill("invalid"); // 포커스 해제하여 유효성 검사 트리거 await page.getByLabel(/이름|Name/i).click(); // 에러 메시지 확인 const errorMsg = page .locator("form") .getByText(/Employee ID|필수|invalid|format/i); await expect(errorMsg).toBeVisible(); }); });