From f7d37211399d355661fb9a8b0fcd68f3214a9d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20G=C3=B6r=C3=B6mbei?= Date: Mon, 13 Apr 2026 18:43:39 +0200 Subject: [PATCH] feat(e2e): seed workflow via dev-token and assert details page Add workflow-seeded Playwright spec: mint JWT, create workflow via API, inject lcp.lowcode.session.v1, assert GET /api/workflows/{id} is 200 and main shows the workflow name. npm scripts e2e:seeded (+ ui/debug). Document localhost API base and optional E2E_API_BASE; update live e2e docs. Made-with: Cursor --- docs/live/02_allapot.md | 2 +- docs/live/03_kovetkezo_lepesek.md | 2 +- docs/live/e2e-smoke-plan.md | 9 +++- frontend/e2e/workflow-seeded.spec.ts | 68 ++++++++++++++++++++++++++++ frontend/package.json | 3 ++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 frontend/e2e/workflow-seeded.spec.ts diff --git a/docs/live/02_allapot.md b/docs/live/02_allapot.md index 4f15138..b99d340 100644 --- a/docs/live/02_allapot.md +++ b/docs/live/02_allapot.md @@ -63,7 +63,7 @@ Drift-proof observability egy greenfield lowcode platformban. - **Frontend (Angular)** - - **E2E smoke (Playwright):** `frontend/e2e/smoke.spec.ts` — fő low-code + **New workflow/entity**, **Admin tenants**, **Upgrade**, **Auth** + **`/lowcode/auth/callback`** + részletes útvonalak (workflow / run / entity / records, nem létező UUID-val); CI: `scripts/e2e-smoke-ci.sh` → `npm run e2e:smoke` + **`frontend-e2e`**; lokális Windows: `scripts/e2e-smoke-ci.ps1`; közreműködői útmutató: [`CONTRIBUTING.md`](../../CONTRIBUTING.md), [`frontend/README.md`](../../frontend/README.md) — [`e2e-smoke-plan.md`](e2e-smoke-plan.md). + - **E2E smoke (Playwright):** `frontend/e2e/smoke.spec.ts` — fő low-code + **New workflow/entity**, **Admin tenants**, **Upgrade**, **Auth** + **`/lowcode/auth/callback`** + részletes útvonalak (workflow / run / entity / records, nem létező UUID-val); CI: `scripts/e2e-smoke-ci.sh` → `npm run e2e:smoke` + **`frontend-e2e`**; lokális Windows: `scripts/e2e-smoke-ci.ps1`; közreműködői útmutató: [`CONTRIBUTING.md`](../../CONTRIBUTING.md), [`frontend/README.md`](../../frontend/README.md) — [`e2e-smoke-plan.md`](e2e-smoke-plan.md). **Opcionális seedelt E2E:** `e2e/workflow-seeded.spec.ts` — `npm run e2e:seeded` (dev-token + workflow létrehozás + session → létező workflow details; nem a CI smoke). - **Iter 67+ termék:** ütem és soron következő slice-ok — [`roadmap-iter-67-product.md`](roadmap-iter-67-product.md). **67a:** globális **fejléc** — aktuális **tenant** (élő frissítés `setLowCodeSession` után); fő nav: Workflows / Runs / Entities, Auth, Admin, Upgrade; **`/`** átirányítás **`/lowcode/workflows`** (demó belépés). **67b:** **Workflows** lista — név szerinti **kliens oldali szűrő** + jobb üres állapot szövegek. **67c:** **Entities** lista — ugyanilyen név szűrő + **Workflows / All runs** linkek; **Entity records** — üres vs. szűrő-0 találat szétválasztva, „Showing X of Y”. **67d:** **Workflow runs** — **szerver oldali** szűrők (állapot, started after/before UTC), lapozás, üres állapotok; nav: **Entities**. - Low-code **auth** (`/lowcode/auth`, `/lowcode/auth/callback`): dev token + opcionális **OIDC** (PKCE), ha a backend `spa-oidc-config` elérhető — [`oidc-jwt-bearer.md`](oidc-jwt-bearer.md); **BFF módban** (`meta.enabled && configured`): induláskor `bff/meta`, interceptor **`withCredentials`**, nincs SPA Bearer a store-ból; auth oldalon BFF login / session / logout — [`auth-bff-httponly.md`](auth-bff-httponly.md). **Dev proxy** (`frontend/proxy.conf.json`): **`changeOrigin: false`** az `/api` felé, hogy a backend `Host`-ja megegyezzen a SPA originnel (`localhost:4200`) és a BFF **`redirect_uri`** / IdP regisztráció összhangban legyen (§ *62c+ — helyi dev smoke*, § *teszt IdP regisztráció*). - Workflow details oldalon a read-only **Viewer v2** működik (kártyák + nyilak): step típus szerinti alcím / összefoglaló, `foreach`/`switch` branch előnézet, **JSON →** ugrás a JSON szerkesztőhöz; közös `lowcode-workflow-viewer-utils` + unit teszt; a JSON/Viewer nézet váltása stabil. **Builder** (iter 58a + **58b** New workflow + **58c** natív drag&drop fogó): lépés **palette**, **↑↓** + **húzd–ejtés** sorrend, törlés, JSON szinkron — [`workflow-visual-builder.md`](workflow-visual-builder.md), `lowcode-workflow-builder-utils` + teszt (`moveBuilderStepToSlot`); **New** oldalon **Builder | JSON** váltó + Prettify/Minify a JSON nézetben; **58c+** (dependency nélkül): ~**44px** fogó / ↑↓, érintésre ajánlott **↑↓** a szövegben; **`@angular/cdk`:** dokumentált **defer** — ugyanott § *Döntés*. diff --git a/docs/live/03_kovetkezo_lepesek.md b/docs/live/03_kovetkezo_lepesek.md index 1f54d53..6de4f7e 100644 --- a/docs/live/03_kovetkezo_lepesek.md +++ b/docs/live/03_kovetkezo_lepesek.md @@ -9,7 +9,7 @@ ## Workflow engine — ACTIVE -**ACTIVE (WIP=1):** **E2E további réteg (opcionális)** — auth / OIDC / részletes oldalak, ha priorítás; fő navigációs smoke + **auth/callback** + részletes útvonalak (hiányzó UUID): [`e2e-smoke-plan.md`](e2e-smoke-plan.md) ✅; Windows **PowerShell** runner: `scripts/e2e-smoke-ci.ps1` ✅. **Minőség / API 68** — **68a–k** ✅ (workflow + entitás/rekord + futások + domainCommand — [`roadmap-iter-68-quality.md`](roadmap-iter-68-quality.md)). **Termék 67 (a–d)** ✅ — [`roadmap-iter-67-product.md`](roadmap-iter-67-product.md). További backlog: [`02_allapot.md`](02_allapot.md) · [`PROJECT_CONTEXT.md`](../PROJECT_CONTEXT.md). **66+ enterprise** (supply-chain, Gitleaks, SBOM, Dependabot, CodeQL — [`ci-codeql.md`](ci-codeql.md)) ✅; Angular **LTS upgrade** + `npm audit` kapu külön hullám — [`ci-supply-chain.md`](ci-supply-chain.md). Történeti roadmap: [`roadmap-iter-65-plus.md`](roadmap-iter-65-plus.md) · [`roadmap-iter-64-plus.md`](roadmap-iter-64-plus.md). **Integrációs tesztek (Backend.Tests)** (fő vonal kész): `AuthSpaOidcConfigTests`; `AdminObservabilityTests`; `AdminUpgradeRunsTests` / `AdminUpgradeRunsMutationTests`; `AdminInstallationTests`; `AdminAuditTests`; `AdminTenantsTests`; `BffAuthEndpointsTests` / `BffSessionBearerWorkflowTests`. **Iter 65** ✅ (**65a–c**, **PR #112–114** — [`roadmap-iter-65-plus.md`](roadmap-iter-65-plus.md) · [`api-lifecycle-headers.md`](api-lifecycle-headers.md)). **Iter 64** ✅ (**64a–e**, **PR #106–110** — [`roadmap-iter-64-plus.md`](roadmap-iter-64-plus.md); záró: **64e** **PR #110** — [`ci-dotnet-format.md`](ci-dotnet-format.md)). **Iter 63** ✅ (**63a–d**, **PR #102–105** — [`roadmap-next-iterations.md`](roadmap-next-iterations.md)). **62c+ e2e** hátrasorolva (nem blokkoló). **58c+** touch UX ✅ **PR #99** — [`workflow-visual-builder.md`](workflow-visual-builder.md). **58c+ `@angular/cdk`:** elhalasztva — ugyanott § *Döntés*. **62c+** doksi ✅ — [`auth-bff-httponly.md`](auth-bff-httponly.md) (**PR #95**, **PR #97**). **62c — BFF** ✅ **PR #93**. **62b2** ✅ [`oidc-jwt-bearer.md`](oidc-jwt-bearer.md). **62b1** ✅. **62** ✅. **61** ✅. **60–58** ✅. +**ACTIVE (WIP=1):** **E2E további réteg (opcionális)** — auth / OIDC happy path, entity/run seedelt részletek, ha priorítás; fő navigációs smoke + **auth/callback** + részletes útvonalak (hiányzó UUID): [`e2e-smoke-plan.md`](e2e-smoke-plan.md) ✅; **seedelt workflow details:** `npm run e2e:seeded` ✅; Windows **PowerShell** runner: `scripts/e2e-smoke-ci.ps1` ✅. **Minőség / API 68** — **68a–k** ✅ (workflow + entitás/rekord + futások + domainCommand — [`roadmap-iter-68-quality.md`](roadmap-iter-68-quality.md)). **Termék 67 (a–d)** ✅ — [`roadmap-iter-67-product.md`](roadmap-iter-67-product.md). További backlog: [`02_allapot.md`](02_allapot.md) · [`PROJECT_CONTEXT.md`](../PROJECT_CONTEXT.md). **66+ enterprise** (supply-chain, Gitleaks, SBOM, Dependabot, CodeQL — [`ci-codeql.md`](ci-codeql.md)) ✅; Angular **LTS upgrade** + `npm audit` kapu külön hullám — [`ci-supply-chain.md`](ci-supply-chain.md). Történeti roadmap: [`roadmap-iter-65-plus.md`](roadmap-iter-65-plus.md) · [`roadmap-iter-64-plus.md`](roadmap-iter-64-plus.md). **Integrációs tesztek (Backend.Tests)** (fő vonal kész): `AuthSpaOidcConfigTests`; `AdminObservabilityTests`; `AdminUpgradeRunsTests` / `AdminUpgradeRunsMutationTests`; `AdminInstallationTests`; `AdminAuditTests`; `AdminTenantsTests`; `BffAuthEndpointsTests` / `BffSessionBearerWorkflowTests`. **Iter 65** ✅ (**65a–c**, **PR #112–114** — [`roadmap-iter-65-plus.md`](roadmap-iter-65-plus.md) · [`api-lifecycle-headers.md`](api-lifecycle-headers.md)). **Iter 64** ✅ (**64a–e**, **PR #106–110** — [`roadmap-iter-64-plus.md`](roadmap-iter-64-plus.md); záró: **64e** **PR #110** — [`ci-dotnet-format.md`](ci-dotnet-format.md)). **Iter 63** ✅ (**63a–d**, **PR #102–105** — [`roadmap-next-iterations.md`](roadmap-next-iterations.md)). **62c+ e2e** hátrasorolva (nem blokkoló). **58c+** touch UX ✅ **PR #99** — [`workflow-visual-builder.md`](workflow-visual-builder.md). **58c+ `@angular/cdk`:** elhalasztva — ugyanott § *Döntés*. **62c+** doksi ✅ — [`auth-bff-httponly.md`](auth-bff-httponly.md) (**PR #95**, **PR #97**). **62c — BFF** ✅ **PR #93**. **62b2** ✅ [`oidc-jwt-bearer.md`](oidc-jwt-bearer.md). **62b1** ✅. **62** ✅. **61** ✅. **60–58** ✅. > **56–57** lezárva: SQL Server EF + Helm backup — [`sqlserver-platform.md`](sqlserver-platform.md), [`k3s-home-lab.md`](k3s-home-lab.md), [`container-deploy.md`](container-deploy.md). diff --git a/docs/live/e2e-smoke-plan.md b/docs/live/e2e-smoke-plan.md index c2aba3b..51db526 100644 --- a/docs/live/e2e-smoke-plan.md +++ b/docs/live/e2e-smoke-plan.md @@ -25,6 +25,7 @@ Első futás előtt böngésző motor: `npm run e2e:install-browsers` (a `fronte | `powershell -File scripts/e2e-smoke-ci.ps1` | Ugyanaz, **Windows PowerShell 5.1+** vagy **pwsh** (a repo gyökeréből; `npm` és `dotnet` a PATH-on). | | `npm run e2e` | Összes Playwright teszt az `e2e/` alatt. Ha **nincs** `PW_NO_WEBSERVER`, a konfig megpróbálja saját `webServer` blokkal indítani a `dotnet run` + `ng serve`-et (lokálisan ez néha kényelmetlen; CI **nem** ezt használja). | | `npm run e2e:smoke` | Csak a **smoke** fájl (`e2e/smoke.spec.ts`) — ezt futtatja a CI script is. | +| `npm run e2e:seeded` | **`workflow-seeded.spec.ts`**: dev-token + `POST /api/workflows`, majd SPA session injektálás → létező workflow részletek (nem része a CI smoke-nak). | | `PW_NO_WEBSERVER=1 npm run e2e:smoke` | Csak smoke — **előbb** kézzel indítsd a 5002-es backendet és a 4200-as dev szervert két terminálban. | **Megjegyzés (Windows):** az `ng serve` gyakran **`http://localhost:4200`**-on válaszol; a **`127.0.0.1:4200`** nem mindig ugyanaz a stacken. A Playwright **`baseURL`** és a CI script **`localhost:4200`**-at használ. @@ -48,6 +49,10 @@ Első futás előtt böngésző motor: `npm run e2e:install-browsers` (a `fronte A **11–14** tesztek egy rögzített, üres adatbázisban nem létező UUID-t használnak (`00000000-0000-0000-0000-000000000001`); így nincs szükség seedre, és a részletes útvonalak is lefedettek. +### Seedelt workflow (opcionális, nem CI smoke) + +A **`e2e/workflow-seeded.spec.ts`** a backendhez közvetlenül hív (`http://localhost:5002`): `POST /api/auth/dev-token` (tenant: `default`), majd `POST /api/workflows` JWT-vel. A böngészőben `sessionStorage` (`lcp.lowcode.session.v1`) beállítása után megnyitja `/lowcode/workflows/{id}` és ellenőrzi a workflow nevét. **Ne** használj `127.0.0.1`-et az API base URL-hez fejlesztői módban a tenant feloldás miatt; az env **`E2E_API_BASE`** felülírhatja az alapértelmezett `http://localhost:5002`-t. + ## CI - Workflow: **`.github/workflows/ci.yml`** — job **`frontend-e2e`** (a **`frontend-quality`** után; a **Docker** job erre is vár). @@ -56,11 +61,11 @@ A **11–14** tesztek egy rögzített, üres adatbázisban nem létező UUID-t h ## Következő lépések (backlog) - BFF / OIDC **happy path** (IdP round-trip, ha van stabil teszt IdP / mock). -- Részletes oldalak **létező** erőforrással (seed / fixture) — ha kell mélyebb E2E. +- További részletes oldalak **létező** erőforrással (entity / run) — kiterjeszthető az `e2e:seeded` mintára. ## DoD (E2E iteráció — MVP) -- `package.json` script: `npm run e2e`, `npm run e2e:smoke` (CI / smoke), `npm run e2e:smoke:ui` / `npm run e2e:smoke:debug` (smoke + UI/debug), `npm run e2e:ui` / `npm run e2e:debug` (összes spec), `npm run e2e:report` (HTML riport böngészőben; lokálisan), `npm run e2e:install-browsers`. +- `package.json` script: `npm run e2e`, `npm run e2e:smoke` (CI / smoke), `npm run e2e:seeded` (opcionális seedelt workflow E2E), `npm run e2e:smoke:ui` / `npm run e2e:smoke:debug` (smoke + UI/debug), `npm run e2e:ui` / `npm run e2e:debug` (összes spec), `npm run e2e:report` (HTML riport böngészőben; lokálisan), `npm run e2e:install-browsers`. - CI-ben zöld **`frontend-e2e`** job. - Új dependency: **`@playwright/test`** — governance szerint dependency review / jóváhagyás; lásd `docs/GOVERNANCE.md`. diff --git a/frontend/e2e/workflow-seeded.spec.ts b/frontend/e2e/workflow-seeded.spec.ts new file mode 100644 index 0000000..13ceef3 --- /dev/null +++ b/frontend/e2e/workflow-seeded.spec.ts @@ -0,0 +1,68 @@ +import { test, expect } from '@playwright/test'; + +/** + * Uses backend dev-token + POST /api/workflows, then injects SPA session so the browser + * loads workflow details with a real row. API calls use `localhost` (not 127.0.0.1) so + * Development tenant resolution matches the default tenant; see TenantResolutionMiddleware. + */ +const API_BASE = process.env.E2E_API_BASE ?? 'http://localhost:5002'; + +const SESSION_KEY = 'lcp.lowcode.session.v1'; + +const MINIMAL_DEF = '{"steps":[{"type":"noop"}]}'; + +test.describe('Workflow details (seeded)', () => { + test('shows name for workflow created via API', async ({ page, request }) => { + const wfName = `e2e-seeded-${Date.now()}`; + + const tokenResp = await request.post(`${API_BASE}/api/auth/dev-token`, { + headers: { 'Content-Type': 'application/json' }, + data: { subject: 'e2e-workflow-seeded', tenantSlug: 'default', roles: [] }, + }); + expect(tokenResp.ok(), await tokenResp.text()).toBeTruthy(); + const tokenJson = (await tokenResp.json()) as { accessToken: string }; + expect(tokenJson.accessToken).toBeTruthy(); + + const createResp = await request.post(`${API_BASE}/api/workflows`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${tokenJson.accessToken}`, + }, + data: { name: wfName, definitionJson: MINIMAL_DEF }, + }); + expect(createResp.ok(), await createResp.text()).toBeTruthy(); + const created = (await createResp.json()) as { workflowDefinitionId: string }; + const id = created.workflowDefinitionId; + expect(id).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, + ); + + const sessionPayload = JSON.stringify({ + tenantSlug: 'default', + accessToken: tokenJson.accessToken, + }); + + await page.addInitScript( + ({ key, payload }: { key: string; payload: string }) => { + sessionStorage.setItem(key, payload); + }, + { key: SESSION_KEY, payload: sessionPayload }, + ); + + const getWorkflow = page.waitForResponse( + (r) => + r.request().method() === 'GET' && + r.url().includes(`/api/workflows/${id}`) && + !r.url().includes('/runs'), + ); + + await page.goto(`/lowcode/workflows/${id}`); + + const detailsResp = await getWorkflow; + expect(detailsResp.status(), await detailsResp.text()).toBe(200); + + await expect(page.getByRole('heading', { name: 'Workflow' })).toBeVisible(); + await expect(page.getByRole('main')).toContainText(wfName, { timeout: 15_000 }); + await expect(page.getByRole('link', { name: '← Workflows' })).toBeVisible(); + }); +}); diff --git a/frontend/package.json b/frontend/package.json index f79553d..0582e02 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,9 @@ "test": "ng test", "e2e": "playwright test", "e2e:smoke": "playwright test e2e/smoke.spec.ts", + "e2e:seeded": "playwright test e2e/workflow-seeded.spec.ts", + "e2e:seeded:ui": "playwright test e2e/workflow-seeded.spec.ts --ui", + "e2e:seeded:debug": "playwright test e2e/workflow-seeded.spec.ts --debug", "e2e:smoke:ui": "playwright test e2e/smoke.spec.ts --ui", "e2e:smoke:debug": "playwright test e2e/smoke.spec.ts --debug", "e2e:ui": "playwright test --ui",