/** * Die Prüfliste zur Selbstbewertung offener Fragen. * * **Der Anlass.** Bei 63 der 104 offenen Fragen ist in der amtlichen * Musterantwort nichts unterstrichen, und die Anwendung gibt die * Unterstreichungen seit 0.17.0 zu Recht nicht mehr als Pflichtinhalt aus. * Damit stand der Lernende bei der vierstufigen Selbstbewertung – die * unmittelbar die Wiedervorlage steuert – ohne jedes Kriterium da. * * **Die Leitplanke.** `docs/entscheidung-freitext.md` Abschnitt 8 verlangt, * dass über einer solchen Liste **nie wieder** „muss Ihre Antwort enthalten“ * steht. Der letzte Test dieser Datei hält das am ganzen Bestand fest. */ import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; import type { Erklaerungen } from '../src/shared/erklaerungen'; import type { Katalog } from '../src/shared/katalog'; const WURZEL = join(process.cwd(), '..'); const ERKLAERUNGEN = JSON.parse( readFileSync(join(WURZEL, 'content', 'erklaerungen.json'), 'utf8'), ) as Erklaerungen; const KATALOG = JSON.parse( readFileSync(join(WURZEL, 'content', 'katalog', 'katalog.json'), 'utf8'), ) as Katalog; const OFFEN = new Set(KATALOG.fragen.filter((frage) => frage.typ !== 'mc').map((f) => f.id)); const MIT_PUNKTEN = Object.entries(ERKLAERUNGEN.zuFrage).filter( ([, eintrag]) => eintrag.kernpunkte !== undefined, ); describe('Die ausgelieferten Kernpunkte', () => { it('decken den größeren Teil der offenen Fragen ab', () => { /* Nicht alle: Wo die Musterantwort aus einer einzigen Tatsache besteht („Unbefristet“, „Nein“), wäre eine Prüfliste mit einem Punkt kein Werkzeug, sondern Beiwerk. */ expect(OFFEN.size).toBe(104); expect(MIT_PUNKTEN.length).toBeGreaterThan(70); expect(MIT_PUNKTEN.length).toBeLessThanOrEqual(OFFEN.size); }); it('stehen ausschließlich an offenen Fragen', () => { /* Bei einer Auswahlfrage stehen die Antwortmöglichkeiten schon da – eine Prüfliste wäre dort die Lösung, nicht eine Hilfe beim Bewerten. */ const falschePlatzierung = MIT_PUNKTEN.filter(([frageId]) => !OFFEN.has(frageId)).map( ([frageId]) => frageId, ); expect(falschePlatzierung).toEqual([]); }); it('führen zwischen zwei und acht Punkte', () => { const daneben = MIT_PUNKTEN.filter(([, eintrag]) => { const anzahl = eintrag.kernpunkte?.length ?? 0; return anzahl < 2 || anzahl > 8; }).map(([frageId]) => frageId); expect(daneben).toEqual([]); }); it('wiederholen keinen Punkt innerhalb einer Frage', () => { const doppelt = MIT_PUNKTEN.filter(([, eintrag]) => { const punkte = eintrag.kernpunkte ?? []; return new Set(punkte).size !== punkte.length; }).map(([frageId]) => frageId); expect(doppelt).toEqual([]); }); it('bleiben Stichworte statt Satzgefüge', () => { const zuLang = MIT_PUNKTEN.flatMap(([frageId, eintrag]) => (eintrag.kernpunkte ?? []) .filter((punkt) => punkt.length > 140 || punkt.trim().length === 0) .map((punkt) => `${frageId}: ${punkt.slice(0, 40)}`), ); expect(zuLang).toEqual([]); }); it('behaupten nirgends, was eine Antwort enthalten muss', () => { /* Die Leitplanke aus `docs/entscheidung-freitext.md` Abschnitt 8. Bis Fassung 0.17.0 stand über einer ähnlichen Liste „Diese Kernelemente muss Ihre Antwort enthalten“ – unbelegt, und ausdrücklich abgeschafft. Dieser Test hält fest, dass die Behauptung nicht durch die Hintertür zurückkommt. */ const verboten = /muss\s+(ihre|die)\s+antwort|zwingend\s+erforderlich/iu; const verstoesse = MIT_PUNKTEN.flatMap(([frageId, eintrag]) => (eintrag.kernpunkte ?? []).filter((punkt) => verboten.test(punkt)).map(() => frageId), ); expect(verstoesse).toEqual([]); }); it('sind bei den Fragen gesetzt, an denen der Befund hing', () => { // Vier Beispiele quer durch die Kapitel, damit ein stilles Verschwinden // auffällt. expect(ERKLAERUNGEN.zuFrage['I.5-02']?.kernpunkte).toContain( 'gegen einen gegenwärtigen rechtswidrigen Angriff', ); expect(ERKLAERUNGEN.zuFrage['I.1-30']?.kernpunkte).toHaveLength(4); expect(ERKLAERUNGEN.zuFrage['II-20']?.kernpunkte).toEqual([ 'Hülse', 'Geschoss', 'Zündsatz', 'Treibladung', ]); expect(ERKLAERUNGEN.zuFrage['IV-41']?.kernpunkte).toHaveLength(6); }); it('lassen die einteiligen Musterantworten aus', () => { /* Beispiele: „Unbefristet“, „Ja“, „Mindestens alle drei Jahre“. Eine Prüfliste mit einem Punkt wäre Beiwerk. */ for (const frageId of ['I.1-71', 'I.1-72', 'I.1-65']) { expect(ERKLAERUNGEN.zuFrage[frageId]?.kernpunkte, frageId).toBeUndefined(); } }); });