diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..9c160d1 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,19 @@ +# Multi-stage Build für das Effigenix-Backend. +# Genutzt vom E2E-Test-Stack (test-automation/docker-compose.e2e.yml). + +FROM maven:3.9-eclipse-temurin-21-alpine AS build +WORKDIR /app + +# Dependency-Layer cachen +COPY pom.xml . +RUN mvn dependency:go-offline -q + +# Source kompilieren und paketieren (Tests überspringen) +COPY src ./src +RUN mvn package -DskipTests -q + +# Schlankes Runtime-Image +FROM eclipse-temurin:21-jre-alpine +WORKDIR /app +COPY --from=build /app/target/*.jar app.jar +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/backend/src/main/resources/application-e2e.yml b/backend/src/main/resources/application-e2e.yml new file mode 100644 index 0000000..ab92fc1 --- /dev/null +++ b/backend/src/main/resources/application-e2e.yml @@ -0,0 +1,15 @@ +# Spring-Profil für E2E-Tests gegen echte PostgreSQL-Datenbank. +# Aktiviert via SPRING_PROFILES_ACTIVE=e2e (docker-compose.e2e.yml). +# Liquibase-Kontext "e2e" aktiviert Changeset 039-seed-e2e-testusers. + +spring: + liquibase: + contexts: e2e + +sentry: + dsn: "" + +logging: + level: + root: WARN + de.effigenix: INFO diff --git a/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql new file mode 100644 index 0000000..d1d4e3e --- /dev/null +++ b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql @@ -0,0 +1,46 @@ +-- E2E-Testbenutzer für automatisierte Tests. +-- Wird nur mit Liquibase-Kontext "e2e" eingespielt (039-seed-e2e-testusers.xml). +-- +-- Benutzer: +-- admin / admin123 → ADMIN-Rolle (darf alles) +-- viewer / test1234 → SALES_STAFF-Rolle (nur MASTERDATA_READ, kein WRITE) + +-- admin (Passwort: admin123) +INSERT INTO users (id, username, email, password_hash, branch_id, status, created_at, last_login) +VALUES ( + '00000000-0000-0000-0000-000000000001', + 'admin', + 'admin@effigenix.com', + '$2a$12$SJmX80hUZoA66W77CX7cHeRw1TPscXD6S8HYEZfhJ5PxTfkbwbLdi', + NULL, + 'ACTIVE', + CURRENT_TIMESTAMP, + NULL +) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO user_roles (user_id, role_id) +SELECT '00000000-0000-0000-0000-000000000001', id +FROM roles +WHERE name = 'ADMIN' +ON CONFLICT DO NOTHING; + +-- viewer (Passwort: test1234) → SALES_STAFF = nur MASTERDATA_READ +INSERT INTO users (id, username, email, password_hash, branch_id, status, created_at, last_login) +VALUES ( + '00000000-0000-0000-0000-000000000002', + 'viewer', + 'viewer@effigenix.com', + '$2a$12$LJ3m4ys3uz2YPMRvKbmrZOZHAMSKL4FBy.XLR3WnCKsMbVDfGKJVa', + NULL, + 'ACTIVE', + CURRENT_TIMESTAMP, + NULL +) +ON CONFLICT (id) DO NOTHING; + +INSERT INTO user_roles (user_id, role_id) +SELECT '00000000-0000-0000-0000-000000000002', id +FROM roles +WHERE name = 'SALES_STAFF' +ON CONFLICT DO NOTHING; diff --git a/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml new file mode 100644 index 0000000..26a1c78 --- /dev/null +++ b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/backend/src/main/resources/db/changelog/db.changelog-master.xml b/backend/src/main/resources/db/changelog/db.changelog-master.xml index bc14b9b..2290dc1 100644 --- a/backend/src/main/resources/db/changelog/db.changelog-master.xml +++ b/backend/src/main/resources/db/changelog/db.changelog-master.xml @@ -44,5 +44,6 @@ + diff --git a/justfile b/justfile index 075edc5..f9a57cc 100644 --- a/justfile +++ b/justfile @@ -50,6 +50,10 @@ test-frontend: test-backend: cd backend && mvn test +# E2E-Tests (Playwright API-Tests via Docker-Stack) +test-e2e: + docker compose -f test-automation/docker-compose.e2e.yml up --build --abort-on-container-exit --exit-code-from e2e-runner + # ─── Code Generation ───────────────────────────────────── # OpenAPI Spec + TypeScript Types generieren diff --git a/test-automation/TASKS.md b/test-automation/TASKS.md index 07d8310..8731494 100644 --- a/test-automation/TASKS.md +++ b/test-automation/TASKS.md @@ -25,18 +25,19 @@ Konzept: [`docs/ui-testing-automation.md`](./docs/ui-testing-automation.md) > Playwright-Setup in `test-automation/web-ui/`. API-Tests ohne Browser. -- [ ] `web-ui/package.json` finalisieren (Abhängigkeiten prüfen, ggf. pnpm workspace eintragen) -- [ ] `web-ui/playwright.config.ts` validieren und anpassen -- [ ] `web-ui/fixtures/auth.fixture.ts` implementieren und testen -- [ ] `web-ui/fixtures/seed.fixture.ts` implementieren (DB-Reset-Strategie klären) -- [ ] `web-ui/helpers/api-client.ts` typisiert implementieren -- [ ] Backend `Dockerfile` erstellen (test-Profil, mit Seed-Daten) -- [ ] `docker-compose.e2e.yml` validieren (DB → Backend → e2e-runner Healthchecks) -- [ ] `web-ui/Dockerfile` validieren -- [ ] Erste Spec: `tests/api/masterdata/categories.spec.ts` (TC-CAT, Issue #62) -- [ ] Erste Spec: `tests/api/masterdata/suppliers.spec.ts` (TC-SUP, Issue #63) +- [x] `web-ui/package.json` finalisieren (standalone, kein Workspace-Eintrag nötig) +- [x] `web-ui/playwright.config.ts` validieren und anpassen +- [x] `web-ui/fixtures/auth.fixture.ts` implementieren (viewer-Passwort: test1234) +- [x] `web-ui/fixtures/seed.fixture.ts` implementieren (Strategie: Option B – UUID-Suffixe) +- [x] `web-ui/helpers/api-client.ts` typisiert implementieren +- [x] Backend `Dockerfile` erstellen (Multi-stage Maven + JRE, Profil via SPRING_PROFILES_ACTIVE) +- [x] `docker-compose.e2e.yml` validieren (Profil auf `e2e` korrigiert, Viewer-Passwort angepasst) +- [x] `web-ui/Dockerfile` korrigiert (standalone pnpm install, kein Workspace) +- [x] `application-e2e.yml` + Liquibase-Changeset 039 (admin + viewer e2e-Benutzer) +- [x] Erste Spec: `tests/api/masterdata/categories.spec.ts` (TC-CAT, Issue #62) +- [x] Erste Spec: `tests/api/masterdata/suppliers.spec.ts` (TC-SUP-01 ACTIVE korrigiert, Issue #63) - [ ] End-to-end-Run lokal erfolgreich: `docker compose -f test-automation/docker-compose.e2e.yml up` -- [ ] `just test-e2e` Recipe im `justfile` ergänzen +- [x] `just test-e2e` Recipe im `justfile` ergänzt --- diff --git a/test-automation/docker-compose.e2e.yml b/test-automation/docker-compose.e2e.yml index c71e01e..f8a2e1d 100644 --- a/test-automation/docker-compose.e2e.yml +++ b/test-automation/docker-compose.e2e.yml @@ -21,7 +21,7 @@ services: context: ../backend dockerfile: Dockerfile environment: - SPRING_PROFILES_ACTIVE: test + SPRING_PROFILES_ACTIVE: e2e SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/effigenix SPRING_DATASOURCE_USERNAME: effigenix SPRING_DATASOURCE_PASSWORD: effigenix @@ -45,7 +45,7 @@ services: TEST_USER_ADMIN: admin TEST_USER_ADMIN_PASS: admin123 TEST_USER_VIEWER: viewer - TEST_USER_VIEWER_PASS: viewer123 + TEST_USER_VIEWER_PASS: test1234 depends_on: backend: condition: service_healthy diff --git a/test-automation/web-ui/Dockerfile b/test-automation/web-ui/Dockerfile index f767bf8..52e2ad2 100644 --- a/test-automation/web-ui/Dockerfile +++ b/test-automation/web-ui/Dockerfile @@ -1,20 +1,18 @@ +# E2E-Test-Runner (Playwright API-Tests, kein Browser) +# Build-Context: Repo-Root (..) +# Standalone – benötigt keine pnpm-Workspace-Konfiguration. + FROM mcr.microsoft.com/playwright:v1.51.0-noble -WORKDIR /app - -# pnpm installieren RUN npm install -g pnpm@9 -# Workspace-Root und e2e-Package-Manifest kopieren -COPY frontend/package.json frontend/pnpm-workspace.yaml ./ -COPY test-automation/web-ui/package.json ./test-automation/web-ui/ - -# pnpm Install (nur Prod + Dev-Deps des e2e-Pakets) -RUN pnpm install --frozen-lockfile - -# Test-Code und Konfiguration kopieren -COPY test-automation/web-ui/ ./test-automation/web-ui/ - WORKDIR /app/test-automation/web-ui -ENTRYPOINT ["pnpm", "exec", "playwright", "test"] +# Nur package.json zuerst für Layer-Caching +COPY test-automation/web-ui/package.json ./ +RUN pnpm install --no-frozen-lockfile + +# Test-Code kopieren +COPY test-automation/web-ui/ ./ + +ENTRYPOINT ["pnpm", "exec", "playwright", "test", "--project=api"] diff --git a/test-automation/web-ui/fixtures/auth.fixture.ts b/test-automation/web-ui/fixtures/auth.fixture.ts index 797fac1..8a46feb 100644 --- a/test-automation/web-ui/fixtures/auth.fixture.ts +++ b/test-automation/web-ui/fixtures/auth.fixture.ts @@ -22,7 +22,7 @@ export const test = base.extend({ const res = await request.post('/api/auth/login', { data: { username: process.env.TEST_USER_VIEWER ?? 'viewer', - password: process.env.TEST_USER_VIEWER_PASS ?? 'viewer123', + password: process.env.TEST_USER_VIEWER_PASS ?? 'test1234', }, }); expect(res.status()).toBe(200); diff --git a/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts index 6a224c7..c7a48fa 100644 --- a/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts +++ b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts @@ -12,7 +12,7 @@ test.describe('TC-SUP: Lieferanten', () => { }); expect(res.status()).toBe(201); const body = await res.json(); - expect(body.status).toBe('AKTIV'); + expect(body.status).toBe('ACTIVE'); }); test('TC-SUP-02: Lieferant erscheint in Liste nach Erstellung', async ({ request, adminToken }) => { diff --git a/test-automation/web-ui/tsconfig.json b/test-automation/web-ui/tsconfig.json index 47ddf1b..0fcbd3b 100644 --- a/test-automation/web-ui/tsconfig.json +++ b/test-automation/web-ui/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", + "module": "CommonJS", + "moduleResolution": "node16", "strict": true, "esModuleInterop": true, "skipLibCheck": true,