1
0
forked from baron/baron-sso

orgfront 테스트/픽스처

This commit is contained in:
2026-05-07 10:57:11 +09:00
parent 49778af905
commit 5615e9a4fb
2 changed files with 106 additions and 60 deletions

View File

@@ -1,5 +1,13 @@
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
const shareToken = "playwright";
function withShareToken(path: string) {
return path.includes("?")
? `${path}&token=${shareToken}`
: `${path}?token=${shareToken}`;
}
type TenantFixture = { type TenantFixture = {
id: string; id: string;
type: string; type: string;
@@ -75,41 +83,58 @@ async function seedOrgfrontAuth(page: Parameters<typeof test>[0]["page"]) {
}, },
expires_at: issuedAt + 3600, expires_at: issuedAt + 3600,
}; };
const storageKeys = [
window.localStorage.setItem( "user:http://localhost:5000/oidc:orgfront",
"user:http://localhost:5000/oidc/:orgfront",
"user:http://localhost:5000/oidc:devfront",
"user:http://localhost:5000/oidc/:devfront",
"user:http://172.16.9.189:5000/oidc:orgfront",
"user:http://172.16.9.189:5000/oidc/:orgfront",
"oidc.user:http://localhost:5000/oidc:orgfront", "oidc.user:http://localhost:5000/oidc:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc/:orgfront", "oidc.user:http://localhost:5000/oidc/:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc:devfront", "oidc.user:http://localhost:5000/oidc:devfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc/:devfront", "oidc.user:http://localhost:5000/oidc/:devfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://172.16.9.189:5000/oidc:orgfront", "oidc.user:http://172.16.9.189:5000/oidc:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://172.16.9.189:5000/oidc/:orgfront", "oidc.user:http://172.16.9.189:5000/oidc/:orgfront",
JSON.stringify(mockOidcUser), ];
); for (const key of storageKeys) {
window.localStorage.setItem(key, JSON.stringify(mockOidcUser));
}
window.localStorage.setItem("playwright_auth_bypass", "1");
window.localStorage.setItem("dev_tenant_id", "group-hmac"); window.localStorage.setItem("dev_tenant_id", "group-hmac");
}, },
{ issuedAt: nowInSeconds }, { issuedAt: nowInSeconds },
); );
await page.route("**/oidc/**", async (route) => { await page.route("**/oidc/**", async (route) => {
const url = route.request().url();
if (url.includes(".well-known/openid-configuration")) {
await route.fulfill({
json: {
issuer: "http://localhost:5000/oidc",
authorization_endpoint: "http://localhost:5000/oidc/auth",
token_endpoint: "http://localhost:5000/oidc/token",
jwks_uri: "http://localhost:5000/oidc/jwks",
userinfo_endpoint: "http://localhost:5000/oidc/userinfo",
end_session_endpoint: "http://localhost:5000/oidc/session/end",
},
headers: { "Access-Control-Allow-Origin": "*" },
});
return;
}
if (url.includes("/jwks")) {
await route.fulfill({
json: { keys: [] },
headers: { "Access-Control-Allow-Origin": "*" },
});
return;
}
await route.fulfill({ await route.fulfill({
status: 200, status: 200,
contentType: "application/json", body: "ok",
body: JSON.stringify({ keys: [] }), headers: { "Access-Control-Allow-Origin": "*" },
}); });
}); });
} }
@@ -186,7 +211,7 @@ test.beforeEach(async ({ page }) => {
test("developer navigation exposes chart, picker, and embed preview", async ({ test("developer navigation exposes chart, picker, and embed preview", async ({
page, page,
}) => { }) => {
await page.goto("/"); await page.goto(withShareToken("/chart"));
await expect(page.getByRole("link", { name: "조직도" })).toBeVisible(); await expect(page.getByRole("link", { name: "조직도" })).toBeVisible();
await expect(page.getByRole("link", { name: "조직 선택기" })).toBeVisible(); await expect(page.getByRole("link", { name: "조직 선택기" })).toBeVisible();
@@ -207,7 +232,7 @@ test("developer navigation exposes chart, picker, and embed preview", async ({
test("picker menu lets developers switch selection mode and selectable type", async ({ test("picker menu lets developers switch selection mode and selectable type", async ({
page, page,
}) => { }) => {
await page.goto("/picker"); await page.goto(withShareToken("/picker"));
await expect(page.getByLabel("선택 모드")).toHaveValue("multiple"); await expect(page.getByLabel("선택 모드")).toHaveValue("multiple");
await expect(page.getByLabel("선택 대상")).toHaveValue("both"); await expect(page.getByLabel("선택 대상")).toHaveValue("both");
@@ -230,7 +255,7 @@ test("picker menu lets developers switch selection mode and selectable type", as
test("picker displays user names with job title and position", async ({ test("picker displays user names with job title and position", async ({
page, page,
}) => { }) => {
await page.goto("/embed/picker?mode=single&select=user"); await page.goto(withShareToken("/embed/picker?mode=single&select=user"));
await expect( await expect(
page.getByRole("button", { page.getByRole("button", {
@@ -242,7 +267,7 @@ test("picker displays user names with job title and position", async ({
test("embed preview menu updates the iframe picker source", async ({ test("embed preview menu updates the iframe picker source", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview"); await page.goto(withShareToken("/embed-preview"));
await expect(page.getByLabel("선택 모드")).toHaveValue("multiple"); await expect(page.getByLabel("선택 모드")).toHaveValue("multiple");
await expect(page.getByLabel("선택 대상")).toHaveValue("both"); await expect(page.getByLabel("선택 대상")).toHaveValue("both");
@@ -297,7 +322,7 @@ test("embed preview menu updates the iframe picker source", async ({
test("embed preview passes tenant id and custom dimensions through the picker url", async ({ test("embed preview passes tenant id and custom dimensions through the picker url", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview"); await page.goto(withShareToken("/embed-preview"));
await page.getByLabel("tenant ID").fill("company-baron"); await page.getByLabel("tenant ID").fill("company-baron");
await page.getByLabel("임베딩 너비").fill("520"); await page.getByLabel("임베딩 너비").fill("520");
@@ -325,7 +350,9 @@ test("embed preview passes tenant id and custom dimensions through the picker ur
test("embed picker scopes the tree by tenant id, hides users for tenant selection, and keeps direct members before child tenants", async ({ test("embed picker scopes the tree by tenant id, hides users for tenant selection, and keeps direct members before child tenants", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?tenantId=company-baron&select=tenant"); await page.goto(
withShareToken("/embed-preview?tenantId=company-baron&select=tenant"),
);
await expect(page.getByLabel("tenant ID")).toHaveValue("company-baron"); await expect(page.getByLabel("tenant ID")).toHaveValue("company-baron");
await expect(page.getByTestId("embed-preview-src")).toContainText( await expect(page.getByTestId("embed-preview-src")).toContainText(
@@ -352,7 +379,7 @@ test("embed picker scopes the tree by tenant id, hides users for tenant selectio
test("embed picker keeps the lightweight search controls inside the picker section at the default embed width", async ({ test("embed picker keeps the lightweight search controls inside the picker section at the default embed width", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview"); await page.goto(withShareToken("/embed-preview"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
const searchSection = picker.getByTestId("org-picker-search-section"); const searchSection = picker.getByTestId("org-picker-search-section");
@@ -379,7 +406,7 @@ test("embed picker keeps the lightweight search controls inside the picker secti
test("embed picker keeps only the lightweight picker surface scrollable", async ({ test("embed picker keeps only the lightweight picker surface scrollable", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview"); await page.goto(withShareToken("/embed-preview"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await expect( await expect(
@@ -415,7 +442,7 @@ test("embed picker keeps only the lightweight picker surface scrollable", async
test("embed preview can hide the descendant selection switch", async ({ test("embed preview can hide the descendant selection switch", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=multiple&select=both"); await page.goto(withShareToken("/embed-preview?mode=multiple&select=both"));
await expect(page.getByLabel("하위 선택 스위치 표시")).toBeChecked(); await expect(page.getByLabel("하위 선택 스위치 표시")).toBeChecked();
await page.getByLabel("하위 선택 스위치 표시").uncheck(); await page.getByLabel("하위 선택 스위치 표시").uncheck();
@@ -434,7 +461,7 @@ test("embed preview can hide the descendant selection switch", async ({
test("embed picker renders compact tree rows with member emails", async ({ test("embed picker renders compact tree rows with member emails", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=single&select=user"); await page.goto(withShareToken("/embed-preview?mode=single&select=user"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await expect(picker.getByText("user-eng@example.com")).toBeVisible(); await expect(picker.getByText("user-eng@example.com")).toBeVisible();
@@ -451,7 +478,7 @@ test("embed picker renders compact tree rows with member emails", async ({
test("embed picker filters organizations and users by id, name, and metadata", async ({ test("embed picker filters organizations and users by id, name, and metadata", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=multiple&select=both"); await page.goto(withShareToken("/embed-preview?mode=multiple&select=both"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
const search = picker.getByLabel("조직/구성원 검색"); const search = picker.getByLabel("조직/구성원 검색");
@@ -475,7 +502,7 @@ test("embed picker filters organizations and users by id, name, and metadata", a
test("embed picker search does not keep unmatched descendants under a matching organization", async ({ test("embed picker search does not keep unmatched descendants under a matching organization", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=multiple&select=both"); await page.goto(withShareToken("/embed-preview?mode=multiple&select=both"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await picker.getByLabel("조직/구성원 검색").fill("센"); await picker.getByLabel("조직/구성원 검색").fill("센");
@@ -489,7 +516,7 @@ test("embed picker search does not keep unmatched descendants under a matching o
test("embed picker posts a single user selection with type, id, and name", async ({ test("embed picker posts a single user selection with type, id, and name", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=single&select=user"); await page.goto(withShareToken("/embed-preview?mode=single&select=user"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await picker await picker
@@ -507,7 +534,7 @@ test("embed picker posts a single user selection with type, id, and name", async
test("embed picker single selection counts only the selected node without descendants", async ({ test("embed picker single selection counts only the selected node without descendants", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=single&select=both"); await page.goto(withShareToken("/embed-preview?mode=single&select=both"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await picker await picker
@@ -528,7 +555,7 @@ test("embed picker single selection counts only the selected node without descen
test("embed picker highlights a single selected item without tree connectors", async ({ test("embed picker highlights a single selected item without tree connectors", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=single&select=both"); await page.goto(withShareToken("/embed-preview?mode=single&select=both"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
await expect( await expect(
@@ -548,7 +575,7 @@ test("embed picker highlights a single selected item without tree connectors", a
test("embed picker renders tenant names with the dedicated tenant text color", async ({ test("embed picker renders tenant names with the dedicated tenant text color", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=single&select=both"); await page.goto(withShareToken("/embed-preview?mode=single&select=both"));
const picker = page.frameLocator("iframe"); const picker = page.frameLocator("iframe");
const tenantName = picker.getByTestId("org-picker-node-name-tenant").first(); const tenantName = picker.getByTestId("org-picker-node-name-tenant").first();
@@ -563,7 +590,7 @@ test("embed picker renders tenant names with the dedicated tenant text color", a
test("embed picker includes descendants by default and can disable descendant inclusion", async ({ test("embed picker includes descendants by default and can disable descendant inclusion", async ({
page, page,
}) => { }) => {
await page.goto("/embed-preview?mode=multiple&select=both"); await page.goto(withShareToken("/embed-preview?mode=multiple&select=both"));
let picker = page.frameLocator("iframe"); let picker = page.frameLocator("iframe");
await expect( await expect(
@@ -582,7 +609,9 @@ test("embed picker includes descendants by default and can disable descendant in
await expect(output).toContainText('"id": "user-platform"'); await expect(output).toContainText('"id": "user-platform"');
await page.goto( await page.goto(
"/embed-preview?mode=multiple&select=both&includeDescendants=false", withShareToken(
"/embed-preview?mode=multiple&select=both&includeDescendants=false",
),
); );
picker = page.frameLocator("iframe"); picker = page.frameLocator("iframe");
await picker.getByLabel("Engineering 선택").check(); await picker.getByLabel("Engineering 선택").check();

View File

@@ -214,41 +214,58 @@ test("org chart places multi-tenant users only on leaf memberships without dupli
}, },
expires_at: seededIssuedAt + 3600, expires_at: seededIssuedAt + 3600,
}; };
const storageKeys = [
window.localStorage.setItem( "user:http://localhost:5000/oidc:orgfront",
"user:http://localhost:5000/oidc/:orgfront",
"user:http://localhost:5000/oidc:devfront",
"user:http://localhost:5000/oidc/:devfront",
"user:http://172.16.9.189:5000/oidc:orgfront",
"user:http://172.16.9.189:5000/oidc/:orgfront",
"oidc.user:http://localhost:5000/oidc:orgfront", "oidc.user:http://localhost:5000/oidc:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc/:orgfront", "oidc.user:http://localhost:5000/oidc/:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc:devfront", "oidc.user:http://localhost:5000/oidc:devfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://localhost:5000/oidc/:devfront", "oidc.user:http://localhost:5000/oidc/:devfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://172.16.9.189:5000/oidc:orgfront", "oidc.user:http://172.16.9.189:5000/oidc:orgfront",
JSON.stringify(mockOidcUser),
);
window.localStorage.setItem(
"oidc.user:http://172.16.9.189:5000/oidc/:orgfront", "oidc.user:http://172.16.9.189:5000/oidc/:orgfront",
JSON.stringify(mockOidcUser), ];
); for (const key of storageKeys) {
window.localStorage.setItem(key, JSON.stringify(mockOidcUser));
}
window.localStorage.setItem("playwright_auth_bypass", "1");
window.localStorage.setItem("dev_tenant_id", "group"); window.localStorage.setItem("dev_tenant_id", "group");
}, },
{ issuedAt }, { issuedAt },
); );
await page.route("**/oidc/**", async (route) => { await page.route("**/oidc/**", async (route) => {
const url = route.request().url();
if (url.includes(".well-known/openid-configuration")) {
await route.fulfill({
json: {
issuer: "http://localhost:5000/oidc",
authorization_endpoint: "http://localhost:5000/oidc/auth",
token_endpoint: "http://localhost:5000/oidc/token",
jwks_uri: "http://localhost:5000/oidc/jwks",
userinfo_endpoint: "http://localhost:5000/oidc/userinfo",
end_session_endpoint: "http://localhost:5000/oidc/session/end",
},
headers: { "Access-Control-Allow-Origin": "*" },
});
return;
}
if (url.includes("/jwks")) {
await route.fulfill({
json: { keys: [] },
headers: { "Access-Control-Allow-Origin": "*" },
});
return;
}
await route.fulfill({ await route.fulfill({
status: 200, status: 200,
contentType: "application/json", body: "ok",
body: JSON.stringify({ keys: [] }), headers: { "Access-Control-Allow-Origin": "*" },
}); });
}); });