forked from baron/baron-sso
chore: consolidate local integration changes
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test.describe("Worksmobile tenant management", () => {
|
||||
@@ -32,7 +31,10 @@ test.describe("Worksmobile tenant management", () => {
|
||||
page,
|
||||
}) => {
|
||||
const comparisonRequests: boolean[] = [];
|
||||
const syncRequests: string[] = [];
|
||||
const syncRequests: Array<{
|
||||
userId: string;
|
||||
body: Record<string, unknown>;
|
||||
}> = [];
|
||||
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const url = new URL(route.request().url());
|
||||
@@ -218,7 +220,13 @@ test.describe("Worksmobile tenant management", () => {
|
||||
isWorksmobileTenantPath("/worksmobile/users/user-missing/sync") &&
|
||||
method === "POST"
|
||||
) {
|
||||
syncRequests.push("user-missing");
|
||||
syncRequests.push({
|
||||
userId: "user-missing",
|
||||
body: JSON.parse(route.request().postData() ?? "{}") as Record<
|
||||
string,
|
||||
unknown
|
||||
>,
|
||||
});
|
||||
return route.fulfill({
|
||||
json: { id: "job-user-missing", resourceId: "user-missing" },
|
||||
headers,
|
||||
@@ -235,7 +243,8 @@ test.describe("Worksmobile tenant management", () => {
|
||||
await expect(page.getByRole("tab", { name: "조직" })).toBeVisible();
|
||||
|
||||
await page.getByRole("tab", { name: "이력" }).click();
|
||||
await expect(page.getByText("비밀번호 파일 히스토리")).toBeVisible();
|
||||
await expect(page.getByText("비밀번호 파일 히스토리")).not.toBeVisible();
|
||||
await expect(page.getByText("최근 작업")).toBeVisible();
|
||||
await expect(page.getByText("domainMappings")).not.toBeVisible();
|
||||
await expect(page.getByText("SCIM token")).not.toBeVisible();
|
||||
await page.getByRole("tab", { name: "사용자" }).click();
|
||||
@@ -246,6 +255,9 @@ test.describe("Worksmobile tenant management", () => {
|
||||
"worksmobile-구성원-virtual-body",
|
||||
);
|
||||
await expect(userComparisonTable).toBeVisible();
|
||||
await expect(page.getByTestId("worksmobile-구성원-row-count")).toHaveText(
|
||||
"표시 2 / 전체 5",
|
||||
);
|
||||
await expect(userSyncCard).toBeVisible();
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
@@ -347,7 +359,17 @@ test.describe("Worksmobile tenant management", () => {
|
||||
await page
|
||||
.getByRole("button", { name: "선택 구성원 WORKS에 생성" })
|
||||
.click();
|
||||
await expect.poll(() => syncRequests).toEqual(["user-missing"]);
|
||||
await expect(page.getByText("WORKS 초기 비밀번호")).toBeVisible();
|
||||
await page.getByLabel("초기 비밀번호").fill("InitPass123!");
|
||||
await page.getByRole("button", { name: "생성 작업 등록" }).click();
|
||||
await expect
|
||||
.poll(() => syncRequests)
|
||||
.toEqual([
|
||||
{
|
||||
userId: "user-missing",
|
||||
body: expect.objectContaining({ initialPassword: "InitPass123!" }),
|
||||
},
|
||||
]);
|
||||
|
||||
await page.getByRole("tab", { name: "조직" }).click();
|
||||
await expect(page.getByText("조직 단건 동기화")).toBeVisible();
|
||||
@@ -357,6 +379,9 @@ test.describe("Worksmobile tenant management", () => {
|
||||
"worksmobile-조직/그룹-virtual-body",
|
||||
);
|
||||
await expect(groupComparisonTable).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId("worksmobile-조직/그룹-row-count"),
|
||||
).toHaveText("표시 2 / 전체 2");
|
||||
await expect(groupSyncCard).toBeVisible();
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
@@ -381,6 +406,228 @@ test.describe("Worksmobile tenant management", () => {
|
||||
await expect(page.getByText("works-parent-tech")).toBeVisible();
|
||||
});
|
||||
|
||||
test("separates selected user create and update actions", async ({
|
||||
page,
|
||||
}) => {
|
||||
const syncRequests: Array<{
|
||||
userId: string;
|
||||
body: Record<string, unknown>;
|
||||
}> = [];
|
||||
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const url = new URL(route.request().url());
|
||||
const method = route.request().method();
|
||||
const headers = { "Access-Control-Allow-Origin": "*" };
|
||||
const isWorksmobileTenantPath = (suffix: string) =>
|
||||
url.pathname.endsWith(`/admin/tenants/hanmac-family-id${suffix}`) ||
|
||||
url.pathname.endsWith(
|
||||
`/admin/tenants/038326b6-954a-48a7-a85f-efd83f62b82a${suffix}`,
|
||||
);
|
||||
|
||||
if (url.pathname.endsWith("/user/me")) {
|
||||
return route.fulfill({
|
||||
json: {
|
||||
id: "admin-user",
|
||||
name: "Admin",
|
||||
role: "super_admin",
|
||||
manageableTenants: [
|
||||
{
|
||||
id: "038326b6-954a-48a7-a85f-efd83f62b82a",
|
||||
name: "한맥 가족",
|
||||
slug: "hanmac-family",
|
||||
type: "COMPANY_GROUP",
|
||||
},
|
||||
],
|
||||
},
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
url.pathname.endsWith("/admin/tenants/hanmac-family-id") &&
|
||||
method === "GET"
|
||||
) {
|
||||
return route.fulfill({
|
||||
json: {
|
||||
id: "hanmac-family-id",
|
||||
name: "한맥 가족",
|
||||
slug: "hanmac-family",
|
||||
type: "COMPANY_GROUP",
|
||||
status: "active",
|
||||
parentId: null,
|
||||
},
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
if (isWorksmobileTenantPath("/worksmobile") && method === "GET") {
|
||||
return route.fulfill({
|
||||
json: {
|
||||
tenant: {
|
||||
id: "hanmac-family-id",
|
||||
name: "한맥 가족",
|
||||
slug: "hanmac-family",
|
||||
type: "COMPANY_GROUP",
|
||||
status: "active",
|
||||
memberCount: 0,
|
||||
createdAt: "2026-05-04T00:00:00Z",
|
||||
updatedAt: "2026-05-04T00:00:00Z",
|
||||
},
|
||||
config: {
|
||||
enabled: true,
|
||||
tokenConfigured: true,
|
||||
},
|
||||
recentJobs: [],
|
||||
},
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
isWorksmobileTenantPath("/worksmobile/credential-batches") &&
|
||||
method === "GET"
|
||||
) {
|
||||
return route.fulfill({ json: [], headers });
|
||||
}
|
||||
|
||||
if (
|
||||
isWorksmobileTenantPath("/worksmobile/comparison") &&
|
||||
method === "GET"
|
||||
) {
|
||||
return route.fulfill({
|
||||
json: {
|
||||
users: [
|
||||
{
|
||||
resourceType: "USER",
|
||||
baronId: "user-missing",
|
||||
baronName: "김생성",
|
||||
status: "missing_in_worksmobile",
|
||||
},
|
||||
{
|
||||
resourceType: "USER",
|
||||
baronId: "user-update",
|
||||
baronName: "이업데이트",
|
||||
baronEmail: "domain@typo.example.com",
|
||||
worksmobileId: "works-user-update",
|
||||
externalKey: "user-update",
|
||||
worksmobileName: "이업데이트",
|
||||
worksmobileEmail: "domain@example.com",
|
||||
status: "needs_update",
|
||||
},
|
||||
],
|
||||
groups: [],
|
||||
},
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
isWorksmobileTenantPath("/worksmobile/users/user-missing/sync") &&
|
||||
method === "POST"
|
||||
) {
|
||||
syncRequests.push({
|
||||
userId: "user-missing",
|
||||
body: JSON.parse(route.request().postData() ?? "{}") as Record<
|
||||
string,
|
||||
unknown
|
||||
>,
|
||||
});
|
||||
return route.fulfill({
|
||||
json: { id: "job-user-missing", resourceId: "user-missing" },
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
isWorksmobileTenantPath("/worksmobile/users/user-update/sync") &&
|
||||
method === "POST"
|
||||
) {
|
||||
syncRequests.push({
|
||||
userId: "user-update",
|
||||
body: JSON.parse(route.request().postData() ?? "{}") as Record<
|
||||
string,
|
||||
unknown
|
||||
>,
|
||||
});
|
||||
return route.fulfill({
|
||||
json: { id: "job-user-update", resourceId: "user-update" },
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
return route.fulfill({ json: { items: [], total: 0 }, headers });
|
||||
});
|
||||
|
||||
await page.goto("/worksmobile");
|
||||
await page.getByRole("tab", { name: "사용자" }).click();
|
||||
|
||||
const userComparisonSection = page
|
||||
.getByRole("heading", { name: "구성원" })
|
||||
.locator("xpath=ancestor::div[contains(@class, 'space-y-2')][1]");
|
||||
await expect(userComparisonSection.getByText("김생성")).toBeVisible();
|
||||
await expect(userComparisonSection.getByText("이업데이트")).toHaveCount(2);
|
||||
|
||||
const statusHeader = userComparisonSection
|
||||
.locator("thead th")
|
||||
.filter({ hasText: "상태" })
|
||||
.locator("div")
|
||||
.first();
|
||||
await expect
|
||||
.poll(() =>
|
||||
statusHeader.evaluate((element) => {
|
||||
const style = window.getComputedStyle(element);
|
||||
return { alignItems: style.alignItems, display: style.display };
|
||||
}),
|
||||
)
|
||||
.toEqual({ alignItems: "center", display: "flex" });
|
||||
|
||||
await page
|
||||
.getByRole("row", { name: /김생성/ })
|
||||
.getByRole("checkbox")
|
||||
.check();
|
||||
await page
|
||||
.getByRole("row", { name: /이업데이트/ })
|
||||
.getByRole("checkbox")
|
||||
.check();
|
||||
|
||||
await userComparisonSection
|
||||
.getByRole("button", { name: "선택 구성원 WORKS에 생성" })
|
||||
.click();
|
||||
await expect(page.getByText("WORKS 초기 비밀번호")).toBeVisible();
|
||||
await page.getByLabel("초기 비밀번호").fill("InitPass123!");
|
||||
await page.getByRole("button", { name: "생성 작업 등록" }).click();
|
||||
await expect
|
||||
.poll(() => syncRequests)
|
||||
.toEqual([
|
||||
{
|
||||
userId: "user-missing",
|
||||
body: expect.objectContaining({ initialPassword: "InitPass123!" }),
|
||||
},
|
||||
]);
|
||||
|
||||
await page
|
||||
.getByRole("row", { name: /이업데이트/ })
|
||||
.getByRole("checkbox")
|
||||
.check();
|
||||
await userComparisonSection
|
||||
.getByRole("button", { name: "선택 구성원 업데이트 적용" })
|
||||
.click();
|
||||
await expect
|
||||
.poll(() => syncRequests)
|
||||
.toEqual([
|
||||
{
|
||||
userId: "user-missing",
|
||||
body: expect.objectContaining({ initialPassword: "InitPass123!" }),
|
||||
},
|
||||
{
|
||||
userId: "user-update",
|
||||
body: expect.not.objectContaining({
|
||||
initialPassword: expect.anything(),
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("shows a toast when selected WORKS creation fails", async ({ page }) => {
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const url = new URL(route.request().url());
|
||||
@@ -651,9 +898,7 @@ test.describe("Worksmobile tenant management", () => {
|
||||
).toBeDisabled();
|
||||
});
|
||||
|
||||
test("downloads initial password CSV and enqueues WORKS admin jobs", async ({
|
||||
page,
|
||||
}) => {
|
||||
test("shows WORKS job history and enqueues admin jobs", async ({ page }) => {
|
||||
const requests: string[] = [];
|
||||
const headers = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
@@ -790,24 +1035,6 @@ test.describe("Worksmobile tenant management", () => {
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
url.pathname.endsWith(
|
||||
"/admin/tenants/038326b6-954a-48a7-a85f-efd83f62b82a/worksmobile/initial-passwords.csv",
|
||||
) &&
|
||||
method === "GET"
|
||||
) {
|
||||
requests.push("download-passwords");
|
||||
return route.fulfill({
|
||||
body: "email,password\nuser@example.com,Secret123!\n",
|
||||
contentType: "text/csv",
|
||||
headers: {
|
||||
...headers,
|
||||
"Content-Disposition":
|
||||
'attachment; filename="worksmobile-passwords.csv"',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
url.pathname.endsWith(
|
||||
"/admin/tenants/038326b6-954a-48a7-a85f-efd83f62b82a/worksmobile/backfill/dry-run",
|
||||
@@ -864,18 +1091,10 @@ test.describe("Worksmobile tenant management", () => {
|
||||
await page.goto("/worksmobile");
|
||||
await expect(page.getByText("Worksmobile 연동")).toBeVisible();
|
||||
await page.getByRole("tab", { name: "이력" }).click();
|
||||
|
||||
const download = page.waitForEvent("download");
|
||||
await page
|
||||
.getByRole("button", { name: "batch-1 비밀번호 CSV 다운로드" })
|
||||
.click();
|
||||
const passwordCsv = await download;
|
||||
expect(passwordCsv.suggestedFilename()).toBe("worksmobile-passwords.csv");
|
||||
const passwordCsvPath = await passwordCsv.path();
|
||||
expect(passwordCsvPath).toBeTruthy();
|
||||
expect(await readFile(passwordCsvPath ?? "", "utf8")).toContain(
|
||||
"user@example.com,Secret123!",
|
||||
);
|
||||
await expect(page.getByText("비밀번호 파일 히스토리")).not.toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: /비밀번호 CSV 다운로드/ }),
|
||||
).toHaveCount(0);
|
||||
|
||||
await page.getByRole("button", { name: "Backfill Dry-run" }).click();
|
||||
await expect.poll(() => requests).toContain("dry-run");
|
||||
@@ -915,6 +1134,5 @@ test.describe("Worksmobile tenant management", () => {
|
||||
page.once("dialog", (dialog) => dialog.accept());
|
||||
await page.getByRole("button", { name: /대기중 payload 삭제/ }).click();
|
||||
await expect.poll(() => requests).toContain("delete-pending");
|
||||
expect(requests).toContain("download-passwords");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user