/** * DependencyMap Component Tests * * Tests fuer die Control-Requirement Mapping Visualisierung */ import { describe, it, expect, vi } from 'vitest' import { render, screen, fireEvent } from '@testing-library/react' import DependencyMap from '../../components/compliance/charts/DependencyMap' // Mock-Daten const mockRequirements = [ { id: 'req-1', article: 'Art. 32', title: 'Sicherheit der Verarbeitung', regulation_code: 'GDPR', }, { id: 'req-2', article: 'Art. 9', title: 'Risikomanagement', regulation_code: 'AIACT', }, { id: 'req-3', article: 'Art. 25', title: 'Datenschutz durch Technikgestaltung', regulation_code: 'GDPR', }, ] const mockControls = [ { id: 'ctrl-1', control_id: 'PRIV-001', title: 'Verarbeitungsverzeichnis', domain: 'priv', status: 'pass', }, { id: 'ctrl-2', control_id: 'CRYPTO-001', title: 'Verschluesselung', domain: 'crypto', status: 'pass', }, { id: 'ctrl-3', control_id: 'AI-001', title: 'KI-Risikobewertung', domain: 'ai', status: 'partial', }, ] const mockMappings = [ { requirement_id: 'req-1', control_id: 'PRIV-001', coverage_level: 'full' as const }, { requirement_id: 'req-1', control_id: 'CRYPTO-001', coverage_level: 'partial' as const }, { requirement_id: 'req-2', control_id: 'AI-001', coverage_level: 'full' as const }, { requirement_id: 'req-3', control_id: 'PRIV-001', coverage_level: 'planned' as const }, ] describe('DependencyMap', () => { it('should render the component with data', () => { render( ) // Statistik-Header sollte sichtbar sein expect(screen.getByText('Abdeckung')).toBeInTheDocument() expect(screen.getByText('Vollstaendig')).toBeInTheDocument() expect(screen.getByText('Teilweise')).toBeInTheDocument() expect(screen.getByText('Geplant')).toBeInTheDocument() }) it('should render empty state when no data', () => { render( ) expect(screen.getByText(/Keine Mappings vorhanden/i)).toBeInTheDocument() }) it('should show correct coverage statistics', () => { render( ) // 2 full, 1 partial, 1 planned expect(screen.getByText('2')).toBeInTheDocument() // full mappings expect(screen.getByText('1')).toBeInTheDocument() // partial/planned mappings }) it('should display control IDs in matrix header', () => { render( ) expect(screen.getByText('PRIV-001')).toBeInTheDocument() expect(screen.getByText('CRYPTO-001')).toBeInTheDocument() expect(screen.getByText('AI-001')).toBeInTheDocument() }) it('should display requirement articles', () => { render( ) expect(screen.getByText(/GDPR Art. 32/i)).toBeInTheDocument() expect(screen.getByText(/AIACT Art. 9/i)).toBeInTheDocument() }) it('should support German language', () => { render( ) expect(screen.getByText('Alle Verordnungen')).toBeInTheDocument() expect(screen.getByText('Alle Domains')).toBeInTheDocument() }) it('should support English language', () => { render( ) expect(screen.getByText('All Regulations')).toBeInTheDocument() expect(screen.getByText('All Domains')).toBeInTheDocument() expect(screen.getByText('Coverage')).toBeInTheDocument() }) it('should call onControlClick when control is clicked', () => { const onControlClick = vi.fn() render( ) const controlHeader = screen.getByText('PRIV-001') fireEvent.click(controlHeader) expect(onControlClick).toHaveBeenCalledWith(mockControls[0]) }) it('should call onRequirementClick when requirement is clicked', () => { const onRequirementClick = vi.fn() render( ) // Finde den Requirement-Text const reqElement = screen.getByText(/Sicherheit der Verarbeitung/i) fireEvent.click(reqElement.closest('div[class*="cursor-pointer"]')!) expect(onRequirementClick).toHaveBeenCalledWith(mockRequirements[0]) }) it('should filter by regulation', () => { render( ) const regSelect = screen.getByDisplayValue('Alle Verordnungen') fireEvent.change(regSelect, { target: { value: 'AIACT' } }) // Nur AIACT Requirements sollten sichtbar sein expect(screen.queryByText(/GDPR Art. 32/i)).not.toBeInTheDocument() expect(screen.getByText(/AIACT Art. 9/i)).toBeInTheDocument() }) it('should filter by domain', () => { render( ) const domainSelect = screen.getByDisplayValue('Alle Domains') fireEvent.change(domainSelect, { target: { value: 'priv' } }) // Nur Privacy Controls sollten sichtbar sein expect(screen.getByText('PRIV-001')).toBeInTheDocument() expect(screen.queryByText('CRYPTO-001')).not.toBeInTheDocument() }) it('should switch between matrix and connection view', () => { render( ) // Standard ist Matrix-Ansicht expect(screen.getByText('Matrix')).toBeInTheDocument() // Wechsle zu Verbindungs-Ansicht fireEvent.click(screen.getByText('Verbindungen')) // Connection-View Text sollte erscheinen expect(screen.getByText(/Waehlen Sie ein Control/i)).toBeInTheDocument() }) it('should highlight connected items when control is selected', () => { render( ) // Klicke auf einen Control fireEvent.click(screen.getByText('PRIV-001')) // Der Control sollte highlighted sein (bg-primary-100 Klasse) const controlElement = screen.getByText('PRIV-001').closest('div') expect(controlElement?.className).toContain('bg-primary-100') }) it('should show legend with coverage levels', () => { render( ) expect(screen.getByText('Vollstaendig abgedeckt')).toBeInTheDocument() expect(screen.getByText('Teilweise abgedeckt')).toBeInTheDocument() expect(screen.getByText('Geplant')).toBeInTheDocument() }) it('should calculate coverage percentage correctly', () => { render( ) // 3 von 3 Requirements haben mindestens ein Mapping = 100% expect(screen.getByText('100.0%')).toBeInTheDocument() }) it('should show control counts in connection view', () => { render( ) // Wechsle zu Verbindungs-Ansicht fireEvent.click(screen.getByText('Verbindungen')) // PRIV-001 hat 2 Verbindungen const privControl = screen.getAllByText('PRIV-001')[0].closest('button') expect(privControl?.textContent).toContain('2') }) })