diff --git a/adminfront/tests/auth.spec.ts b/adminfront/tests/auth.spec.ts deleted file mode 100644 index 77c793f7..00000000 --- a/adminfront/tests/auth.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { expect, test } from "@playwright/test"; - -test.describe("Auth Flow", () => { - test("unauthenticated user is redirected to login", async ({ page }) => { - // Navigate to a protected route without setting localStorage - await page.goto("/"); - - // Check if it redirects to login - await expect(page).toHaveURL(/\/login$/); - - // Verify login page content - await expect(page.getByText("Baron SSO")).toBeVisible(); - await expect(page.getByText("관리자 로그인")).toBeVisible(); - await expect( - page.getByRole("button", { name: "SSO 계정으로 로그인" }), - ).toBeVisible(); - }); - - test("authenticated user can access dashboard", async ({ page }) => { - // Inject mock session - await page.addInitScript(() => { - window.localStorage.setItem("admin_session", "playwright-admin-session"); - }); - - await page.goto("/"); - - // Should stay on dashboard (or another protected route) and not redirect to login - await expect(page).not.toHaveURL(/\/login$/); - }); -}); diff --git a/adminfront/tests/tenants.spec.ts b/adminfront/tests/tenants.spec.ts deleted file mode 100644 index 20df7e27..00000000 --- a/adminfront/tests/tenants.spec.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { TenantCreateRequest, TenantSummary } from "../src/lib/adminApi"; - -test.use({ - storageState: { - cookies: [], - origins: [ - { - origin: "http://localhost:5173", - localStorage: [ - { - name: "admin_session", - value: "playwright-admin-session", - }, - ], - }, - ], - }, -}); - -test("tenant create and delete flow", async ({ page }) => { - const tenants: TenantSummary[] = []; - let idSeq = 1; - - await page.route("**/api/v1/admin/tenants**", async (route) => { - const request = route.request(); - const url = new URL(request.url()); - const path = url.pathname; - const isCollection = path.endsWith("/api/v1/admin/tenants"); - const isItem = path.includes("/api/v1/admin/tenants/"); - - if (request.method() === "GET" && isCollection) { - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - items: tenants, - limit: 50, - offset: 0, - total: tenants.length, - }), - }); - return; - } - - if (request.method() === "POST" && isCollection) { - const payload = request.postDataJSON() as TenantCreateRequest; - const now = new Date().toISOString(); - const tenant: TenantSummary = { - id: `tenant-${idSeq++}`, - name: payload.name, - type: payload.type || "COMPANY", - slug: payload.slug || `slug-${idSeq}`, - description: payload.description || "", - status: payload.status || "active", - domains: payload.domains || [], - createdAt: now, - updatedAt: now, - }; - tenants.unshift(tenant); - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify(tenant), - }); - return; - } - - if (request.method() === "DELETE" && isItem) { - const tenantId = path.split("/").pop(); - const index = tenants.findIndex((t) => t.id === tenantId); - if (index !== -1) { - tenants.splice(index, 1); - } - await route.fulfill({ status: 204, body: "" }); - return; - } - - await route.fallback(); - }); - - await page.goto("/tenants"); - await expect(page).toHaveURL(/\/tenants$/); - await expect( - page.getByRole("heading", { name: "테넌트 목록" }), - ).toBeVisible(); - - // Create - const addTenantLink = page.getByRole("link", { name: "테넌트 추가" }); - await addTenantLink.click(); - await expect(page).toHaveURL(/\/tenants\/new$/); - - const uniqueName = `Test Tenant ${Date.now()}`; - await page.getByLabel("테넌트 이름 *").fill(uniqueName); - await page.getByLabel("테넌트 유형").selectOption("COMPANY"); - await page.getByLabel("슬러그 (Slug)").fill("test-tenant"); - await page.getByLabel("설명").fill("This is an E2E test tenant"); - await page - .getByLabel("허용된 도메인 (콤마로 구분)") - .fill("test.com, example.com"); - - await page.getByRole("button", { name: "생성" }).click(); - await expect(page).toHaveURL(/\/tenants$/); - - // Verify created - const createdRow = page.locator("tbody tr").filter({ hasText: uniqueName }); - await expect(createdRow).toBeVisible(); - - // Delete - page.once("dialog", (dialog) => dialog.accept()); - await createdRow.getByRole("button", { name: "삭제" }).click(); - - await expect( - page.locator("tbody tr").filter({ hasText: uniqueName }), - ).toHaveCount(0); -}); - -test("tenant creation form validation", async ({ page }) => { - await page.goto("/tenants/new"); - - // Try to submit empty form - await page.getByRole("button", { name: "생성" }).click(); - - // Since 'name' is required, we check if button is still disabled or form doesn't navigate - await expect(page).toHaveURL(/\/tenants\/new$/); -}); diff --git a/adminfront/tests/user-management.spec.ts b/adminfront/tests/user-management.spec.ts deleted file mode 100644 index f4bf221b..00000000 --- a/adminfront/tests/user-management.spec.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { expect, test } from "@playwright/test"; - -type UserSummary = { - id: string; - email: string; - name: string; - phone?: string; - role: string; - status: string; - companyCode?: string; - department?: string; - createdAt: string; - updatedAt: string; -}; - -type UserCreatePayload = { - email: string; - password?: string; - name: string; - phone?: string; - role?: string; - companyCode?: string; - department?: string; -}; - -test("user create and delete flow", async ({ page }) => { - const nowInSeconds = Math.floor(Date.now() / 1000); - - await page.addInitScript((issuedAt) => { - const mockOidcUser = { - id_token: "playwright-id-token", - session_state: "playwright-session", - access_token: "playwright-access-token", - refresh_token: "playwright-refresh-token", - token_type: "Bearer", - scope: "openid profile email", - profile: { - sub: "playwright-admin", - email: "admin@example.com", - name: "Playwright Admin", - }, - expires_at: issuedAt + 3600, - }; - - window.localStorage.setItem("admin_session", mockOidcUser.access_token); - window.localStorage.setItem( - "oidc.user:http://localhost:5000/oidc:adminfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( - "oidc.user:http://localhost:5000/oidc/:adminfront", - JSON.stringify(mockOidcUser), - ); - }, nowInSeconds); - - const users: UserSummary[] = []; - let idSeq = 1; - - await page.route("**/api/v1/admin/tenants**", async (route) => { - const request = route.request(); - if (request.method() !== "GET") { - await route.fulfill({ - status: 404, - contentType: "application/json", - body: JSON.stringify({ error: "Not found" }), - }); - return; - } - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - items: [ - { - id: "tenant-e2e", - name: "E2E Tenant", - slug: "e2e", - description: "Playwright tenant", - status: "active", - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }, - ], - limit: 100, - offset: 0, - total: 1, - }), - }); - }); - - await page.route("**/api/v1/admin/tenants/*", async (route) => { - const request = route.request(); - if (request.method() !== "GET") { - await route.fulfill({ - status: 404, - contentType: "application/json", - body: JSON.stringify({ error: "Not found" }), - }); - return; - } - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - id: "tenant-e2e", - name: "E2E Tenant", - slug: "e2e", - description: "Playwright tenant", - status: "active", - config: { userSchema: [] }, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }), - }); - }); - - await page.route("**/api/v1/admin/users**", async (route) => { - const request = route.request(); - const url = new URL(request.url()); - const path = url.pathname; - const isCollection = path.endsWith("/api/v1/admin/users"); - const isItem = path.includes("/api/v1/admin/users/"); - - if (request.method() === "GET" && isCollection) { - const search = url.searchParams.get("search")?.toLowerCase() ?? ""; - const limit = Number(url.searchParams.get("limit") ?? "50"); - const offset = Number(url.searchParams.get("offset") ?? "0"); - const filtered = search - ? users.filter( - (user) => - user.name.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search), - ) - : users; - const items = filtered.slice(offset, offset + limit); - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - items, - limit, - offset, - total: filtered.length, - }), - }); - return; - } - - if (request.method() === "POST" && isCollection) { - const payload = request.postDataJSON() as UserCreatePayload; - const now = new Date().toISOString(); - const user: UserSummary = { - id: `user-${idSeq++}`, - email: payload.email, - name: payload.name, - phone: payload.phone, - role: payload.role ?? "user", - status: "active", - companyCode: payload.companyCode, - department: payload.department, - createdAt: now, - updatedAt: now, - }; - users.unshift(user); - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify(user), - }); - return; - } - - if (request.method() === "DELETE" && isItem) { - const userId = path.split("/").pop(); - const index = users.findIndex((user) => user.id === userId); - if (index === -1) { - await route.fulfill({ - status: 404, - contentType: "application/json", - body: JSON.stringify({ error: "User not found" }), - }); - return; - } - users.splice(index, 1); - await route.fulfill({ status: 204, body: "" }); - return; - } - - await route.fulfill({ - status: 404, - contentType: "application/json", - body: JSON.stringify({ error: "Not found" }), - }); - }); - - await page.goto("/users"); - await expect(page).toHaveURL(/\/users$/); - await expect( - page.getByRole("heading", { name: "사용자 관리" }), - ).toBeVisible(); - - const addUserLink = page.getByRole("link", { name: "사용자 추가" }); - await expect(addUserLink).toBeVisible(); - await page.goto("/users/new"); - await expect(page).toHaveURL(/\/users\/new$/); - - const uniqueEmail = `playwright-${Date.now()}@example.com`; - - await page.getByRole("checkbox", { name: "자동 생성" }).setChecked(false); - await page.getByLabel("이메일").fill(uniqueEmail); - await page.getByLabel("비밀번호").fill("Test1234!"); - await page.getByLabel("이름").fill("Playwright User"); - await page.getByLabel("전화번호").fill("010-0000-0000"); - await page.getByLabel("부서").fill("QA"); - await page.getByLabel("역할 (Role)").selectOption("admin"); - - await page.getByRole("button", { name: "사용자 생성" }).click(); - await expect(page).toHaveURL(/\/users$/); - - const createdRow = page.locator("tbody tr").filter({ hasText: uniqueEmail }); - await expect(createdRow).toBeVisible(); - - page.once("dialog", (dialog) => dialog.accept()); - await createdRow.getByRole("button", { name: /사용자 삭제/ }).click(); - - await expect( - page.locator("tbody tr").filter({ hasText: uniqueEmail }), - ).toHaveCount(0); -});