diff --git a/admin-compliance/e2e/specs/document-generator.spec.ts b/admin-compliance/e2e/specs/document-generator.spec.ts new file mode 100644 index 0000000..7c8c830 --- /dev/null +++ b/admin-compliance/e2e/specs/document-generator.spec.ts @@ -0,0 +1,83 @@ +/** + * Document Generator E2E Test + * + * Prueft: Template-Library, Empfehlungen, Kategorie-Filter, Template-Auswahl + */ + +import { test, expect } from '@playwright/test' + +const BASE = process.env.PLAYWRIGHT_BASE_URL || 'https://macmini:3007' + +test.describe('Document Generator', () => { + test('Template Library loads with templates', async ({ page }) => { + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + + // Wait for templates to load + await page.waitForTimeout(2000) + + // Check that template count is shown + const body = await page.textContent('body') + expect(body).toContain('Vorlagen gesamt') + + await page.screenshot({ path: 'e2e/test-results/generator-library.png', fullPage: true }) + }) + + test('Category filter works', async ({ page }) => { + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + await page.waitForTimeout(2000) + + // Click on "Datenschutz" category if it exists + const datenschutzButton = page.locator('button', { hasText: 'Datenschutz' }) + if (await datenschutzButton.isVisible()) { + await datenschutzButton.click() + await page.waitForTimeout(500) + await page.screenshot({ path: 'e2e/test-results/generator-filter-datenschutz.png' }) + } + + // Click "Alle" to reset + const alleButton = page.locator('button', { hasText: 'Alle' }) + if (await alleButton.isVisible()) { + await alleButton.click() + await page.waitForTimeout(500) + } + }) + + test('Recommendation section visible when scope is set', async ({ page }) => { + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + await page.waitForTimeout(2000) + + // Check for recommendation section (may or may not be visible depending on scope state) + const recSection = page.locator('text=Empfohlene Dokumente') + const isVisible = await recSection.isVisible().catch(() => false) + + if (isVisible) { + await page.screenshot({ path: 'e2e/test-results/generator-recommendations.png' }) + + // Check for Pflicht/Empfohlen sections + const pflicht = page.locator('text=Pflicht') + expect(await pflicht.isVisible()).toBeTruthy() + } + }) + + test('New template categories are present', async ({ page }) => { + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + await page.waitForTimeout(2000) + + const body = await page.textContent('body') + + // Check that new categories exist + const expectedCategories = ['TOM', 'Whistleblower', 'HR-Datenschutz', 'Drittlandtransfer'] + for (const cat of expectedCategories) { + const button = page.locator('button', { hasText: cat }) + if (await button.isVisible()) { + await button.click() + await page.waitForTimeout(300) + await page.screenshot({ path: `e2e/test-results/generator-category-${cat.toLowerCase().replace(/[^a-z]/g, '')}.png` }) + } + } + }) +}) diff --git a/admin-compliance/e2e/specs/isms-assets.spec.ts b/admin-compliance/e2e/specs/isms-assets.spec.ts new file mode 100644 index 0000000..f70aff0 --- /dev/null +++ b/admin-compliance/e2e/specs/isms-assets.spec.ts @@ -0,0 +1,64 @@ +/** + * ISMS Asset Register E2E Test + * + * Prueft: Assets-Tab, CRUD, Filter, CSV-Export + */ + +import { test, expect } from '@playwright/test' + +const BASE = process.env.PLAYWRIGHT_BASE_URL || 'https://macmini:3007' + +test.describe('ISMS — Asset Register', () => { + test('ISMS page loads with Assets tab', async ({ page }) => { + await page.goto(`${BASE}/sdk/isms`) + await page.waitForLoadState('networkidle') + + // Check that Assets tab exists + const assetsTab = page.locator('button', { hasText: 'Assets' }) + expect(await assetsTab.isVisible()).toBeTruthy() + + await page.screenshot({ path: 'e2e/test-results/isms-overview.png' }) + }) + + test('Assets tab shows empty state', async ({ page }) => { + await page.goto(`${BASE}/sdk/isms`) + await page.waitForLoadState('networkidle') + + // Click Assets tab + const assetsTab = page.locator('button', { hasText: 'Assets' }) + await assetsTab.click() + await page.waitForTimeout(500) + + // Check for empty state or asset table + const body = await page.textContent('body') + const hasAssets = body?.includes('Gesamt') || false + + await page.screenshot({ path: 'e2e/test-results/isms-assets-tab.png' }) + expect(hasAssets).toBeTruthy() + }) + + test('Add asset form is accessible', async ({ page }) => { + await page.goto(`${BASE}/sdk/isms`) + await page.waitForLoadState('networkidle') + + // Click Assets tab + const assetsTab = page.locator('button', { hasText: 'Assets' }) + await assetsTab.click() + await page.waitForTimeout(500) + + // Click "Asset hinzufuegen" button + const addButton = page.locator('button', { hasText: 'Asset hinzufuegen' }) + if (await addButton.isVisible()) { + await addButton.click() + await page.waitForTimeout(300) + + // Check form fields are visible + const body = await page.textContent('body') + expect(body).toContain('Name') + expect(body).toContain('Kategorie') + expect(body).toContain('Schutzbedarf') + + await page.screenshot({ path: 'e2e/test-results/isms-assets-form.png' }) + } + }) +}) diff --git a/admin-compliance/e2e/specs/scope-profiling.spec.ts b/admin-compliance/e2e/specs/scope-profiling.spec.ts new file mode 100644 index 0000000..39996d5 --- /dev/null +++ b/admin-compliance/e2e/specs/scope-profiling.spec.ts @@ -0,0 +1,103 @@ +/** + * Scope Profiling Test — Three Customer Profiles + * + * Legt drei fiktive Kundenprofile an die NICHT geloescht werden: + * - TechStart GmbH (Startup, L1) + * - MittelstandHandel AG (KMU, L2) + * - FinanzKonzern SE (Enterprise, L4) + * + * WICHTIG: Testdaten werden NICHT aufgeraeumt (User will nachvollziehen). + */ + +import { test, expect } from '@playwright/test' + +const BASE = process.env.PLAYWRIGHT_BASE_URL || 'https://macmini:3007' + +test.describe('Scope Profiling — Customer Profiles', () => { + test.describe.configure({ mode: 'serial' }) + + test('Szenario A: TechStart GmbH — Startup (L1)', async ({ page }) => { + // Navigate to company profile + await page.goto(`${BASE}/sdk/company-profile`) + await page.waitForLoadState('networkidle') + + // Take screenshot for documentation + await page.screenshot({ path: 'e2e/test-results/profile-techstart-start.png' }) + + // Navigate to compliance scope + await page.goto(`${BASE}/sdk/compliance-scope`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/scope-techstart.png' }) + + // Navigate to document generator to check recommendations + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/generator-techstart.png' }) + + // Verify page loads without errors + const body = await page.textContent('body') + expect(body).not.toContain('Application error') + }) + + test('Szenario B: MittelstandHandel AG — KMU (L2)', async ({ page }) => { + await page.goto(`${BASE}/sdk/company-profile`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/profile-mittelstand-start.png' }) + + await page.goto(`${BASE}/sdk/compliance-scope`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/scope-mittelstand.png' }) + + // Check vendor transfers tab + await page.goto(`${BASE}/sdk/vendor-compliance/transfers`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/transfers-mittelstand.png' }) + + // Check document generator + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/generator-mittelstand.png' }) + + const body = await page.textContent('body') + expect(body).not.toContain('Application error') + }) + + test('Szenario C: FinanzKonzern SE — Enterprise (L4)', async ({ page }) => { + await page.goto(`${BASE}/sdk/company-profile`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/profile-finanzkonzern-start.png' }) + + await page.goto(`${BASE}/sdk/compliance-scope`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/scope-finanzkonzern.png' }) + + // Check ISMS with assets + await page.goto(`${BASE}/sdk/isms`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/isms-finanzkonzern.png' }) + + // Check whistleblower (Pflicht ab 50 MA) + await page.goto(`${BASE}/sdk/whistleblower`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/whistleblower-finanzkonzern.png' }) + + // Check document generator + await page.goto(`${BASE}/sdk/document-generator`) + await page.waitForLoadState('networkidle') + + await page.screenshot({ path: 'e2e/test-results/generator-finanzkonzern.png' }) + + const body = await page.textContent('body') + expect(body).not.toContain('Application error') + }) +}) diff --git a/admin-compliance/e2e/specs/sdk-module-reachability.spec.ts b/admin-compliance/e2e/specs/sdk-module-reachability.spec.ts new file mode 100644 index 0000000..02aa2c9 --- /dev/null +++ b/admin-compliance/e2e/specs/sdk-module-reachability.spec.ts @@ -0,0 +1,91 @@ +/** + * SDK Module Reachability Test + * + * Prueft dass alle SDK-Module erreichbar sind (kein 404, kein Crash). + * Schnellster Test — findet kaputte Seiten sofort. + */ + +import { test, expect } from '@playwright/test' + +const BASE = process.env.PLAYWRIGHT_BASE_URL || 'https://macmini:3007' + +// All SDK module routes to test +const SDK_ROUTES = [ + // Phase 1: Vorbereitung + '/sdk/company-profile', + '/sdk/compliance-scope', + '/sdk/advisory-board', + '/sdk/screening', + '/sdk/source-policy', + + // Phase 2: Analyse + '/sdk/requirements', + '/sdk/controls', + '/sdk/evidence', + '/sdk/risks', + '/sdk/ai-act', + '/sdk/audit-checklist', + '/sdk/audit-report', + + // Phase 3: Dokumentation + '/sdk/obligations', + '/sdk/dsfa', + '/sdk/tom', + '/sdk/loeschfristen', + '/sdk/vvt', + + // Phase 4: Rechtliche Texte + '/sdk/einwilligungen', + '/sdk/consent', + '/sdk/cookie-banner', + '/sdk/document-generator', + '/sdk/workflow', + + // Phase 5: Betrieb + '/sdk/dsr', + '/sdk/escalations', + '/sdk/vendor-compliance', + '/sdk/vendor-compliance/transfers', + '/sdk/consent-management', + '/sdk/email-templates', + '/sdk/notfallplan', + '/sdk/incidents', + '/sdk/whistleblower', + '/sdk/academy', + '/sdk/training', + '/sdk/control-library', + + // Zusatzmodule + '/sdk/isms', + '/sdk/iace', + '/sdk/agent', + '/sdk/rag', + '/sdk/quality', + '/sdk/security-backlog', + '/sdk/reporting', + '/sdk/tom-generator', +] + +test.describe('SDK Module Reachability', () => { + for (const route of SDK_ROUTES) { + test(`${route} is reachable`, async ({ page }) => { + const response = await page.goto(`${BASE}${route}`, { + waitUntil: 'domcontentloaded', + timeout: 15000, + }) + + // Page should load successfully (not 404 or 500) + expect(response?.status()).toBeLessThan(400) + + // No error text in the page + const bodyText = await page.textContent('body') + expect(bodyText).not.toContain('404') + expect(bodyText).not.toContain('Application error') + expect(bodyText).not.toContain('Internal Server Error') + + // Page should have some content (not blank) + const contentLength = bodyText?.length || 0 + expect(contentLength).toBeGreaterThan(100) + }) + } +}) diff --git a/admin-compliance/e2e/specs/vendor-transfers.spec.ts b/admin-compliance/e2e/specs/vendor-transfers.spec.ts new file mode 100644 index 0000000..7062c54 --- /dev/null +++ b/admin-compliance/e2e/specs/vendor-transfers.spec.ts @@ -0,0 +1,66 @@ +/** + * Vendor Compliance — Transfers Tab E2E Test + * + * Prueft: Drittlandtransfer-Tab, Erklaerungen, Adequacy-Liste + */ + +import { test, expect } from '@playwright/test' + +const BASE = process.env.PLAYWRIGHT_BASE_URL || 'https://macmini:3007' + +test.describe('Vendor Compliance — Transfers', () => { + test('Transfers tab is accessible', async ({ page }) => { + await page.goto(`${BASE}/sdk/vendor-compliance/transfers`) + await page.waitForLoadState('networkidle') + + // Page should show transfer heading + const body = await page.textContent('body') + expect(body).toContain('Drittlandtransfers') + + await page.screenshot({ path: 'e2e/test-results/transfers-tab.png', fullPage: true }) + }) + + test('Explanation section is visible', async ({ page }) => { + await page.goto(`${BASE}/sdk/vendor-compliance/transfers`) + await page.waitForLoadState('networkidle') + + // Check for the three explanation cards + const body = await page.textContent('body') + expect(body).toContain('Was muss ich tun') + expect(body).toContain('Angemessenheitsbeschluss') + expect(body).toContain('DPF-Zertifizierung') + expect(body).toContain('SCC + TIA') + + await page.screenshot({ path: 'e2e/test-results/transfers-explanations.png' }) + }) + + test('Adequacy countries list is expandable', async ({ page }) => { + await page.goto(`${BASE}/sdk/vendor-compliance/transfers`) + await page.waitForLoadState('networkidle') + + // Click on the details summary to expand + const summary = page.locator('summary', { hasText: 'Angemessenheitsbeschluss' }) + if (await summary.isVisible()) { + await summary.click() + await page.waitForTimeout(300) + + // Check for country names + const body = await page.textContent('body') + expect(body).toContain('Schweiz') + expect(body).toContain('Japan') + expect(body).toContain('Vereinigte Staaten') + + await page.screenshot({ path: 'e2e/test-results/transfers-adequacy-list.png', fullPage: true }) + } + }) + + test('Schrems II info box is present', async ({ page }) => { + await page.goto(`${BASE}/sdk/vendor-compliance/transfers`) + await page.waitForLoadState('networkidle') + + const body = await page.textContent('body') + expect(body).toContain('Schrems II') + + await page.screenshot({ path: 'e2e/test-results/transfers-schrems.png' }) + }) +})