fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit restores all missing components: - Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education, infrastructure, communication, development, onboarding, rbac - SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen, vendor-compliance, tom-generator, dsr, and more - Developer portal (25 pages): API docs, SDK guides, frameworks - All components, lib files, hooks, and types - Updated package.json with all dependencies The issue was caused by incomplete initial repository state - the full admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2 but was never fully synced to the main admin-v2 directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
324
admin-v2/lib/sdk/__tests__/export.test.ts
Normal file
324
admin-v2/lib/sdk/__tests__/export.test.ts
Normal file
@@ -0,0 +1,324 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { exportToPDF, exportToZIP, downloadExport } from '../export'
|
||||
import type { SDKState } from '../types'
|
||||
|
||||
// Mock jsPDF as a class
|
||||
vi.mock('jspdf', () => {
|
||||
return {
|
||||
default: class MockJsPDF {
|
||||
internal = {
|
||||
pageSize: { getWidth: () => 210, getHeight: () => 297 },
|
||||
}
|
||||
setFillColor = vi.fn().mockReturnThis()
|
||||
setDrawColor = vi.fn().mockReturnThis()
|
||||
setTextColor = vi.fn().mockReturnThis()
|
||||
setFontSize = vi.fn().mockReturnThis()
|
||||
setFont = vi.fn().mockReturnThis()
|
||||
setLineWidth = vi.fn().mockReturnThis()
|
||||
text = vi.fn().mockReturnThis()
|
||||
line = vi.fn().mockReturnThis()
|
||||
rect = vi.fn().mockReturnThis()
|
||||
roundedRect = vi.fn().mockReturnThis()
|
||||
circle = vi.fn().mockReturnThis()
|
||||
addPage = vi.fn().mockReturnThis()
|
||||
setPage = vi.fn().mockReturnThis()
|
||||
getNumberOfPages = vi.fn(() => 5)
|
||||
splitTextToSize = vi.fn((text: string) => [text])
|
||||
output = vi.fn(() => new Blob(['mock-pdf'], { type: 'application/pdf' }))
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// Mock JSZip as a class
|
||||
vi.mock('jszip', () => {
|
||||
return {
|
||||
default: class MockJSZip {
|
||||
private mockFolder = {
|
||||
file: vi.fn().mockReturnThis(),
|
||||
folder: vi.fn(() => this.mockFolder),
|
||||
}
|
||||
folder = vi.fn(() => this.mockFolder)
|
||||
generateAsync = vi.fn(() => Promise.resolve(new Blob(['mock-zip'], { type: 'application/zip' })))
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const createMockState = (overrides: Partial<SDKState> = {}): SDKState => ({
|
||||
version: '1.0.0',
|
||||
lastModified: new Date('2024-01-15'),
|
||||
tenantId: 'test-tenant',
|
||||
userId: 'test-user',
|
||||
subscription: 'PROFESSIONAL',
|
||||
currentPhase: 1,
|
||||
currentStep: 'use-case-workshop',
|
||||
completedSteps: ['use-case-workshop', 'screening'],
|
||||
checkpoints: {
|
||||
'CP-UC': {
|
||||
checkpointId: 'CP-UC',
|
||||
passed: true,
|
||||
validatedAt: new Date(),
|
||||
validatedBy: 'SYSTEM',
|
||||
errors: [],
|
||||
warnings: [],
|
||||
},
|
||||
},
|
||||
useCases: [
|
||||
{
|
||||
id: 'uc-1',
|
||||
name: 'Test Use Case',
|
||||
description: 'A test use case for testing',
|
||||
category: 'Marketing',
|
||||
stepsCompleted: 3,
|
||||
steps: [
|
||||
{ id: 's1', name: 'Step 1', completed: true, data: {} },
|
||||
{ id: 's2', name: 'Step 2', completed: true, data: {} },
|
||||
{ id: 's3', name: 'Step 3', completed: true, data: {} },
|
||||
],
|
||||
assessmentResult: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
activeUseCase: 'uc-1',
|
||||
screening: null,
|
||||
modules: [],
|
||||
requirements: [],
|
||||
controls: [
|
||||
{
|
||||
id: 'ctrl-1',
|
||||
name: 'Test Control',
|
||||
description: 'A test control',
|
||||
type: 'TECHNICAL',
|
||||
category: 'Access Control',
|
||||
implementationStatus: 'IMPLEMENTED',
|
||||
effectiveness: 'HIGH',
|
||||
evidence: [],
|
||||
owner: 'Test Owner',
|
||||
dueDate: null,
|
||||
},
|
||||
],
|
||||
evidence: [],
|
||||
checklist: [],
|
||||
risks: [
|
||||
{
|
||||
id: 'risk-1',
|
||||
title: 'Test Risk',
|
||||
description: 'A test risk',
|
||||
category: 'Security',
|
||||
likelihood: 3,
|
||||
impact: 4,
|
||||
severity: 'HIGH',
|
||||
inherentRiskScore: 12,
|
||||
residualRiskScore: 6,
|
||||
status: 'MITIGATED',
|
||||
mitigation: [
|
||||
{
|
||||
id: 'mit-1',
|
||||
description: 'Test mitigation',
|
||||
type: 'MITIGATE',
|
||||
status: 'COMPLETED',
|
||||
effectiveness: 80,
|
||||
controlId: 'ctrl-1',
|
||||
},
|
||||
],
|
||||
owner: 'Risk Owner',
|
||||
relatedControls: ['ctrl-1'],
|
||||
relatedRequirements: [],
|
||||
},
|
||||
],
|
||||
aiActClassification: null,
|
||||
obligations: [],
|
||||
dsfa: null,
|
||||
toms: [],
|
||||
retentionPolicies: [],
|
||||
vvt: [],
|
||||
documents: [],
|
||||
cookieBanner: null,
|
||||
consents: [],
|
||||
dsrConfig: null,
|
||||
escalationWorkflows: [],
|
||||
sbom: null,
|
||||
securityIssues: [],
|
||||
securityBacklog: [],
|
||||
commandBarHistory: [],
|
||||
recentSearches: [],
|
||||
preferences: {
|
||||
language: 'de',
|
||||
theme: 'light',
|
||||
compactMode: false,
|
||||
showHints: true,
|
||||
autoSave: true,
|
||||
autoValidate: true,
|
||||
allowParallelWork: true,
|
||||
},
|
||||
...overrides,
|
||||
})
|
||||
|
||||
describe('exportToPDF', () => {
|
||||
it('should return a Blob', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToPDF(state)
|
||||
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
|
||||
it('should create a PDF with the correct type', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToPDF(state)
|
||||
|
||||
expect(result.type).toBe('application/pdf')
|
||||
})
|
||||
|
||||
it('should handle empty state', async () => {
|
||||
const emptyState = createMockState({
|
||||
useCases: [],
|
||||
risks: [],
|
||||
controls: [],
|
||||
completedSteps: [],
|
||||
})
|
||||
|
||||
const result = await exportToPDF(emptyState)
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
|
||||
it('should handle state with multiple risks of different severities', async () => {
|
||||
const state = createMockState({
|
||||
risks: [
|
||||
{
|
||||
id: 'risk-1',
|
||||
title: 'Critical Risk',
|
||||
description: 'Critical',
|
||||
category: 'Security',
|
||||
likelihood: 5,
|
||||
impact: 5,
|
||||
severity: 'CRITICAL',
|
||||
inherentRiskScore: 25,
|
||||
residualRiskScore: 15,
|
||||
status: 'IDENTIFIED',
|
||||
mitigation: [],
|
||||
owner: null,
|
||||
relatedControls: [],
|
||||
relatedRequirements: [],
|
||||
},
|
||||
{
|
||||
id: 'risk-2',
|
||||
title: 'Low Risk',
|
||||
description: 'Low',
|
||||
category: 'Operational',
|
||||
likelihood: 1,
|
||||
impact: 1,
|
||||
severity: 'LOW',
|
||||
inherentRiskScore: 1,
|
||||
residualRiskScore: 1,
|
||||
status: 'ACCEPTED',
|
||||
mitigation: [],
|
||||
owner: null,
|
||||
relatedControls: [],
|
||||
relatedRequirements: [],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = await exportToPDF(state)
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
})
|
||||
|
||||
describe('exportToZIP', () => {
|
||||
it('should return a Blob', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToZIP(state)
|
||||
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
|
||||
it('should create a ZIP with the correct type', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToZIP(state)
|
||||
|
||||
expect(result.type).toBe('application/zip')
|
||||
})
|
||||
|
||||
it('should handle empty state', async () => {
|
||||
const emptyState = createMockState({
|
||||
useCases: [],
|
||||
risks: [],
|
||||
controls: [],
|
||||
completedSteps: [],
|
||||
})
|
||||
|
||||
const result = await exportToZIP(emptyState)
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
|
||||
it('should respect includeEvidence option', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToZIP(state, { includeEvidence: false })
|
||||
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
|
||||
it('should respect includeDocuments option', async () => {
|
||||
const state = createMockState()
|
||||
const result = await exportToZIP(state, { includeDocuments: false })
|
||||
|
||||
expect(result).toBeInstanceOf(Blob)
|
||||
})
|
||||
})
|
||||
|
||||
describe('downloadExport', () => {
|
||||
let mockCreateElement: ReturnType<typeof vi.spyOn>
|
||||
let mockAppendChild: ReturnType<typeof vi.spyOn>
|
||||
let mockRemoveChild: ReturnType<typeof vi.spyOn>
|
||||
let mockLink: { href: string; download: string; click: ReturnType<typeof vi.fn> }
|
||||
|
||||
beforeEach(() => {
|
||||
mockLink = {
|
||||
href: '',
|
||||
download: '',
|
||||
click: vi.fn(),
|
||||
}
|
||||
|
||||
mockCreateElement = vi.spyOn(document, 'createElement').mockReturnValue(mockLink as unknown as HTMLElement)
|
||||
mockAppendChild = vi.spyOn(document.body, 'appendChild').mockImplementation(() => mockLink as unknown as HTMLElement)
|
||||
mockRemoveChild = vi.spyOn(document.body, 'removeChild').mockImplementation(() => mockLink as unknown as HTMLElement)
|
||||
})
|
||||
|
||||
it('should download JSON format', async () => {
|
||||
const state = createMockState()
|
||||
await downloadExport(state, 'json')
|
||||
|
||||
expect(mockLink.download).toContain('.json')
|
||||
expect(mockLink.click).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should download PDF format', async () => {
|
||||
const state = createMockState()
|
||||
await downloadExport(state, 'pdf')
|
||||
|
||||
expect(mockLink.download).toContain('.pdf')
|
||||
expect(mockLink.click).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should download ZIP format', async () => {
|
||||
const state = createMockState()
|
||||
await downloadExport(state, 'zip')
|
||||
|
||||
expect(mockLink.download).toContain('.zip')
|
||||
expect(mockLink.click).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should include date in filename', async () => {
|
||||
const state = createMockState()
|
||||
await downloadExport(state, 'json')
|
||||
|
||||
// Check that filename contains a date pattern
|
||||
expect(mockLink.download).toMatch(/ai-compliance-sdk-\d{4}-\d{2}-\d{2}\.json/)
|
||||
})
|
||||
|
||||
it('should throw error for unknown format', async () => {
|
||||
const state = createMockState()
|
||||
|
||||
await expect(downloadExport(state, 'unknown' as any)).rejects.toThrow('Unknown export format')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user