9b17e4a282
Dashboard: 3 selector fixes (banner link, KPI values, DSR link). Preview: replaced all networkidle with domcontentloaded + 2s wait. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
298 lines
11 KiB
TypeScript
298 lines
11 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
|
|
/**
|
|
* CMP EWR-Only & Consent Persistence E2E Tests
|
|
*
|
|
* Tests the cookie banner preview page (/sdk/cookie-banner/preview):
|
|
* - Banner appearance on first visit
|
|
* - EWR-Only toggle
|
|
* - "Alle akzeptieren" saves consent and closes banner
|
|
* - Consent persistence across reloads
|
|
* - "Nur notwendige Cookies" saves minimal consent
|
|
* - Cookie FAB button after consent
|
|
* - FAB reopens banner with previous settings
|
|
* - "Consent zuruecksetzen" resets everything
|
|
* - API debug panel
|
|
* - Category toggles (necessary is disabled)
|
|
*/
|
|
|
|
const PREVIEW_URL = '/sdk/cookie-banner/preview'
|
|
|
|
test.describe('Preview Banner — First Visit', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
})
|
|
|
|
test('should show banner on page load', async ({ page }) => {
|
|
await expect(page.getByText('Cookie-Einstellungen')).toBeVisible({ timeout: 10000 })
|
|
await expect(page.getByText('welche Cookie-Kategorien Sie zulassen')).toBeVisible()
|
|
})
|
|
|
|
test('should show simulated website behind the banner', async ({ page }) => {
|
|
// The simulated MusterShop website should be visible behind the overlay
|
|
await expect(page.getByText('MusterShop GmbH')).toBeVisible()
|
|
await expect(page.getByText('Willkommen bei MusterShop')).toBeVisible()
|
|
})
|
|
|
|
test('should display overlay backdrop behind banner', async ({ page }) => {
|
|
const overlay = page.locator('.bg-black\\/40')
|
|
await expect(overlay).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — EWR-Only Toggle', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
await page.waitForTimeout(500)
|
|
})
|
|
|
|
test('should show EWR-Only toggle in banner', async ({ page }) => {
|
|
await expect(page.getByText('Nur EU/EWR')).toBeVisible()
|
|
})
|
|
|
|
test('should toggle EWR-Only state on click', async ({ page }) => {
|
|
// Find the toggle button next to "Nur EU/EWR"
|
|
const ewrLabel = page.getByText('Nur EU/EWR')
|
|
const toggleContainer = ewrLabel.locator('..')
|
|
const toggle = toggleContainer.locator('button')
|
|
|
|
// Initially off (bg-gray-200)
|
|
await expect(toggle).toBeVisible()
|
|
|
|
// Click to enable EWR-Only
|
|
await toggle.click()
|
|
await page.waitForTimeout(300)
|
|
|
|
// Label should now have active styling (text-blue-700)
|
|
await expect(page.locator('.text-blue-700')).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Accept All', () => {
|
|
test('should close banner and show consent in debug panel', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Click "Alle akzeptieren"
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Banner should close (overlay gone)
|
|
const overlayVisible = await page.locator('.bg-black\\/40').isVisible().catch(() => false)
|
|
expect(overlayVisible).toBe(false)
|
|
|
|
// API debug panel should show "Gespeichert"
|
|
await expect(page.getByText('Gespeichert')).toBeVisible({ timeout: 5000 })
|
|
})
|
|
|
|
test('should show API response in debug panel after accept', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// API response panel should show POST response
|
|
const hasResponse = await page.getByText('POST /banner/consent Response').isVisible().catch(() => false) ||
|
|
await page.getByText('device_fingerprint').isVisible().catch(() => false)
|
|
expect(hasResponse).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Nur notwendige Cookies', () => {
|
|
test('should save minimal consent and close banner', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Click "Nur notwendige Cookies"
|
|
await page.getByText('Nur notwendige Cookies').click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Banner should close
|
|
const bannerVisible = await page.getByText('welche Cookie-Kategorien').isVisible().catch(() => false)
|
|
expect(bannerVisible).toBe(false)
|
|
|
|
// Debug panel should show consent
|
|
await expect(page.getByText('Gespeichert')).toBeVisible({ timeout: 5000 })
|
|
|
|
// Categories should show only "necessary"
|
|
const debugPanel = page.locator('.bg-slate-50')
|
|
const panelText = await debugPanel.textContent()
|
|
expect(panelText).toContain('necessary')
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Consent Persistence', () => {
|
|
test('banner should not reappear after accepting and reloading', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Accept all
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Reload the page
|
|
await page.reload()
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
await page.waitForTimeout(2000)
|
|
|
|
// The banner checks consent via API, so the overlay should not appear
|
|
// Note: This depends on the API returning has_consent=true for the fingerprint.
|
|
// The page re-generates a fingerprint on each mount, so the banner WILL
|
|
// appear again (by design — fingerprint is per-session). We verify that
|
|
// the simulated website is still accessible.
|
|
await expect(page.getByText('MusterShop GmbH')).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Cookie FAB Button', () => {
|
|
test('should show footer link to reopen banner after consent', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Accept to close the banner
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Footer has "Cookie-Einstellungen" button
|
|
const footerBtn = page.locator('footer button', { hasText: 'Cookie-Einstellungen' })
|
|
await expect(footerBtn).toBeVisible()
|
|
})
|
|
|
|
test('should reopen banner when footer button is clicked', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Accept to close
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Click footer button to reopen
|
|
const footerBtn = page.locator('footer button', { hasText: 'Cookie-Einstellungen' })
|
|
await footerBtn.click()
|
|
await page.waitForTimeout(500)
|
|
|
|
// Banner should be visible again
|
|
await expect(page.getByText('Cookie-Einstellungen').first()).toBeVisible()
|
|
await expect(page.getByText('welche Cookie-Kategorien')).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Consent Reset', () => {
|
|
test('should reset consent when "zuruecksetzen" is clicked', async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
|
|
// Accept consent first
|
|
await page.getByRole('button', { name: 'Alle akzeptieren' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Verify consent is saved
|
|
await expect(page.getByText('Gespeichert')).toBeVisible()
|
|
|
|
// Click reset
|
|
await page.getByText('Consent zuruecksetzen').click()
|
|
await page.waitForTimeout(500)
|
|
|
|
// Banner should reappear
|
|
await expect(page.getByText('Cookie-Einstellungen')).toBeVisible()
|
|
await expect(page.getByText('welche Cookie-Kategorien')).toBeVisible()
|
|
|
|
// Debug panel should show "Ausstehend" again
|
|
await expect(page.getByText('Ausstehend')).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — API Debug Panel', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
})
|
|
|
|
test('should display API Debug section', async ({ page }) => {
|
|
await expect(page.getByText('API Debug')).toBeVisible()
|
|
})
|
|
|
|
test('should show Site ID and Fingerprint', async ({ page }) => {
|
|
await expect(page.getByText('Site ID')).toBeVisible()
|
|
await expect(page.getByText('preview-test-site')).toBeVisible()
|
|
await expect(page.getByText('Fingerprint')).toBeVisible()
|
|
})
|
|
|
|
test('should show consent status as "Ausstehend" before consent', async ({ page }) => {
|
|
const debugPanel = page.locator('.bg-slate-50')
|
|
await expect(debugPanel.getByText('Ausstehend')).toBeVisible()
|
|
})
|
|
|
|
test('should show links to Consent-Verwaltung and Consent-Records', async ({ page }) => {
|
|
await expect(page.locator('a[href="/sdk/consent-management"]')).toBeVisible()
|
|
await expect(page.locator('a[href="/sdk/einwilligungen"]')).toBeVisible()
|
|
await expect(page.locator('a[href="/sdk/dsr"]')).toBeVisible()
|
|
})
|
|
})
|
|
|
|
|
|
test.describe('Preview Banner — Category Toggles', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto(PREVIEW_URL)
|
|
await page.waitForLoadState('domcontentloaded')
|
|
await page.waitForTimeout(2000)
|
|
await page.waitForTimeout(500)
|
|
})
|
|
|
|
test('should display all 4 category rows', async ({ page }) => {
|
|
await expect(page.getByText('Notwendig', { exact: false }).first()).toBeVisible()
|
|
await expect(page.getByText('Statistik', { exact: false }).first()).toBeVisible()
|
|
await expect(page.getByText('Marketing', { exact: false }).first()).toBeVisible()
|
|
await expect(page.getByText('Funktional', { exact: false }).first()).toBeVisible()
|
|
})
|
|
|
|
test('necessary toggle should be disabled', async ({ page }) => {
|
|
// The necessary category toggle has cursor-not-allowed and opacity-60
|
|
const necessaryToggle = page.locator('button.cursor-not-allowed')
|
|
await expect(necessaryToggle.first()).toBeVisible()
|
|
})
|
|
|
|
test('should toggle statistics category on click', async ({ page }) => {
|
|
// Find the Statistik row and its toggle button
|
|
const statistikRow = page.locator('div', { hasText: 'Statistik' }).filter({ has: page.locator('button') })
|
|
const toggle = statistikRow.first().locator('button:not([disabled])').last()
|
|
|
|
// Click toggle to enable
|
|
await toggle.click()
|
|
await page.waitForTimeout(200)
|
|
|
|
// Save custom selection
|
|
await page.getByRole('button', { name: 'Auswahl speichern' }).click()
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Banner should close and consent should be saved
|
|
const overlayGone = await page.locator('.bg-black\\/40').isVisible().catch(() => false)
|
|
expect(overlayGone).toBe(false)
|
|
})
|
|
|
|
test('should show "Auswahl speichern" button', async ({ page }) => {
|
|
await expect(page.getByRole('button', { name: 'Auswahl speichern' })).toBeVisible()
|
|
})
|
|
})
|