From c84629cc4edd620e3eda62217120c760cc78b552 Mon Sep 17 00:00:00 2001 From: Janosch Date: Fri, 27 Mar 2026 09:41:35 +0100 Subject: [PATCH] init e2e ui tests base skeleton --- test-automation/README.md | 55 ++ test-automation/TASKS.md | 96 +++ test-automation/docker-compose.e2e.yml | 54 ++ test-automation/docs/ui-testing-automation.md | 651 ++++++++++++++++++ test-automation/tui/README.md | 51 ++ test-automation/web-ui/Dockerfile | 20 + .../web-ui/fixtures/auth.fixture.ts | 34 + .../web-ui/fixtures/seed.fixture.ts | 29 + test-automation/web-ui/helpers/api-client.ts | 45 ++ test-automation/web-ui/package.json | 17 + test-automation/web-ui/playwright.config.ts | 31 + .../tests/api/auth/authorization.spec.ts | 30 + .../tests/api/masterdata/categories.spec.ts | 47 ++ .../tests/api/masterdata/suppliers.spec.ts | 47 ++ test-automation/web-ui/tests/web/.gitkeep | 0 test-automation/web-ui/tsconfig.json | 12 + 16 files changed, 1219 insertions(+) create mode 100644 test-automation/README.md create mode 100644 test-automation/TASKS.md create mode 100644 test-automation/docker-compose.e2e.yml create mode 100644 test-automation/docs/ui-testing-automation.md create mode 100644 test-automation/tui/README.md create mode 100644 test-automation/web-ui/Dockerfile create mode 100644 test-automation/web-ui/fixtures/auth.fixture.ts create mode 100644 test-automation/web-ui/fixtures/seed.fixture.ts create mode 100644 test-automation/web-ui/helpers/api-client.ts create mode 100644 test-automation/web-ui/package.json create mode 100644 test-automation/web-ui/playwright.config.ts create mode 100644 test-automation/web-ui/tests/api/auth/authorization.spec.ts create mode 100644 test-automation/web-ui/tests/api/masterdata/categories.spec.ts create mode 100644 test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts create mode 100644 test-automation/web-ui/tests/web/.gitkeep create mode 100644 test-automation/web-ui/tsconfig.json diff --git a/test-automation/README.md b/test-automation/README.md new file mode 100644 index 0000000..3a36779 --- /dev/null +++ b/test-automation/README.md @@ -0,0 +1,55 @@ +# test-automation + +Automatisierte UI/E2E-Tests für Effigenix ERP. + +> **WICHTIG – Branch-Schutz:** +> Alle Arbeiten an diesem Ordner finden ausschliesslich im Branch `experiment/test-automation` statt. +> **Ein Merge in `main` darf NUR mit ausdrücklicher menschlicher Bestätigung erfolgen.** +> Kein automatischer Merge, kein Auto-Squash, kein Force-Push auf `main`. + +--- + +## Struktur + +``` +test-automation/ +├── README.md # Diese Datei +├── TASKS.md # Phasen & Aufgaben (Tracking) +├── docs/ +│ └── ui-testing-automation.md # Technisches Konzept +├── web-ui/ # Playwright E2E-Tests (Web + API) +│ ├── package.json +│ ├── playwright.config.ts +│ ├── Dockerfile +│ ├── tests/ +│ │ ├── api/ # API-Level-Tests (kein Browser) +│ │ └── web/ # Browser-UI-Tests (wächst mit Web-App) +│ ├── fixtures/ # Auth- und Seed-Fixtures +│ └── helpers/ # Typisierter API-Wrapper +├── tui/ # TUI-Tests (vitest + ink-testing-library) +│ └── README.md +└── docker-compose.e2e.yml # Vollständiges E2E-Stack (DB + Backend + Runner) +``` + +## Quickstart + +```bash +# Alle E2E-Tests per Docker starten +docker compose -f test-automation/docker-compose.e2e.yml up --abort-on-container-exit + +# Nur bestimmte Tests +docker compose -f test-automation/docker-compose.e2e.yml run e2e-runner --grep "TC-SUP" + +# HTML-Report anzeigen (nach Test-Run) +pnpm --filter @effigenix/e2e exec playwright show-report e2e-results +``` + +## Framework-Übersicht + +| Bereich | Tool | Zweck | +|---|---|---| +| API E2E | Playwright (request context) | Backend-Akzeptanzkriterien validieren | +| Web UI | Playwright (Chromium) | Browser-Tests sobald Web-App ausgebaut | +| TUI | vitest + ink-testing-library | Terminal-UI Komponenten-Tests | + +Detailliertes technisches Konzept: [`docs/ui-testing-automation.md`](./docs/ui-testing-automation.md) diff --git a/test-automation/TASKS.md b/test-automation/TASKS.md new file mode 100644 index 0000000..701f6c3 --- /dev/null +++ b/test-automation/TASKS.md @@ -0,0 +1,96 @@ +# Test Automation – Aufgaben & Phasen + +Branch: `experiment/test-automation` +Konzept: [`docs/ui-testing-automation.md`](./docs/ui-testing-automation.md) + +> **Merge-Regel:** Kein Merge in `main` ohne ausdrückliche menschliche Bestätigung. + +--- + +## Phase 0 – TUI-Tests ausbauen + +> Sofort umsetzbar, kein neues Setup nötig. Nutzt `ink-testing-library` + `vitest`. +> Ort: `frontend/apps/cli/src/__tests__/screens/` + +- [ ] `__tests__/screens/` Verzeichnisstruktur anlegen (`masterdata/`, `production/`) +- [ ] `SupplierForm.test.tsx` – TC-SUP-01 (Pflichtfelder), TC-SUP-02, TC-SUP-03 (leerer Name) +- [ ] `CategoryForm.test.tsx` – TC-CAT-01 (Happy Path), TC-CAT-04 (Duplikat), TC-CAT-06 (leerer Name) +- [ ] `SupplierList.test.tsx` – TC-SUP-06 (Filter/Suche) +- [ ] Bestehende 4 Tests (`ConfirmDialog`, `ErrorDisplay`, `SuccessDisplay`, `useRoles`) als Vorlage prüfen +- [ ] Alle neuen TUI-Tests laufen durch (`pnpm --filter @effigenix/cli test`) + +--- + +## Phase 1 – API E2E Grundgerüst + +> 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) +- [ ] End-to-end-Run lokal erfolgreich: `docker compose -f test-automation/docker-compose.e2e.yml up` +- [ ] `just test-e2e` Recipe im `justfile` ergänzen + +--- + +## Phase 2 – Vollständige API-Coverage + +> Alle manual-testing Issues und Feature-Stories als Playwright-Specs. + +- [ ] `tests/api/masterdata/customers.spec.ts` – TC-CUS, Issue #65 +- [ ] `tests/api/masterdata/contracts.spec.ts` – TC-B2B, Issue #66 +- [ ] `tests/api/masterdata/articles.spec.ts` – TC-ART, Issue #64 +- [ ] `tests/api/auth/authorization.spec.ts` – TC-AUTH, Issue #67 +- [ ] `tests/api/production/orders.spec.ts` – US-P13–P17, Issues #38–#42 +- [ ] `tests/api/production/batches.spec.ts` – US-P09–P12, Issues #33–#36 +- [ ] `tests/api/production/recipes.spec.ts` – US-P02–P08, Issues #26–#32 +- [ ] `tests/api/production/traceability.spec.ts` – US-P18–P19, Issues #43–#44 +- [ ] `tests/api/inventory/stock.spec.ts` – Story 2.x–6.x, Issues #4–#20 +- [ ] `tests/api/inventory/movements.spec.ts` +- [ ] `tests/api/inventory/reservations.spec.ts` +- [ ] Test-Generierungs-Skript (`scripts/generate-tests-from-issue.ts`) finalisieren +- [ ] Skript in `justfile` als `just generate-test ` integrieren +- [ ] Alle Specs im Docker-Stack grün + +--- + +## Phase 3 – CI/CD Integration + +> GitHub Actions Workflow für automatische Test-Ausführung. + +- [ ] `.github/workflows/e2e.yml` erstellen +- [ ] Trigger: Push auf `main`, PRs gegen `main` +- [ ] JUnit-Report als CI-Artefakt hochladen +- [ ] Playwright HTML-Report als GitHub Pages veröffentlichen (optional) +- [ ] Badge in README einbinden + +--- + +## Phase 4 – Web UI Tests (Browser) + +> Erst sinnvoll, wenn `apps/web` ausgebaut ist. Platzhalter bereits vorhanden. + +- [ ] Browser-Projekt in `playwright.config.ts` aktivieren (`web-chromium`) +- [ ] Page Object Models für Web-App-Seiten anlegen +- [ ] Login-Flow als Browser-Test +- [ ] Erste Screen-Tests (analog zu TUI-Tests in Phase 0) +- [ ] Visuelle Regression via Playwright Screenshots (optional) + +--- + +## Offene Punkte & Entscheidungen + +| Punkt | Status | Massnahme | +|---|---|---| +| Backend `Dockerfile` | Fehlt | In Phase 1 erstellen | +| Seed-Testdaten Isolation | Offen | Strategie in Phase 1 klären (DB-Reset vor Suite oder pro Test) | +| `gh` Token `read:project` Scope | Fehlt | `gh auth refresh -s read:project` ausführen wenn nötig | +| TUI-Tests Abgrenzung | Klar | Vitest + ink-testing-library, gemockte API-Calls | +| Scanner (Tauri/mobil) | Out of scope | Separates Konzept, ggf. `test-automation/scanner/` später | diff --git a/test-automation/docker-compose.e2e.yml b/test-automation/docker-compose.e2e.yml new file mode 100644 index 0000000..c71e01e --- /dev/null +++ b/test-automation/docker-compose.e2e.yml @@ -0,0 +1,54 @@ +version: '3.8' + +# WICHTIG: Nur im Branch experiment/test-automation verwenden. +# Merge in main nur mit ausdrücklicher menschlicher Bestätigung. + +services: + db: + image: postgres:15-alpine + environment: + POSTGRES_DB: effigenix + POSTGRES_USER: effigenix + POSTGRES_PASSWORD: effigenix + healthcheck: + test: ["CMD-SHELL", "pg_isready -U effigenix"] + interval: 5s + timeout: 3s + retries: 10 + + backend: + build: + context: ../backend + dockerfile: Dockerfile + environment: + SPRING_PROFILES_ACTIVE: test + SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/effigenix + SPRING_DATASOURCE_USERNAME: effigenix + SPRING_DATASOURCE_PASSWORD: effigenix + depends_on: + db: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"] + interval: 10s + timeout: 5s + retries: 12 + ports: + - "8080:8080" + + e2e-runner: + build: + context: .. + dockerfile: test-automation/web-ui/Dockerfile + environment: + BASE_URL: http://backend:8080 + TEST_USER_ADMIN: admin + TEST_USER_ADMIN_PASS: admin123 + TEST_USER_VIEWER: viewer + TEST_USER_VIEWER_PASS: viewer123 + depends_on: + backend: + condition: service_healthy + volumes: + - ./e2e-results:/app/test-automation/web-ui/playwright-report + - ./e2e-results:/app/test-automation/web-ui/test-results diff --git a/test-automation/docs/ui-testing-automation.md b/test-automation/docs/ui-testing-automation.md new file mode 100644 index 0000000..0d4426f --- /dev/null +++ b/test-automation/docs/ui-testing-automation.md @@ -0,0 +1,651 @@ +# Technisches Konzept: UI Test Automation – Effigenix ERP + +**Stand:** 2026-03-27 +**Branch:** `experiment/test-automation` + +--- + +## 1. Ausgangslage & Ziel + +### Ist-Zustand + +Das Projekt besteht aus drei Frontend-Targets: + +| App | Technologie | Status | +|---|---|---| +| `apps/cli` | Ink + React (TUI) | Primäre operative UI – vollständig ausgebaut | +| `apps/web` | React + Vite + Tailwind v4 | Frühstadium – aktuell nur Component-Showcase | +| `apps/scanner` | Tauri v2 (mobil) | Prototype | + +Die manuellen Testfälle (GitHub Issues mit Label `manual-testing`: #62–#70) decken alle implementierten Bounded Contexts ab: + +- `TC-CAT` – Produktkategorien +- `TC-SUP` – Lieferanten +- `TC-CUS` – Kunden +- `TC-B2B` – Rahmenverträge +- `TC-AUTH` – Autorisierung Masterdata +- `TC-ART` – Artikel *(offen)* +- `TC-CROSS` – Übergreifend Masterdata/Inventory/Production *(deferred)* + +Weiterhin enthalten alle Feature-Issues (US-Pxx, Story x.x) strukturierte **Akzeptanzkriterien**. + +### Ziel + +Automatisierte UI/E2E-Tests, die: +1. Aus den GitHub-Issues (Akzeptanzkriterien + manuelle Testfälle) abgeleitet werden +2. Repeatable und CI-fähig sind +3. Per Docker reproduzierbar laufen +4. Mit wachsender Web-UI mitwachsen können + +--- + +## 2. Framework-Entscheidung: Playwright + +### Bewertungsmatrix + +| Kriterium | Playwright | Robot Framework | +|---|---|---| +| TypeScript-native | ✅ Erstklassig | ⚠️ via robotframework-browser (Python wrapper) | +| Monorepo-Integration (pnpm) | ✅ Als pnpm Package | ⚠️ Eigenes Python-Ökosystem | +| React/Vite-Support | ✅ Exzellent | ⚠️ Indirekt via Browser-Automation | +| API-Testing (REST) | ✅ `request` Context eingebaut | ✅ Eigene HTTP-Library | +| Lernkurve im Team | ✅ Gering (TypeScript-Kenntnisse vorhanden) | ⚠️ Keyword-DSL + Python | +| Docker-Image Größe | ~600 MB | ~800 MB+ | +| Parallelisierung | ✅ Built-in | ⚠️ Konfigurationsaufwand | +| Community / Ökosystem | ✅ Stark (Microsoft-backed) | ✅ Stabil (älteres Ökosystem) | + +**Entscheidung: Playwright** + +Begründung: Das Team arbeitet bereits in TypeScript. Playwright lässt sich als Workspace-Package in den bestehenden pnpm-Monorepo integrieren. Die API-Testing-Fähigkeit erlaubt es, Backend-Akzeptanzkriterien ohne Browser zu testen – ideal für den aktuellen Stand, wo die Web-UI noch im Aufbau ist. + +--- + +## 3. Architektur + +### 3.1 Monorepo-Integration + +``` +frontend/ +└── apps/ + └── e2e/ # Neues Workspace-Package + ├── package.json + ├── playwright.config.ts + ├── tests/ + │ ├── api/ # API-E2E Tests (kein Browser nötig) + │ │ ├── masterdata/ + │ │ │ ├── categories.spec.ts # aus TC-CAT + │ │ │ ├── suppliers.spec.ts # aus TC-SUP + │ │ │ ├── customers.spec.ts # aus TC-CUS + │ │ │ └── articles.spec.ts # aus TC-ART + │ │ ├── inventory/ + │ │ │ ├── stock.spec.ts + │ │ │ ├── movements.spec.ts + │ │ │ └── reservations.spec.ts + │ │ ├── production/ + │ │ │ ├── recipes.spec.ts + │ │ │ ├── batches.spec.ts + │ │ │ └── orders.spec.ts + │ │ └── auth/ + │ │ └── authorization.spec.ts # aus TC-AUTH + │ └── web/ # Browser-UI Tests (Web App) + │ └── .gitkeep # Platzhalter – wächst mit der Web-App + ├── fixtures/ + │ ├── auth.fixture.ts # Login-Helper (JWT) + │ └── seed.fixture.ts # Testdaten-Setup + └── helpers/ + └── api-client.ts # Typisierter API-Wrapper +``` + +### 3.2 Test-Ebenen + +``` +┌─────────────────────────────────────────────────────┐ +│ Phase 2: Web UI Tests (Browser) │ +│ Playwright + React – sobald Web-App ausgebaut │ +├─────────────────────────────────────────────────────┤ +│ Phase 1 (jetzt): API E2E Tests │ +│ Playwright request context → Spring Boot REST API │ +│ Direkte Ableitung aus Akzeptanzkriterien in Issues │ +├─────────────────────────────────────────────────────┤ +│ Bestehend: Unit + Integration Tests (Maven/vitest) │ +└─────────────────────────────────────────────────────┘ +``` + +**Phase 1** startet mit API-Level-Tests, da die Web-UI noch nicht ausgebaut ist. Diese Tests validieren denselben Scope wie die manuellen Testfälle, ohne einen Browser zu benötigen. + +--- + +## 4. Ticket → Test Mapping + +### 4.1 Struktur der Issues + +Die GitHub-Issues enthalten zwei Test-relevante Formate: + +**Format A – Feature Stories (US-Pxx / Story x.x):** +```markdown +## Akzeptanzkriterien +- [ ] POST `/api/production-orders` → 201, Status PLANNED +- [ ] PlannedDate gestern → 400 (PlannedDateInPast) +- [ ] PlannedQuantity 0 → 400 +``` +→ Direkt in API-Tests übersetzbar (HTTP-Verb, Endpoint, Expected Status Code) + +**Format B – Manuelle Testfälle (TC-xxx):** +```markdown +### TC-SUP-01: Lieferant erstellen – Pflichtfelder +1. Name: `Frisch AG`, Telefon: `+49 30 12345` → Enter +- [x] Erwartung: Lieferant erscheint in Liste, Status AKTIV +``` +→ Schritte + Erwartungen → Playwright `test()` Blöcke + +### 4.2 Mapping-Tabelle: Issues → Spec-Dateien + +| GitHub Issue | Label | Spec-Datei | Priorität | +|---|---|---|---| +| #62 TC-CAT | manual-testing | `api/masterdata/categories.spec.ts` | Hoch | +| #63 TC-SUP | manual-testing | `api/masterdata/suppliers.spec.ts` | Hoch | +| #65 TC-CUS | manual-testing | `api/masterdata/customers.spec.ts` | Hoch | +| #66 TC-B2B | manual-testing | `api/masterdata/contracts.spec.ts` | Mittel | +| #67 TC-AUTH | manual-testing | `api/auth/authorization.spec.ts` | Hoch | +| #64 TC-ART | manual-testing (offen) | `api/masterdata/articles.spec.ts` | Hoch | +| #38–#42 US-P13–P17 | epic:production-order | `api/production/orders.spec.ts` | Mittel | +| #33–#36 US-P09–P12 | epic:batch | `api/production/batches.spec.ts` | Mittel | +| #26–#32 US-P02–P08 | epic:recipe | `api/production/recipes.spec.ts` | Mittel | +| #43–#44 US-P18–P19 | epic:traceability | `api/production/traceability.spec.ts` | Mittel | +| #4–#20 Story 2.x–6.x | epic:stock/inventory | `api/inventory/*.spec.ts` | Mittel | + +### 4.3 Beispiel-Übersetzung + +**Issue #62, TC-CAT-01 → Playwright:** + +```typescript +// tests/api/masterdata/categories.spec.ts +import { test, expect } from '@playwright/test'; + +test.describe('TC-CAT: Produktkategorien', () => { + test('TC-CAT-01: Kategorie erstellen – Happy Path', async ({ request }) => { + const res = await request.post('/api/product-categories', { + data: { name: 'Obst & Gemüse', description: 'Frische Produkte' }, + }); + expect(res.status()).toBe(201); + const body = await res.json(); + expect(body.name).toBe('Obst & Gemüse'); + expect(body.description).toBe('Frische Produkte'); + }); + + test('TC-CAT-02: Kategorie erstellen – ohne Beschreibung', async ({ request }) => { + const res = await request.post('/api/product-categories', { + data: { name: 'Milchprodukte' }, + }); + expect(res.status()).toBe(201); + }); + + test('TC-CAT-04: Doppelter Name wird abgelehnt', async ({ request }) => { + await request.post('/api/product-categories', { data: { name: 'Duplikat-Test' } }); + const res = await request.post('/api/product-categories', { data: { name: 'Duplikat-Test' } }); + expect(res.status()).toBe(409); // oder 422 je nach Backend-Impl. + }); + + test('TC-CAT-06: Leerer Name wird abgelehnt', async ({ request }) => { + const res = await request.post('/api/product-categories', { data: { name: '' } }); + expect(res.status()).toBe(400); + }); +}); +``` + +--- + +## 5. Docker-Setup + +### 5.1 Image-Strategie + +Zwei Images: + +``` +docker-compose.e2e.yml +├── db – postgres:15-alpine (gleiche Config wie dev) +├── backend – effigenix-backend:test (mit test-Profile + Seed-Daten) +└── e2e-runner – effigenix-e2e:latest (Playwright + Tests) +``` + +### 5.2 Playwright Dockerfile + +```dockerfile +# e2e/Dockerfile +FROM mcr.microsoft.com/playwright:v1.51.0-noble + +WORKDIR /app + +# pnpm installieren +RUN npm install -g pnpm@9 + +# Workspace-Dependencies kopieren +COPY frontend/package.json frontend/pnpm-workspace.yaml ./ +COPY frontend/apps/e2e/package.json ./apps/e2e/ +# Andere packages die e2e braucht +COPY frontend/packages/types/package.json ./packages/types/ + +# Install +RUN pnpm install --frozen-lockfile + +# Test-Code kopieren +COPY frontend/apps/e2e/ ./apps/e2e/ +COPY frontend/packages/types/ ./packages/types/ + +WORKDIR /app/apps/e2e + +ENTRYPOINT ["pnpm", "exec", "playwright", "test"] +``` + +### 5.3 docker-compose.e2e.yml + +```yaml +version: '3.8' + +services: + db: + image: postgres:15-alpine + environment: + POSTGRES_DB: effigenix + POSTGRES_USER: effigenix + POSTGRES_PASSWORD: effigenix + healthcheck: + test: ["CMD-SHELL", "pg_isready -U effigenix"] + interval: 5s + timeout: 3s + retries: 10 + + backend: + build: + context: ./backend + dockerfile: Dockerfile + environment: + SPRING_PROFILES_ACTIVE: test + SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/effigenix + SPRING_DATASOURCE_USERNAME: effigenix + SPRING_DATASOURCE_PASSWORD: effigenix + depends_on: + db: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"] + interval: 10s + timeout: 5s + retries: 12 + ports: + - "8080:8080" + + e2e-runner: + build: + context: . + dockerfile: e2e/Dockerfile + environment: + BASE_URL: http://backend:8080 + TEST_USER_ADMIN: admin + TEST_USER_ADMIN_PASS: admin123 + TEST_USER_VIEWER: viewer + TEST_USER_VIEWER_PASS: viewer123 + depends_on: + backend: + condition: service_healthy + volumes: + - ./e2e-results:/app/apps/e2e/playwright-report + - ./e2e-results:/app/apps/e2e/test-results +``` + +### 5.4 Ausführung + +```bash +# Alle E2E-Tests lokal starten +docker compose -f docker-compose.e2e.yml up --abort-on-container-exit + +# Nur bestimmte Tests +docker compose -f docker-compose.e2e.yml run e2e-runner --grep "TC-SUP" + +# Report anzeigen (nach Test-Run) +pnpm exec playwright show-report e2e-results +``` + +--- + +## 6. Playwright-Konfiguration + +```typescript +// frontend/apps/e2e/playwright.config.ts +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 4 : undefined, + reporter: [ + ['html', { outputFolder: 'playwright-report' }], + ['junit', { outputFile: 'test-results/junit.xml' }], // für CI + ], + use: { + baseURL: process.env.BASE_URL ?? 'http://localhost:8080', + extraHTTPHeaders: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }, + projects: [ + { + name: 'api', + testMatch: 'tests/api/**/*.spec.ts', + // Kein Browser benötigt für API-Tests + }, + { + name: 'web-chromium', + testMatch: 'tests/web/**/*.spec.ts', + use: { browserName: 'chromium' }, + }, + ], +}); +``` + +--- + +## 7. Auth-Fixtures + +```typescript +// frontend/apps/e2e/fixtures/auth.fixture.ts +import { test as base, expect } from '@playwright/test'; + +type AuthFixtures = { + adminToken: string; + viewerToken: string; +}; + +export const test = base.extend({ + adminToken: async ({ request }, use) => { + const res = await request.post('/api/auth/login', { + data: { + username: process.env.TEST_USER_ADMIN ?? 'admin', + password: process.env.TEST_USER_ADMIN_PASS ?? 'admin123', + }, + }); + expect(res.status()).toBe(200); + const { token } = await res.json(); + await use(token); + }, + viewerToken: async ({ request }, use) => { + const res = await request.post('/api/auth/login', { + data: { + username: process.env.TEST_USER_VIEWER ?? 'viewer', + password: process.env.TEST_USER_VIEWER_PASS ?? 'viewer123', + }, + }); + expect(res.status()).toBe(200); + const { token } = await res.json(); + await use(token); + }, +}); + +export { expect }; +``` + +--- + +## 8. Test-Generierung aus Issues + +### 8.1 Workflow + +``` +GitHub Issue (body mit AC/TC) + │ + ▼ + gh issue view --json title,body + │ + ▼ + Claude API (claude-sonnet-4-6) + Prompt: "Übersetze diese Akzeptanzkriterien + in Playwright TypeScript Tests..." + │ + ▼ + Generierter Test-Stub → Review → Commit +``` + +### 8.2 Generierungs-Skript (Konzept) + +```typescript +// scripts/generate-tests-from-issue.ts +import { execSync } from 'child_process'; +import Anthropic from '@anthropic-ai/sdk'; +import fs from 'fs'; + +const issueNumber = process.argv[2]; +if (!issueNumber) throw new Error('Usage: tsx generate-tests-from-issue.ts '); + +// Issue-Body via gh CLI laden +const issue = JSON.parse( + execSync(`gh issue view ${issueNumber} --json title,body`).toString() +); + +const client = new Anthropic(); + +const prompt = ` +Du bist ein Senior QA Engineer. Übersetze die folgenden GitHub Issue-Inhalte +in Playwright TypeScript API-Tests (Playwright request context, kein Browser). + +Regeln: +- Verwende test.describe() mit dem Issue-Titel +- Jeden Testfall (TC-xxx oder Akzeptanzkriterium) als eigenständigen test() +- Auth via Bearer Token (Fixture: adminToken oder viewerToken) +- baseURL kommt aus Playwright-Config (nicht hardcoden) +- Nur den Test-Code ausgeben, kein Markdown-Wrapper + +Issue #${issueNumber}: ${issue.title} + +${issue.body} +`; + +const response = await client.messages.create({ + model: 'claude-sonnet-4-6', + max_tokens: 4096, + messages: [{ role: 'user', content: prompt }], +}); + +const code = response.content[0].type === 'text' ? response.content[0].text : ''; +const filename = `tests/api/generated/issue-${issueNumber}.spec.ts`; + +fs.mkdirSync('tests/api/generated', { recursive: true }); +fs.writeFileSync(filename, code); + +console.log(`✓ Test generiert: ${filename}`); +console.log(' → Bitte Review und manuelle Anpassung vor Commit!'); +``` + +### 8.3 Nutzung + +```bash +# Test für ein Issue generieren +cd frontend/apps/e2e +tsx ../../scripts/generate-tests-from-issue.ts 63 + +# Output: tests/api/generated/issue-63.spec.ts +# → Review → in tests/api/masterdata/suppliers.spec.ts einpflegen +``` + +### 8.4 Kandidaten für sofortige Generierung + +Folgende Issues enthalten vollständige, abgehakte Testfälle (alle `[x]`) und sind direkt verwertbar: + +| Issue | Testfälle | Status | +|---|---|---| +| #62 TC-CAT | 6 TCs | ✅ Alle abgenommen | +| #63 TC-SUP | 12 TCs | ✅ Alle abgenommen | +| #65 TC-CUS | Kunden-CRUD | ✅ | +| #66 TC-B2B | Rahmenverträge | ✅ | +| #38 US-P13 | 3 ACs | ✅ | +| #39–#42 US-P14–P17 | je 2–4 ACs | ✅ | + +--- + +## 9. TUI-Testing (Terminal UI) + +### 9.1 Machbarkeit + +**Ja, TUI-Testing ist möglich und bereits vorbereitet.** + +`ink-testing-library` ist bereits im `@effigenix/cli`-Package als `devDependency` installiert und wird in 4 bestehenden Tests genutzt (z.B. `ConfirmDialog.test.tsx`). + +Das Pattern ist: +```typescript +import { render } from 'ink-testing-library'; +const { lastFrame, stdin } = render(); +``` + +`lastFrame()` gibt die aktuelle Terminal-Ausgabe als String zurück. `stdin` ermöglicht simulierte Tastatureingaben. + +### 9.2 Was testbar ist + +| Art | Testbar | Methode | +|---|---|---| +| Render-Output (Text, Farben) | ✅ | `lastFrame()` | +| Tastaturnavigation (`↑↓`, Enter, `n`, `e`) | ✅ | `stdin.write(...)` | +| Zustandsübergänge (Formular → Liste) | ✅ | Async `lastFrame()` nach Input | +| API-Calls (echte HTTP) | ⚠️ | Erfordert Mock via `vi.mock()` | +| Vollständiger E2E-Flow mit echtem Backend | ❌ | Nicht sinnvoll (Domäne von Playwright-API-Tests) | + +### 9.3 Teststruktur für TUI + +``` +frontend/apps/cli/src/__tests__/ +├── shared/ # Bestehend +│ ├── ConfirmDialog.test.tsx +│ ├── ErrorDisplay.test.tsx +│ └── SuccessDisplay.test.tsx +├── hooks/ # Bestehend +│ └── useRoles.test.ts +└── screens/ # Neu – aus TC-xxx Issues ableiten + ├── masterdata/ + │ ├── SupplierList.test.tsx # aus TC-SUP-06 (Filter) + │ ├── SupplierForm.test.tsx # aus TC-SUP-01/02/03 (Formular) + │ └── CategoryForm.test.tsx # aus TC-CAT-01/06 (Validierung) + └── production/ + └── RecipeForm.test.tsx +``` + +### 9.4 Beispiel: TC-SUP-03 als TUI-Test + +```typescript +// __tests__/screens/masterdata/SupplierForm.test.tsx +import { render } from 'ink-testing-library'; +import { vi, describe, it, expect } from 'vitest'; +import React from 'react'; +import { SupplierCreateForm } from '../../../components/masterdata/SupplierCreateForm.js'; + +vi.mock('@effigenix/api-client', () => ({ + suppliersApi: { + create: vi.fn().mockResolvedValue({ status: 201, data: { id: '1', name: 'Frisch AG' } }), + }, +})); + +describe('TC-SUP: Lieferanten-Formular', () => { + it('TC-SUP-03: Leerer Name → kein API-Call', async () => { + const onSuccess = vi.fn(); + const { stdin, lastFrame } = render( + React.createElement(SupplierCreateForm, { onSuccess }) + ); + + // Enter ohne Name + stdin.write('\r'); + await new Promise(r => setTimeout(r, 50)); + + expect(lastFrame()).toContain('Pflichtfeld'); + expect(onSuccess).not.toHaveBeenCalled(); + }); + + it('TC-SUP-01: Pflichtfelder ausgefüllt → Lieferant wird angelegt', async () => { + const onSuccess = vi.fn(); + const { stdin, lastFrame } = render( + React.createElement(SupplierCreateForm, { onSuccess }) + ); + + // Name eingeben + stdin.write('Frisch AG\r'); + // Telefon eingeben + stdin.write('+49 30 12345\r'); + // Speichern + stdin.write('\r'); + await new Promise(r => setTimeout(r, 100)); + + expect(onSuccess).toHaveBeenCalled(); + }); +}); +``` + +### 9.5 Abgrenzung TUI-Tests vs. API-Tests + +``` +TUI-Tests (vitest + ink-testing-library) + → "Rendert der Screen korrekt?" + → "Werden Validierungsfehler angezeigt?" + → "Reagiert Tastatur-Navigation richtig?" + → API-Calls werden gemockt + +API E2E-Tests (Playwright) + → "Funktioniert das Backend korrekt?" + → "Werden alle Akzeptanzkriterien aus dem Ticket erfüllt?" + → Kein UI-Rendering +``` + +Beide Ebenen ergänzen sich: TUI-Tests sichern das Verhalten der UI-Komponenten, API-Tests sichern den Backend-Vertrag. + +--- + +## 10. Umsetzungsplan (Phasen) + +### Phase 0 – TUI-Tests ausbauen (sofort, ohne neues Setup) + +- [ ] `__tests__/screens/` Verzeichnis anlegen +- [ ] Formular-Tests für `SupplierCreateForm` (TC-SUP-01/02/03) +- [ ] Formular-Tests für `CategoryForm` (TC-CAT-01/04/06) +- [ ] Filter-Tests für Listen-Screens (TC-SUP-06) +- [ ] Bestehende 4 Tests als Vorlage nutzen + +### Phase 1 – API E2E Grundgerüst + +- [ ] `frontend/apps/e2e` Workspace-Package anlegen +- [ ] `playwright.config.ts` einrichten (API-Projekt) +- [ ] Auth-Fixture implementieren +- [ ] `docker-compose.e2e.yml` erstellen +- [ ] Backend `Dockerfile` (test-Profile, Seed-Daten) +- [ ] Erste Spec: `api/masterdata/categories.spec.ts` (TC-CAT, Issue #62) +- [ ] Erste Spec: `api/masterdata/suppliers.spec.ts` (TC-SUP, Issue #63) +- [ ] `just test-e2e` Recipe in `justfile` ergänzen + +### Phase 2 – Vollständige API-Coverage + +- [ ] Alle `manual-testing`-Issues in Specs übersetzen (#62–#67) +- [ ] Production BC Specs aus US-P13–P19 (#38–#44) +- [ ] Inventory BC Specs aus Story 2.x–6.x (#4–#20) +- [ ] Auth/Authorization Spec (TC-AUTH, #67) +- [ ] Generierungs-Skript finalisieren und in `justfile` integrieren + +### Phase 3 – CI/CD Integration + +- [ ] `.github/workflows/e2e.yml` erstellen +- [ ] Trigger: auf `main`-Push und PRs gegen `main` +- [ ] JUnit-Report als CI-Artefakt +- [ ] Playwright HTML-Report als GitHub Pages (optional) + +### Phase 4 – Web UI Tests (wenn App ausgebaut) + +- [ ] Browser-Projekt in `playwright.config.ts` aktivieren +- [ ] Page Object Models für die Web-App-Seiten +- [ ] Visuelle Regression (optional: Playwright screenshots) + +--- + +## 10. Offene Punkte & Entscheidungen + +| Punkt | Status | Anmerkung | +|---|---|---| +| Backend `Dockerfile` | Fehlt noch | Nötig für E2E-Docker-Setup | +| Seed-Testdaten Isolation | Offen | Aktuell globale Seed-DB; für E2E per Test isolieren oder DB-Reset vor Suite | +| `read:project` Scope für `gh` | Token fehlt Scope | Für Projektstatus-Abfrage (welche Issues in "Test") nötig; `gh auth refresh -s read:project` | +| TUI-Testing | Out of scope | Ink-TUI-Testing via `ink-testing-library` ist möglich, aber separates Konzept | +| Scanner (Tauri/mobil) | Out of scope | Appium oder Tauri-eigene Test-Tools; separates Konzept | diff --git a/test-automation/tui/README.md b/test-automation/tui/README.md new file mode 100644 index 0000000..5ddd41d --- /dev/null +++ b/test-automation/tui/README.md @@ -0,0 +1,51 @@ +# TUI-Tests – Terminal UI + +TUI-Tests für `apps/cli` (Ink + React) laufen **nicht** in diesem Ordner, sondern direkt im CLI-Paket: + +``` +frontend/apps/cli/src/__tests__/ +├── shared/ # Bestehend: ConfirmDialog, ErrorDisplay, SuccessDisplay +├── hooks/ # Bestehend: useRoles +└── screens/ # Phase 0 – wird hier ausgebaut + ├── masterdata/ + │ ├── SupplierForm.test.tsx + │ ├── SupplierList.test.tsx + │ └── CategoryForm.test.tsx + └── production/ + └── RecipeForm.test.tsx +``` + +## Warum nicht hier? + +TUI-Tests nutzen `vitest` + `ink-testing-library` und sind eng am Quellcode der CLI-App. +Sie gehören zum CLI-Paket (`@effigenix/cli`) und laufen mit dem bestehenden Vitest-Setup. +Ein separates Package wäre unnötiger Overhead. + +## Tests ausführen + +```bash +# Alle TUI-Tests +pnpm --filter @effigenix/cli test + +# Mit Watch +pnpm --filter @effigenix/cli test --watch + +# Einzelne Spec +pnpm --filter @effigenix/cli test SupplierForm +``` + +## Abgrenzung + +| TUI-Tests | API E2E-Tests (Playwright) | +|---|---| +| "Rendert der Screen korrekt?" | "Funktioniert das Backend?" | +| Validierungsfehler sichtbar? | Akzeptanzkriterien aus Issues | +| Tastatur-Navigation korrekt? | Kein UI-Rendering | +| API-Calls via `vi.mock()` | Echtes Backend via Docker | + +Details: [`../docs/ui-testing-automation.md`](../docs/ui-testing-automation.md) Abschnitt 9. + +## Zukünftig: Scanner / Tauri + +Sollte Tauri-Testing (Appium o.ä.) aufgenommen werden, käme ein `scanner/`-Ordner +auf derselben Ebene wie `web-ui/` und `tui/` hinzu. diff --git a/test-automation/web-ui/Dockerfile b/test-automation/web-ui/Dockerfile new file mode 100644 index 0000000..f767bf8 --- /dev/null +++ b/test-automation/web-ui/Dockerfile @@ -0,0 +1,20 @@ +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"] diff --git a/test-automation/web-ui/fixtures/auth.fixture.ts b/test-automation/web-ui/fixtures/auth.fixture.ts new file mode 100644 index 0000000..797fac1 --- /dev/null +++ b/test-automation/web-ui/fixtures/auth.fixture.ts @@ -0,0 +1,34 @@ +import { test as base, expect } from '@playwright/test'; + +type AuthFixtures = { + adminToken: string; + viewerToken: string; +}; + +export const test = base.extend({ + adminToken: async ({ request }, use) => { + const res = await request.post('/api/auth/login', { + data: { + username: process.env.TEST_USER_ADMIN ?? 'admin', + password: process.env.TEST_USER_ADMIN_PASS ?? 'admin123', + }, + }); + expect(res.status()).toBe(200); + const { token } = await res.json(); + await use(token); + }, + + viewerToken: async ({ request }, use) => { + const res = await request.post('/api/auth/login', { + data: { + username: process.env.TEST_USER_VIEWER ?? 'viewer', + password: process.env.TEST_USER_VIEWER_PASS ?? 'viewer123', + }, + }); + expect(res.status()).toBe(200); + const { token } = await res.json(); + await use(token); + }, +}); + +export { expect }; diff --git a/test-automation/web-ui/fixtures/seed.fixture.ts b/test-automation/web-ui/fixtures/seed.fixture.ts new file mode 100644 index 0000000..58a62a3 --- /dev/null +++ b/test-automation/web-ui/fixtures/seed.fixture.ts @@ -0,0 +1,29 @@ +import { test as base } from '@playwright/test'; +import { ApiClient } from '../helpers/api-client.js'; + +type SeedFixtures = { + apiClient: ApiClient; +}; + +/** + * Seed-Fixture: stellt einen authentifizierten ApiClient bereit. + * + * Strategie (zu klären in Phase 1): + * Option A – DB-Reset vor jeder Suite via Spring Boot test-Profile + Liquibase + * Option B – Test-Daten mit zufälligen Namen (UUID-Suffix) zur Isolation + * + * Aktuell: Option B als pragmatischer Einstieg. + */ +export const test = base.extend({ + apiClient: async ({ request }, use) => { + const res = await request.post('/api/auth/login', { + data: { + username: process.env.TEST_USER_ADMIN ?? 'admin', + password: process.env.TEST_USER_ADMIN_PASS ?? 'admin123', + }, + }); + const { token } = await res.json(); + const client = new ApiClient(request, token); + await use(client); + }, +}); diff --git a/test-automation/web-ui/helpers/api-client.ts b/test-automation/web-ui/helpers/api-client.ts new file mode 100644 index 0000000..ee25899 --- /dev/null +++ b/test-automation/web-ui/helpers/api-client.ts @@ -0,0 +1,45 @@ +import type { APIRequestContext, APIResponse } from '@playwright/test'; + +/** + * Typisierter API-Wrapper für Playwright-Tests. + * Ergänzt den raw request-Context um Auth-Header und JSON-Defaults. + */ +export class ApiClient { + constructor( + private readonly request: APIRequestContext, + private readonly token: string, + ) {} + + private get authHeaders() { + return { Authorization: `Bearer ${this.token}` }; + } + + async get(path: string): Promise { + return this.request.get(path, { headers: this.authHeaders }); + } + + async post(path: string, body: unknown): Promise { + return this.request.post(path, { + data: body, + headers: this.authHeaders, + }); + } + + async put(path: string, body: unknown): Promise { + return this.request.put(path, { + data: body, + headers: this.authHeaders, + }); + } + + async patch(path: string, body: unknown): Promise { + return this.request.patch(path, { + data: body, + headers: this.authHeaders, + }); + } + + async delete(path: string): Promise { + return this.request.delete(path, { headers: this.authHeaders }); + } +} diff --git a/test-automation/web-ui/package.json b/test-automation/web-ui/package.json new file mode 100644 index 0000000..5f884a6 --- /dev/null +++ b/test-automation/web-ui/package.json @@ -0,0 +1,17 @@ +{ + "name": "@effigenix/e2e", + "version": "0.1.0", + "private": true, + "description": "Playwright E2E-Tests für Effigenix ERP (Web UI + API)", + "scripts": { + "test": "playwright test", + "test:api": "playwright test --project=api", + "test:web": "playwright test --project=web-chromium", + "report": "playwright show-report playwright-report" + }, + "devDependencies": { + "@playwright/test": "^1.51.0", + "@types/node": "^20.0.0", + "typescript": "^5.4.0" + } +} diff --git a/test-automation/web-ui/playwright.config.ts b/test-automation/web-ui/playwright.config.ts new file mode 100644 index 0000000..a7ffe88 --- /dev/null +++ b/test-automation/web-ui/playwright.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 4 : undefined, + reporter: [ + ['html', { outputFolder: 'playwright-report' }], + ['junit', { outputFile: 'test-results/junit.xml' }], + ], + use: { + baseURL: process.env.BASE_URL ?? 'http://localhost:8080', + extraHTTPHeaders: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }, + projects: [ + { + name: 'api', + testMatch: 'tests/api/**/*.spec.ts', + // Kein Browser nötig – reiner API-Test via request context + }, + { + name: 'web-chromium', + testMatch: 'tests/web/**/*.spec.ts', + use: { browserName: 'chromium' }, + }, + ], +}); diff --git a/test-automation/web-ui/tests/api/auth/authorization.spec.ts b/test-automation/web-ui/tests/api/auth/authorization.spec.ts new file mode 100644 index 0000000..07a76fd --- /dev/null +++ b/test-automation/web-ui/tests/api/auth/authorization.spec.ts @@ -0,0 +1,30 @@ +import { test, expect } from '../../../fixtures/auth.fixture.js'; + +/** + * TC-AUTH – Autorisierung Masterdata + * Quelle: GitHub Issue #67 + */ +test.describe('TC-AUTH: Autorisierung', () => { + test('TC-AUTH-01: Unauthentifizierter Zugriff wird abgelehnt', async ({ request }) => { + const res = await request.get('/api/suppliers'); + expect([401, 403]).toContain(res.status()); + }); + + test('TC-AUTH-02: Admin darf Lieferant erstellen', async ({ request, adminToken }) => { + const res = await request.post('/api/suppliers', { + data: { name: `Auth-Test-${Date.now()}`, phone: '+49 30 00000' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(201); + }); + + test('TC-AUTH-03: Viewer darf keine Lieferanten erstellen', async ({ request, viewerToken }) => { + const res = await request.post('/api/suppliers', { + data: { name: `Viewer-Test-${Date.now()}`, phone: '+49 30 00001' }, + headers: { Authorization: `Bearer ${viewerToken}` }, + }); + expect(res.status()).toBe(403); + }); + + // TODO: Weitere ACs aus Issue #67 ergänzen +}); diff --git a/test-automation/web-ui/tests/api/masterdata/categories.spec.ts b/test-automation/web-ui/tests/api/masterdata/categories.spec.ts new file mode 100644 index 0000000..d5acf93 --- /dev/null +++ b/test-automation/web-ui/tests/api/masterdata/categories.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '../../../fixtures/auth.fixture.js'; + +/** + * TC-CAT – Produktkategorien + * Quelle: GitHub Issue #62 + */ +test.describe('TC-CAT: Produktkategorien', () => { + test('TC-CAT-01: Kategorie erstellen – Happy Path', async ({ request, adminToken }) => { + const res = await request.post('/api/product-categories', { + data: { name: 'Obst & Gemüse', description: 'Frische Produkte' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(201); + const body = await res.json(); + expect(body.name).toBe('Obst & Gemüse'); + expect(body.description).toBe('Frische Produkte'); + }); + + test('TC-CAT-02: Kategorie erstellen – ohne Beschreibung', async ({ request, adminToken }) => { + const res = await request.post('/api/product-categories', { + data: { name: `Milchprodukte-${Date.now()}` }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(201); + }); + + test('TC-CAT-04: Doppelter Name wird abgelehnt', async ({ request, adminToken }) => { + const name = `Duplikat-${Date.now()}`; + await request.post('/api/product-categories', { + data: { name }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + const res = await request.post('/api/product-categories', { + data: { name }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect([409, 422]).toContain(res.status()); + }); + + test('TC-CAT-06: Leerer Name wird abgelehnt', async ({ request, adminToken }) => { + const res = await request.post('/api/product-categories', { + data: { name: '' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(400); + }); +}); diff --git a/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts new file mode 100644 index 0000000..6a224c7 --- /dev/null +++ b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '../../../fixtures/auth.fixture.js'; + +/** + * TC-SUP – Lieferanten + * Quelle: GitHub Issue #63 + */ +test.describe('TC-SUP: Lieferanten', () => { + test('TC-SUP-01: Lieferant erstellen – Pflichtfelder', async ({ request, adminToken }) => { + const res = await request.post('/api/suppliers', { + data: { name: `Frisch AG ${Date.now()}`, phone: '+49 30 12345' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(201); + const body = await res.json(); + expect(body.status).toBe('AKTIV'); + }); + + test('TC-SUP-02: Lieferant erscheint in Liste nach Erstellung', async ({ request, adminToken }) => { + const name = `ListTest-${Date.now()}`; + await request.post('/api/suppliers', { + data: { name, phone: '+49 30 99999' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + const res = await request.get('/api/suppliers', { + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(200); + const body = await res.json(); + const found = (Array.isArray(body) ? body : body.content ?? []).some( + (s: { name: string }) => s.name === name, + ); + expect(found).toBe(true); + }); + + test('TC-SUP-03: Lieferant ohne Name wird abgelehnt', async ({ request, adminToken }) => { + const res = await request.post('/api/suppliers', { + data: { phone: '+49 30 12345' }, + headers: { Authorization: `Bearer ${adminToken}` }, + }); + expect(res.status()).toBe(400); + }); + + // TODO: Weitere TCs aus Issue #63 nach Implementierung hinzufügen + // TC-SUP-04: Doppelter Name abgelehnt + // TC-SUP-05: Lieferant deaktivieren + // TC-SUP-06: Filter nach Name +}); diff --git a/test-automation/web-ui/tests/web/.gitkeep b/test-automation/web-ui/tests/web/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test-automation/web-ui/tsconfig.json b/test-automation/web-ui/tsconfig.json new file mode 100644 index 0000000..47ddf1b --- /dev/null +++ b/test-automation/web-ui/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist" + }, + "include": ["tests/**/*.ts", "fixtures/**/*.ts", "helpers/**/*.ts", "playwright.config.ts"] +}