import { describe, expect, it } from 'vitest'; import { CONTENT_PACK } from '../content/pack'; import { answerKeyDoc, certificateDoc, getQuiz, handoutDoc, printableTestDoc, scoreQuiz, trainingLogDoc, } from './quiz'; import { QUIZ_PASS_PCT, QUIZ_QUESTIONS } from './quizContent'; import type { CompanyProfile } from './types'; const profile: CompanyProfile = { name: 'Muster GmbH', street: '', zipCity: '', contactPerson: '', email: '', phone: '', website: '', logoDataUrl: '', countries: [], }; describe('KI-Kompetenztest', () => { it('hat 12 einfache Fragen mit je 3 Optionen und gültigem Lösungsindex', () => { expect(QUIZ_QUESTIONS).toHaveLength(12); for (const q of QUIZ_QUESTIONS) { expect(q.options).toHaveLength(3); expect([0, 1, 2]).toContain(q.correctIndex); } }); it('löst Fragen lokalisiert auf (DE und EN unterscheiden sich)', () => { const de = getQuiz('de'); const en = getQuiz('en'); expect(de).toHaveLength(en.length); expect(de[0]?.question).not.toBe(en[0]?.question); }); it('wertet korrekt aus: alle richtig = bestanden, alle falsch = durchgefallen', () => { const perfect = scoreQuiz(QUIZ_QUESTIONS.map((q) => q.correctIndex)); expect(perfect.pct).toBe(100); expect(perfect.passed).toBe(true); const wrong = scoreQuiz(QUIZ_QUESTIONS.map((q) => ((q.correctIndex + 1) % 3) as 0 | 1 | 2)); expect(wrong.correct).toBe(0); expect(wrong.passed).toBe(false); }); it('wendet die Bestehensgrenze an (knapp darunter = durchgefallen)', () => { // 8 von 12 = 67 % < 70 % → nicht bestanden; 9 von 12 = 75 % → bestanden const eight = scoreQuiz( QUIZ_QUESTIONS.map((q, i) => (i < 8 ? q.correctIndex : ((q.correctIndex + 1) % 3) as 0 | 1 | 2)), ); expect(eight.passed).toBe(false); const nine = scoreQuiz( QUIZ_QUESTIONS.map((q, i) => (i < 9 ? q.correctIndex : ((q.correctIndex + 1) % 3) as 0 | 1 | 2)), ); expect(nine.passed).toBe(true); expect(QUIZ_PASS_PCT).toBe(70); }); it('erzeugt ein Zertifikat mit Name, Ergebnis, Art.-4-Bezug und Disclaimer', () => { const score = scoreQuiz(QUIZ_QUESTIONS.map((q) => q.correctIndex)); const md = certificateDoc('Max Mustermann', score, CONTENT_PACK, '2026-07-04', profile); expect(md).toContain('Nachweis KI-Kompetenz (Art. 4'); expect(md).toContain('Max Mustermann'); expect(md).toContain('BESTANDEN'); expect(md).toContain('Muster GmbH'); expect(md).toContain('keine Rechtsberatung'); }); it('Papierfassung enthält alle Fragen, Ankreuzfelder und Auswertungszeile', () => { const md = printableTestDoc(CONTENT_PACK, '2026-07-04', profile); expect(md).toContain('Papierfassung'); expect((md.match(/☐/g) ?? []).length).toBe(36); // 12 Fragen × 3 Optionen expect(md).toContain('**Name:**'); expect(md).toContain('Ergebnis: ______ / 12'); expect(md).not.toContain('richtige Antwort'); // keine Lösungen im Testbogen }); it('Lösungsbogen enthält je Frage den Fragetext, die richtige Antwort im Wortlaut und die Erklärung', () => { const md = answerKeyDoc(CONTENT_PACK, '2026-07-04', profile); expect(md).toContain('Lösungsbogen'); // Fragetext enthalten (selbsterklärend, ohne Testbogen daneben): expect((md.match(/^## \d+\./gm) ?? []).length).toBe(12); expect(md).toContain('Was macht ein KI-System'); // Richtige Antwort mit Buchstabe UND Wortlaut: expect((md.match(/\*\*Richtige Antwort: [ABC]\)\*\*/g) ?? []).length).toBe(12); expect(md).toContain('Nein — nur in vom Unternehmen freigegebene KI-Systeme.'); // Erklärungen enthalten: expect((md.match(/_Erklärung:_/g) ?? []).length).toBe(12); }); it('Schulungshandout enthält die 12 Erklärungen und ist lokalisiert', () => { const de = handoutDoc(CONTENT_PACK, '2026-07-04', profile, 'de'); expect(de).toContain('Schulungshandout'); expect((de.match(/^## \d+\./gm) ?? []).length).toBe(12); const en = handoutDoc(CONTENT_PACK, '2026-07-04', profile, 'en'); expect(en).toContain('Training handout'); expect(en).not.toBe(de); }); it('erzeugt das Schulungsregister mit Quelle, Beleg-Prüfsumme und ID', () => { const md = trainingLogDoc( [ { id: 'abcdef12-3456', name: 'Max Mustermann', date: '2026-07-04', scorePct: 92, passed: true, source: 'paper', attachment: { fileName: 'scan.pdf', sha256: 'f'.repeat(64), dataUrl: 'data:application/pdf;base64,x' }, }, { id: '2', name: 'Erika Musterfrau', date: '2026-07-03', scorePct: 58, passed: false }, ], CONTENT_PACK, '2026-07-04', profile, ); expect(md).toContain('Schulungsregister'); expect(md).toContain('| Papier |'); // Quelle Papier-Test expect(md).toContain('| App |'); // Alt-Einträge ohne source = App expect(md).toContain('`ffffffffffffffff…`'); // Beleg-Prüfsumme (gekürzt) expect(md).toContain('`abcdef12`'); // Register-ID (gekürzt) expect(md).toContain('NICHT BESTANDEN'); }); it('Zertifikat enthält die Register-ID für die Nachweiskette', () => { const score = scoreQuiz(QUIZ_QUESTIONS.map((q) => q.correctIndex)); const md = certificateDoc('Max', score, CONTENT_PACK, '2026-07-04', profile, 'de', 'abcdef12-3456-7890'); expect(md).toContain('Register-ID'); expect(md).toContain('`abcdef12`'); }); });