1
0
forked from baron/baron-sso

chore: consolidate local integration changes

This commit is contained in:
2026-06-09 21:03:05 +09:00
parent aa2848c3b6
commit 1341f07ef9
158 changed files with 10995 additions and 1490 deletions

View File

@@ -121,6 +121,105 @@ test.describe("Tenants Management", () => {
expect(headerWhiteSpace.every((value) => value === "nowrap")).toBe(true);
});
test("should export currently selected organization users by tenant slug", async ({
page,
}) => {
let exportUrl = "";
await page.route("**/api/v1/admin/tenants**", async (route) => {
if (route.request().method() !== "GET") {
return route.continue();
}
const url = new URL(route.request().url());
if (url.pathname.endsWith("/admin/tenants/tenant-company")) {
return route.fulfill({
json: {
id: "tenant-company",
name: "GPDTDC",
slug: "gpdtdc",
type: "COMPANY",
status: "active",
},
headers: { "Access-Control-Allow-Origin": "*" },
});
}
return route.fulfill({
json: {
items: [
{
id: "tenant-company",
name: "GPDTDC",
slug: "gpdtdc",
type: "COMPANY",
status: "active",
memberCount: 1,
recursiveMemberCount: 1,
},
{
id: "tenant-team",
parentId: "tenant-company",
name: "기술연구팀",
slug: "gpdtdc-rnd",
type: "ORGANIZATION",
status: "active",
memberCount: 1,
recursiveMemberCount: 1,
},
],
total: 2,
limit: 1000,
offset: 0,
},
headers: { "Access-Control-Allow-Origin": "*" },
});
});
await page.route(/\/admin\/users(\?.*)?$/, async (route) => {
const url = new URL(route.request().url());
expect(url.searchParams.get("tenantSlug")).toBe("gpdtdc");
return route.fulfill({
json: {
items: [
{
id: "user-1",
name: "Member User",
email: "member@example.com",
role: "user",
status: "active",
tenantSlug: "gpdtdc",
},
],
total: 1,
},
headers: { "Access-Control-Allow-Origin": "*" },
});
});
await page.route(/\/admin\/users\/export(\?.*)?$/, async (route) => {
exportUrl = route.request().url();
return route.fulfill({
status: 200,
headers: {
"content-type": "text/csv; charset=utf-8",
"content-disposition": 'attachment; filename="tenant-users.csv"',
},
body: "email,name\nmember@example.com,Member User\n",
});
});
await page.goto("/tenants/tenant-company/organization");
await expect(page.getByText("Member User")).toBeVisible();
const [download] = await Promise.all([
page.waitForEvent("download"),
page.getByTestId("tenant-current-users-export-btn").click(),
]);
expect(download.suggestedFilename()).toBe("tenant-users.csv");
expect(exportUrl).toContain("tenantSlug=gpdtdc");
expect(exportUrl).toContain("includeIds=false");
});
test("searches tenant ids in the tree view and selects descendants", async ({
page,
}) => {
@@ -141,7 +240,8 @@ test.describe("Tenants Management", () => {
slug: "acme",
status: "active",
type: "COMPANY",
memberCount: 0,
memberCount: 3,
totalMemberCount: 9,
updatedAt: new Date().toISOString(),
},
{
@@ -151,7 +251,8 @@ test.describe("Tenants Management", () => {
status: "active",
type: "ORGANIZATION",
parentId: "company-1",
memberCount: 0,
memberCount: 4,
totalMemberCount: 6,
updatedAt: new Date().toISOString(),
},
{
@@ -161,19 +262,31 @@ test.describe("Tenants Management", () => {
status: "active",
type: "USER_GROUP",
parentId: "dept-1",
memberCount: 0,
memberCount: 2,
totalMemberCount: 2,
updatedAt: new Date().toISOString(),
},
];
let filtered = items;
if (search) {
filtered = items.filter(
const directMatches = items.filter(
(i) =>
i.name.toLowerCase().includes(search) ||
i.slug.toLowerCase().includes(search) ||
i.id.toLowerCase().includes(search),
);
const ids = new Set(directMatches.map((item) => item.id));
for (const match of directMatches) {
let parentId = match.parentId;
while (parentId) {
const parent = items.find((item) => item.id === parentId);
if (!parent) break;
ids.add(parent.id);
parentId = parent.parentId;
}
}
filtered = items.filter((item) => ids.has(item.id));
}
await route.fulfill({
@@ -192,7 +305,14 @@ test.describe("Tenants Management", () => {
await page
.getByPlaceholder(/이름 또는 슬러그, ID 검색|search/i)
.fill("team-1");
await expect(page.locator("table")).toContainText("Acme");
await expect(page.locator("table")).toContainText("Planning");
await expect(page.locator("table")).toContainText("Platform");
await expect(page.getByTestId("tenant-search-match-team-1")).toBeVisible();
await expect(page.getByTestId("tenant-search-match-company-1")).toHaveCount(
0,
);
await expect(page.getByTestId("tenant-search-match-dept-1")).toHaveCount(0);
await page.getByPlaceholder(/이름 또는 슬러그, ID 검색|search/i).fill("");
await page
@@ -226,7 +346,8 @@ test.describe("Tenants Management", () => {
slug: "acme",
status: "active",
type: "COMPANY",
memberCount: 0,
memberCount: 3,
totalMemberCount: 9,
updatedAt: new Date().toISOString(),
},
{
@@ -236,7 +357,8 @@ test.describe("Tenants Management", () => {
status: "active",
type: "ORGANIZATION",
parentId: "company-1",
memberCount: 0,
memberCount: 4,
totalMemberCount: 6,
updatedAt: new Date().toISOString(),
},
{
@@ -246,7 +368,8 @@ test.describe("Tenants Management", () => {
status: "active",
type: "USER_GROUP",
parentId: "dept-1",
memberCount: 0,
memberCount: 2,
totalMemberCount: 2,
updatedAt: new Date().toISOString(),
},
];
@@ -280,6 +403,11 @@ test.describe("Tenants Management", () => {
"aria-pressed",
"true",
);
await expect(
page
.getByTestId("tenant-internal-id-company-1")
.locator("xpath=ancestor::tr"),
).toContainText("9명");
await page.getByPlaceholder(/UUID|슬러그|slug/i).fill("team-1");
await page.keyboard.press("Enter");
@@ -743,16 +871,18 @@ test.describe("Tenants Management", () => {
let exportUrl = "";
let importRequested = false;
let importBody = "";
const openDataManagementMenu = async () => {
const openDataManagementMenu = async (
expectedTestId = "tenant-export-menu-item",
) => {
const btn = page.getByTestId("tenant-data-mgmt-btn");
const exportMenuItem = page.getByTestId("tenant-export-menu-item");
const expectedMenuItem = page.getByTestId(expectedTestId);
// Attempt to open the menu with a retry loop using toPass
await expect(async () => {
if (!(await exportMenuItem.isVisible())) {
if (!(await expectedMenuItem.isVisible())) {
await btn.click({ force: true });
}
await expect(exportMenuItem).toBeVisible({ timeout: 2000 });
await expect(expectedMenuItem).toBeVisible({ timeout: 2000 });
}).toPass({
intervals: [1000, 2000],
timeout: 10000,
@@ -847,7 +977,7 @@ test.describe("Tenants Management", () => {
await expect(page.getByText(/조직\/사용자 통합/)).toHaveCount(0);
await openDataManagementMenu();
await openDataManagementMenu("tenant-export-menu-item");
await expect(page.getByTestId("tenant-template-menu-item")).toBeVisible();
await expect(page.getByTestId("tenant-import-menu-item")).toBeVisible();
@@ -872,14 +1002,14 @@ test.describe("Tenants Management", () => {
expect(exportDownload.suggestedFilename()).toBe("tenants.csv");
expect(exportUrl).toContain("includeIds=false");
await openDataManagementMenu();
await openDataManagementMenu("tenant-export-with-ids-menu-item");
await expect(
page.getByTestId("tenant-export-with-ids-menu-item"),
).toBeVisible();
await safeDownload("tenant-export-with-ids-menu-item");
expect(exportUrl).toContain("includeIds=true");
await openDataManagementMenu();
await openDataManagementMenu("tenant-template-menu-item");
const template = await safeDownload("tenant-template-menu-item");
expect(template.suggestedFilename()).toBe("tenant-import-template.csv");