Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
241
admin-compliance/e2e/fixtures/sdk-fixtures.ts
Normal file
241
admin-compliance/e2e/fixtures/sdk-fixtures.ts
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Playwright Test Fixtures for AI Compliance SDK
|
||||
*
|
||||
* These fixtures provide reusable setup for SDK E2E tests.
|
||||
* Demo data is seeded via the API (same storage path as real data).
|
||||
*/
|
||||
|
||||
import { test as base, expect, Page } from '@playwright/test'
|
||||
|
||||
// Selectors for SDK components
|
||||
export const selectors = {
|
||||
// Dashboard
|
||||
dashboard: '[data-testid="sdk-dashboard"]',
|
||||
loadDemoDataButton: '[data-testid="load-demo-data"]',
|
||||
progressBar: '[data-testid="progress-bar"]',
|
||||
|
||||
// Sidebar
|
||||
sidebar: '[data-testid="sdk-sidebar"]',
|
||||
sidebarPhase1: '[data-testid="sidebar-phase-1"]',
|
||||
sidebarPhase2: '[data-testid="sidebar-phase-2"]',
|
||||
sidebarStep: (stepId: string) => `[data-testid="sidebar-step-${stepId}"]`,
|
||||
|
||||
// Command Bar
|
||||
commandBar: '[data-testid="command-bar"]',
|
||||
commandInput: '[data-testid="command-input"]',
|
||||
commandSuggestion: (index: number) => `[data-testid="command-suggestion-${index}"]`,
|
||||
|
||||
// Navigation
|
||||
prevButton: '[data-testid="prev-step-button"]',
|
||||
nextButton: '[data-testid="next-step-button"]',
|
||||
stepHeader: '[data-testid="step-header"]',
|
||||
|
||||
// Use Case Workshop
|
||||
useCaseCard: (index: number) => `[data-testid="use-case-card-${index}"]`,
|
||||
addUseCaseButton: '[data-testid="add-use-case-button"]',
|
||||
useCaseForm: '[data-testid="use-case-form"]',
|
||||
|
||||
// Risk Matrix
|
||||
riskCard: (riskId: string) => `[data-testid="risk-card-${riskId}"]`,
|
||||
riskMatrix: '[data-testid="risk-matrix"]',
|
||||
addRiskButton: '[data-testid="add-risk-button"]',
|
||||
|
||||
// Controls
|
||||
controlCard: (controlId: string) => `[data-testid="control-card-${controlId}"]`,
|
||||
controlsGrid: '[data-testid="controls-grid"]',
|
||||
|
||||
// Export
|
||||
exportButton: '[data-testid="export-button"]',
|
||||
exportPdfButton: '[data-testid="export-pdf-button"]',
|
||||
exportZipButton: '[data-testid="export-zip-button"]',
|
||||
}
|
||||
|
||||
// Type for SDK test fixtures
|
||||
type SDKFixtures = {
|
||||
sdkPage: Page
|
||||
withDemoData: Page
|
||||
commandBar: Page
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended test with SDK-specific fixtures
|
||||
*/
|
||||
export const test = base.extend<SDKFixtures>({
|
||||
// Basic SDK page (navigates to dashboard)
|
||||
sdkPage: async ({ page }, use) => {
|
||||
await page.goto('/sdk')
|
||||
// Wait for page to be ready
|
||||
await page.waitForLoadState('networkidle')
|
||||
await use(page)
|
||||
},
|
||||
|
||||
// SDK page with demo data loaded
|
||||
withDemoData: async ({ page }, use) => {
|
||||
// Navigate to SDK
|
||||
await page.goto('/sdk')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// Seed demo data via API (same storage path as real data)
|
||||
await page.evaluate(async () => {
|
||||
const response = await fetch('/api/sdk/v1/demo/seed', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tenantId: 'e2e-test-tenant' }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
// If endpoint doesn't exist, try seeding via localStorage
|
||||
// This is a fallback for development
|
||||
console.warn('Demo seed endpoint not available, using localStorage fallback')
|
||||
}
|
||||
})
|
||||
|
||||
// Reload page to pick up demo data
|
||||
await page.reload()
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
await use(page)
|
||||
|
||||
// Cleanup: Clear demo data after test
|
||||
await page.evaluate(async () => {
|
||||
try {
|
||||
await fetch('/api/sdk/v1/demo/clear', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tenantId: 'e2e-test-tenant' }),
|
||||
})
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// SDK page with command bar opened
|
||||
commandBar: async ({ page }, use) => {
|
||||
await page.goto('/sdk')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// Open command bar with keyboard shortcut
|
||||
await page.keyboard.press('Meta+k')
|
||||
|
||||
// Wait for command bar to be visible
|
||||
await page.waitForSelector(selectors.commandBar, { state: 'visible' })
|
||||
|
||||
await use(page)
|
||||
},
|
||||
})
|
||||
|
||||
// Re-export expect for convenience
|
||||
export { expect }
|
||||
|
||||
/**
|
||||
* Helper: Wait for SDK to initialize
|
||||
*/
|
||||
export async function waitForSDKInit(page: Page): Promise<void> {
|
||||
await page.waitForLoadState('networkidle')
|
||||
// Wait for React hydration
|
||||
await page.waitForFunction(() => {
|
||||
return document.querySelector('[data-testid="sdk-dashboard"]') !== null ||
|
||||
document.querySelector('[data-testid="step-header"]') !== null
|
||||
}, { timeout: 10000 })
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Navigate to a specific SDK step
|
||||
*/
|
||||
export async function navigateToStep(page: Page, stepId: string): Promise<void> {
|
||||
const stepUrl = getStepUrl(stepId)
|
||||
await page.goto(stepUrl)
|
||||
await waitForSDKInit(page)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Get URL for a step
|
||||
*/
|
||||
export function getStepUrl(stepId: string): string {
|
||||
const stepUrls: Record<string, string> = {
|
||||
'use-case-workshop': '/sdk/advisory-board',
|
||||
'screening': '/sdk/screening',
|
||||
'modules': '/sdk/modules',
|
||||
'requirements': '/sdk/requirements',
|
||||
'controls': '/sdk/controls',
|
||||
'evidence': '/sdk/evidence',
|
||||
'audit-checklist': '/sdk/audit-checklist',
|
||||
'risks': '/sdk/risks',
|
||||
'ai-act': '/sdk/ai-act',
|
||||
'obligations': '/sdk/obligations',
|
||||
'dsfa': '/sdk/dsfa',
|
||||
'tom': '/sdk/tom',
|
||||
'loeschfristen': '/sdk/loeschfristen',
|
||||
'vvt': '/sdk/vvt',
|
||||
'consent': '/sdk/consent',
|
||||
'cookie-banner': '/sdk/cookie-banner',
|
||||
'einwilligungen': '/sdk/einwilligungen',
|
||||
'dsr': '/sdk/dsr',
|
||||
'escalations': '/sdk/escalations',
|
||||
}
|
||||
return stepUrls[stepId] || '/sdk'
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Use command bar to navigate
|
||||
*/
|
||||
export async function useCommandBarToNavigate(page: Page, searchTerm: string): Promise<void> {
|
||||
// Open command bar
|
||||
await page.keyboard.press('Meta+k')
|
||||
await page.waitForSelector(selectors.commandBar, { state: 'visible' })
|
||||
|
||||
// Type search term
|
||||
await page.fill(selectors.commandInput, searchTerm)
|
||||
|
||||
// Wait for suggestions
|
||||
await page.waitForSelector(selectors.commandSuggestion(0), { timeout: 5000 })
|
||||
|
||||
// Click first suggestion
|
||||
await page.click(selectors.commandSuggestion(0))
|
||||
|
||||
// Wait for navigation
|
||||
await page.waitForLoadState('networkidle')
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Seed demo data programmatically
|
||||
*/
|
||||
export async function seedDemoData(page: Page, tenantId: string = 'e2e-test'): Promise<boolean> {
|
||||
const result = await page.evaluate(async (tid) => {
|
||||
try {
|
||||
const response = await fetch('/api/sdk/v1/demo/seed', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tenantId: tid }),
|
||||
})
|
||||
return response.ok
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}, tenantId)
|
||||
|
||||
if (result) {
|
||||
await page.reload()
|
||||
await waitForSDKInit(page)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Clear demo data
|
||||
*/
|
||||
export async function clearDemoData(page: Page, tenantId: string = 'e2e-test'): Promise<boolean> {
|
||||
return await page.evaluate(async (tid) => {
|
||||
try {
|
||||
const response = await fetch('/api/sdk/v1/demo/clear', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tenantId: tid }),
|
||||
})
|
||||
return response.ok
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}, tenantId)
|
||||
}
|
||||
Reference in New Issue
Block a user