1
0
forked from baron/baron-sso

네이버 계정 정합성 맞춤

This commit is contained in:
2026-06-15 19:54:09 +09:00
parent 8e9d015443
commit 4d468cd39f
97 changed files with 5837 additions and 2031 deletions

View File

@@ -1,7 +1,10 @@
import { expect, test } from "@playwright/test";
import { installAdminFrontStaticRoutes } from "./helpers/static-adminfront";
test.describe("Bulk Actions and Tree Search", () => {
test.beforeEach(async ({ page }) => {
await installAdminFrontStaticRoutes(page);
await page.addInitScript(() => {
window.localStorage.setItem("locale", "ko");
window.localStorage.setItem("admin_session", "fake-token");
@@ -196,6 +199,55 @@ test.describe("Bulk Actions and Tree Search", () => {
await expect(selectionBar).not.toBeVisible({ timeout: 10000 });
});
test("should show a failure toast when bulk update returns blocked rows", async ({
page,
}) => {
await page.route("**/api/v1/admin/users/bulk", async (route) => {
if (route.request().method() === "PUT") {
return route.fulfill({
json: {
results: [
{
id: "u-1",
success: false,
message:
"internal email domain cannot be assigned to personal tenant: u1@brsw.kr",
},
],
},
headers: { "Access-Control-Allow-Origin": "*" },
});
}
return route.fallback();
});
await page.goto("/users");
await expect(page.locator("table")).toContainText("User One", {
timeout: 20000,
});
await page.locator('table input[type="checkbox"]').nth(1).click();
const selectionBar = page.getByTestId("bulk-action-bar");
await expect(selectionBar).toBeVisible({ timeout: 15000 });
await page.getByTestId("bulk-status-select").click();
await page.getByRole("option", { name: /입사대기|Preboarding/i }).click();
await page.getByTestId("bulk-apply-btn").click();
await expect(
page.getByText(/1명의 사용자 정보 수정에 실패했습니다/),
).toBeVisible();
await expect(
page.getByText(
/내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다/,
),
).toBeVisible();
await expect(
page.getByText(/선택한 사용자들의 정보가 수정되었습니다/),
).not.toBeVisible();
await expect(selectionBar).toBeVisible();
});
test("should let super admins apply selected admin permission to selected users", async ({
page,
}) => {

View File

@@ -925,6 +925,17 @@ test.describe("Tenants Management", () => {
await expect(
page.getByRole("button", { name: "다른 테넌트 선택" }),
).toBeVisible();
await page.getByRole("button", { name: "한맥가족에서 선택" }).click();
await expect(page.getByRole("dialog")).toBeVisible();
const hanmacPickerSrc = await page
.getByTestId("parent-tenant-picker-frame")
.getAttribute("src");
expect(hanmacPickerSrc).toContain("http://localhost:5175/login");
expect(decodeURIComponent(hanmacPickerSrc ?? "")).toContain(
"tenantId=family-1",
);
await page.keyboard.press("Escape");
await expect(page.getByRole("dialog")).toHaveCount(0);
const parentLabelTop = await page
.getByText(/상위 테넌트/)
.first()
@@ -1945,6 +1956,22 @@ test.describe("Tenants Management", () => {
expect(topColumns.split(" ").length).toBe(3);
expect(configColumns.split(" ").length).toBe(4);
await page
.getByTestId("tenant-parent-picker-slot")
.getByRole("button")
.first()
.click();
await expect(page.getByRole("dialog")).toBeVisible();
const detailPickerSrc = await page
.getByTestId("parent-tenant-picker-frame")
.getAttribute("src");
expect(detailPickerSrc).toContain("http://localhost:5175/login");
expect(decodeURIComponent(detailPickerSrc ?? "")).toContain(
"/embed/picker",
);
await page.keyboard.press("Escape");
await expect(page.getByRole("dialog")).toHaveCount(0);
const nameTop = await page
.getByTestId("tenant-name-slot")
.evaluate((element) => element.getBoundingClientRect().top);

View File

@@ -689,6 +689,37 @@ test.describe("User Management", () => {
await expect(page).toHaveURL(/.*\/users$/, { timeout: 10000 });
});
test("should show a Korean policy message when an internal domain user is created as personal", async ({
page,
}) => {
await page.route(/\/admin\/users$/, async (route) => {
if (route.request().method() !== "POST") {
return route.fallback();
}
return route.fulfill({
status: 400,
json: {
error:
"internal email domain cannot be assigned to personal tenant: user@hanmaceng.co.kr",
},
});
});
await page.goto("/users/new");
await expect(page.getByText(/사용자 추가/i).first()).toBeVisible();
await page.getByRole("tab", { name: /개인 회원/i }).click();
await page.locator('input[name="name"]').fill("Internal User");
await page.locator('input[name="email"]').fill("user@hanmaceng.co.kr");
await page.getByRole("button", { name: /생성/i }).click();
await expect(
page.getByText(
/내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다/,
),
).toBeVisible();
});
test("should export users through the authenticated API client", async ({
page,
}) => {
@@ -1032,6 +1063,43 @@ test.describe("User Management", () => {
expect(createPayload).toBeUndefined();
});
test("should open Hanmac family tenant picker without submitting the user create form", async ({
page,
}) => {
let createRequests = 0;
await page.route(/\/admin\/users(\?.*)?$/, async (route) => {
if (route.request().method() === "POST") {
createRequests += 1;
return route.fulfill({
status: 201,
json: {
id: "new-user-id",
name: "Family User",
email: "family@test.com",
},
});
}
return route.fallback();
});
await page.goto("/users/new");
await page.getByTestId("add-appointment-btn").click();
await expect(page.getByTestId("appointment-row-0")).toBeVisible();
await page.getByRole("button", { name: "한맥가족에서 선택" }).click();
await expect(page).toHaveURL(/\/users\/new$/);
await expect(page.getByRole("dialog")).toBeVisible();
const pickerSrc = await page
.getByTestId("appointment-tenant-picker-frame")
.getAttribute("src");
expect(decodeURIComponent(pickerSrc ?? "")).toContain(
"tenantId=hanmac-family-id",
);
expect(createRequests).toBe(0);
});
test("should hide Hanmac family subtree and system tenants when creating a non-family user", async ({
page,
}) => {

View File

@@ -1,7 +1,10 @@
import { expect, test } from "@playwright/test";
import { installAdminFrontStaticRoutes } from "./helpers/static-adminfront";
test.describe("Users Bulk Upload", () => {
test.beforeEach(async ({ page }) => {
await installAdminFrontStaticRoutes(page);
await page.addInitScript(() => {
window.localStorage.setItem("locale", "ko");
window.localStorage.setItem("admin_session", "fake-token");
@@ -117,6 +120,56 @@ test.describe("Users Bulk Upload", () => {
await expect(uploadBtn).toBeDisabled();
});
test("should show Korean policy message for internal domain personal failures", async ({
page,
}) => {
await page.route("**/api/v1/admin/users/bulk", async (route) => {
if (route.request().method() === "POST") {
await route.fulfill({
json: {
results: [
{
email: "user@pre-cast.co.kr",
success: false,
message:
"internal email domain cannot be assigned to personal tenant: user@pre-cast.co.kr",
},
],
},
headers: { "Access-Control-Allow-Origin": "*" },
});
return;
}
await route.continue();
});
await page.goto("/users");
await expect(page.getByTestId("page-title")).toContainText(
/사용자|Users/i,
{ timeout: 20000 },
);
await page.getByTestId("user-data-mgmt-btn").click();
await page
.getByRole("menuitem", { name: /일괄 임포트|일괄 등록|Bulk Import/i })
.click();
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles({
name: "users.csv",
mimeType: "text/csv",
buffer: Buffer.from("email,name\nuser@pre-cast.co.kr,Internal User\n"),
});
await page.getByTestId("bulk-start-btn").click();
await expect(
page.getByText(
/내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다/,
),
).toBeVisible();
});
test("should create missing tenant before user bulk import", async ({
page,
}) => {