From 5615e9a4fbde2379421d33b2dd0be26f7c2dd2bd Mon Sep 17 00:00:00 2001 From: kyy Date: Thu, 7 May 2026 10:57:11 +0900 Subject: [PATCH] =?UTF-8?q?orgfront=20=ED=85=8C=EC=8A=A4=ED=8A=B8/?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- orgfront/tests/orgchart-picker.spec.ts | 107 +++++++++++------- orgfront/tests/orgchart-vector-render.spec.ts | 59 ++++++---- 2 files changed, 106 insertions(+), 60 deletions(-) diff --git a/orgfront/tests/orgchart-picker.spec.ts b/orgfront/tests/orgchart-picker.spec.ts index f55056db..7fbf98ae 100644 --- a/orgfront/tests/orgchart-picker.spec.ts +++ b/orgfront/tests/orgchart-picker.spec.ts @@ -1,5 +1,13 @@ import { expect, test } from "@playwright/test"; +const shareToken = "playwright"; + +function withShareToken(path: string) { + return path.includes("?") + ? `${path}&token=${shareToken}` + : `${path}?token=${shareToken}`; +} + type TenantFixture = { id: string; type: string; @@ -75,41 +83,58 @@ async function seedOrgfrontAuth(page: Parameters[0]["page"]) { }, expires_at: issuedAt + 3600, }; - - window.localStorage.setItem( + const storageKeys = [ + "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", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc/:orgfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc:devfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc/:devfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "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", - 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"); }, { issuedAt: nowInSeconds }, ); 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({ status: 200, - contentType: "application/json", - body: JSON.stringify({ keys: [] }), + body: "ok", + headers: { "Access-Control-Allow-Origin": "*" }, }); }); } @@ -186,7 +211,7 @@ test.beforeEach(async ({ page }) => { test("developer navigation exposes chart, picker, and embed preview", async ({ page, }) => { - await page.goto("/"); + await page.goto(withShareToken("/chart")); 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 ({ page, }) => { - await page.goto("/picker"); + await page.goto(withShareToken("/picker")); await expect(page.getByLabel("선택 모드")).toHaveValue("multiple"); 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 ({ page, }) => { - await page.goto("/embed/picker?mode=single&select=user"); + await page.goto(withShareToken("/embed/picker?mode=single&select=user")); await expect( 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 ({ page, }) => { - await page.goto("/embed-preview"); + await page.goto(withShareToken("/embed-preview")); await expect(page.getByLabel("선택 모드")).toHaveValue("multiple"); 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 ({ page, }) => { - await page.goto("/embed-preview"); + await page.goto(withShareToken("/embed-preview")); await page.getByLabel("tenant ID").fill("company-baron"); 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 ({ 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.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 ({ page, }) => { - await page.goto("/embed-preview"); + await page.goto(withShareToken("/embed-preview")); const picker = page.frameLocator("iframe"); 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 ({ page, }) => { - await page.goto("/embed-preview"); + await page.goto(withShareToken("/embed-preview")); const picker = page.frameLocator("iframe"); 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 ({ 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 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 ({ 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"); 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 ({ 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 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 ({ 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"); 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 ({ 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"); 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 ({ 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"); 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 ({ 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"); 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 ({ 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 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 ({ 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"); 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 page.goto( - "/embed-preview?mode=multiple&select=both&includeDescendants=false", + withShareToken( + "/embed-preview?mode=multiple&select=both&includeDescendants=false", + ), ); picker = page.frameLocator("iframe"); await picker.getByLabel("Engineering 선택").check(); diff --git a/orgfront/tests/orgchart-vector-render.spec.ts b/orgfront/tests/orgchart-vector-render.spec.ts index 7948a492..bfd55ae0 100644 --- a/orgfront/tests/orgchart-vector-render.spec.ts +++ b/orgfront/tests/orgchart-vector-render.spec.ts @@ -214,41 +214,58 @@ test("org chart places multi-tenant users only on leaf memberships without dupli }, expires_at: seededIssuedAt + 3600, }; - - window.localStorage.setItem( + const storageKeys = [ + "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", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc/:orgfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc:devfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "oidc.user:http://localhost:5000/oidc/:devfront", - JSON.stringify(mockOidcUser), - ); - window.localStorage.setItem( "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", - 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"); }, { issuedAt }, ); 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({ status: 200, - contentType: "application/json", - body: JSON.stringify({ keys: [] }), + body: "ok", + headers: { "Access-Control-Allow-Origin": "*" }, }); });