forked from baron/baron-sso
af 테스트 삭제
This commit is contained in:
@@ -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$/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -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$/);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user