feat: Cookie-Banner ↔ Backend Integration (DSR, Retention, Consent Proof)
Phase 1: Vendor sync from service registry (82+ services → banner vendors) Phase 2: Category-based retention (marketing=90d, statistics=790d, not hardcoded 365d) Phase 3: DSR ↔ Banner email linking (link-email, by-email, Art.17 erasure, Art.15/20 export) Phase 4: Consent sync (Banner → Einwilligungen bridge) Phase 6: Consent proof (SHA256 config hash + config_version in audit log, Art. 7(1) DSGVO) New files: - banner_dsr_service.py — email linking + DSR integration - vendor_banner_sync.py — service registry → vendor configs - migration 106 — linked_email, banner_config_hash, consent_version columns Tests: 20+ new backend tests + 2 Playwright E2E test suites (API + UI) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
import { navigateToSDK, waitForPageLoad } from '../utils/test-helpers'
|
||||
|
||||
/**
|
||||
* Cookie Banner UI E2E Tests
|
||||
*
|
||||
* Tests the cookie banner configuration page and admin UI.
|
||||
* Verifies that the banner builder, category management,
|
||||
* and code export work correctly.
|
||||
*/
|
||||
|
||||
test.describe('Cookie Banner Configuration Page', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await navigateToSDK(page, '/cookie-banner')
|
||||
})
|
||||
|
||||
test('should load cookie banner page', async ({ page }) => {
|
||||
// The page should load with the step header
|
||||
await expect(page.getByText('Cookie-Banner')).toBeVisible({ timeout: 10000 })
|
||||
})
|
||||
|
||||
test('should display category cards', async ({ page }) => {
|
||||
// Wait for content to load
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Check for standard cookie categories
|
||||
const pageContent = await page.textContent('body')
|
||||
expect(pageContent).toBeTruthy()
|
||||
|
||||
// At minimum the "Notwendig" category should exist
|
||||
const hasCategories = pageContent?.includes('Notwendig') ||
|
||||
pageContent?.includes('necessary') ||
|
||||
pageContent?.includes('Kategorie')
|
||||
expect(hasCategories).toBeTruthy()
|
||||
})
|
||||
|
||||
test('should have banner preview section', async ({ page }) => {
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Check for preview or banner-related UI elements
|
||||
const hasPreview = await page.locator('text=Vorschau').isVisible().catch(() => false) ||
|
||||
await page.locator('text=Preview').isVisible().catch(() => false) ||
|
||||
await page.locator('text=Banner').isVisible().catch(() => false)
|
||||
expect(hasPreview).toBeTruthy()
|
||||
})
|
||||
|
||||
test('should have export/publish buttons', async ({ page }) => {
|
||||
// Check for action buttons
|
||||
const exportBtn = page.getByRole('button', { name: /Code exportieren|Export/ })
|
||||
const publishBtn = page.getByRole('button', { name: /Veroeffentlichen|Speichern|Publish/ })
|
||||
|
||||
const hasExport = await exportBtn.isVisible().catch(() => false)
|
||||
const hasPublish = await publishBtn.isVisible().catch(() => false)
|
||||
|
||||
// At least one action button should be present
|
||||
expect(hasExport || hasPublish).toBeTruthy()
|
||||
})
|
||||
|
||||
test('should display cookie statistics', async ({ page }) => {
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Check for statistics display (cookie count, third-party count)
|
||||
const pageContent = await page.textContent('body')
|
||||
const hasStats = pageContent?.includes('Cookie') || pageContent?.includes('Vendor')
|
||||
expect(hasStats).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test.describe('Cookie Banner Navigation', () => {
|
||||
test('should be reachable from SDK sidebar', async ({ page }) => {
|
||||
// Navigate to SDK dashboard first
|
||||
await navigateToSDK(page, '')
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Look for cookie banner link in sidebar or navigation
|
||||
const bannerLink = page.locator('a[href*="cookie-banner"]').first()
|
||||
if (await bannerLink.isVisible().catch(() => false)) {
|
||||
await bannerLink.click()
|
||||
await waitForPageLoad(page)
|
||||
await expect(page).toHaveURL(/cookie-banner/)
|
||||
}
|
||||
})
|
||||
|
||||
test('should navigate between consent management pages', async ({ page }) => {
|
||||
await navigateToSDK(page, '/einwilligungen')
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Check if tabs/links to cookie-banner exist
|
||||
const cookieBannerTab = page.locator('a[href*="cookie-banner"], button:has-text("Cookie")')
|
||||
const isVisible = await cookieBannerTab.first().isVisible().catch(() => false)
|
||||
|
||||
if (isVisible) {
|
||||
await cookieBannerTab.first().click()
|
||||
await waitForPageLoad(page)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test.describe('Consent Management Page', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await navigateToSDK(page, '/consent-management')
|
||||
})
|
||||
|
||||
test('should load consent management page', async ({ page }) => {
|
||||
await page.waitForTimeout(1000)
|
||||
const pageContent = await page.textContent('body')
|
||||
// Page should have consent-related content
|
||||
const hasContent = pageContent?.includes('Consent') ||
|
||||
pageContent?.includes('Einwilligung') ||
|
||||
pageContent?.includes('consent')
|
||||
expect(hasContent).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
test.describe('DSR Module — Banner Integration', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await navigateToSDK(page, '/dsr')
|
||||
})
|
||||
|
||||
test('should load DSR portal', async ({ page }) => {
|
||||
await expect(page.getByRole('heading', { name: /DSR|Betroffenen/ })).toBeVisible({
|
||||
timeout: 10000,
|
||||
})
|
||||
})
|
||||
|
||||
test('should have tab navigation for DSR workflow', async ({ page }) => {
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// DSR should have workflow tabs
|
||||
const pageContent = await page.textContent('body')
|
||||
const hasTabs = pageContent?.includes('Eingang') ||
|
||||
pageContent?.includes('Bearbeitung') ||
|
||||
pageContent?.includes('Abgeschlossen')
|
||||
expect(hasTabs).toBeTruthy()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user