Baustein 8: Lernzielkontrollen mit Freigabe, Abgabe und Korrektur
- Ausbilder gibt frei; vorher sieht der Azubi die Fragen nicht - Freigabe laesst sich zuruecknehmen, solange nicht abgegeben wurde - Antworten werden beim Tippen je Frage zwischengespeichert - Musterloesungen erst nach dem Absenden: sichtbareKontrolle() entfernt sie serverseitig, bevor die Daten in die Ausgabe gelangen - Korrektur mit Punkten und Anmerkung je Frage, Summe und Note laufen mit - Notenschluessel der IHK; solange eine Frage offen ist, bleibt das Ergebnis vorlaeufig und die Kontrolle gilt nicht als korrigiert - Ergebnis bei beiden sichtbar, Schnitt ueber alle Kontrollen - Abgegebene Kontrollen unter "Was auf dich wartet" und im Wochenfortschritt - scripts/pruefungen/musterloesung-dichtheit.mjs prueft die Sperre gegen den echten Wortlaut aus der Inhaltsdatei im rohen Seitenquelltext 36 neue Tests, davon 21 fuer die Sichtbarkeit der Musterloesung. Insgesamt 277. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7c4a051347
commit
d226a6bae8
@@ -0,0 +1,104 @@
|
||||
import { chromium } from '@playwright/test';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
/**
|
||||
* Gezielte Prüfung der einen Zusage, auf die es bei den Lernzielkontrollen
|
||||
* ankommt: Die Musterlösung darf vor dem Absenden nirgends herauskommen.
|
||||
*
|
||||
* Geprüft wird gegen den **echten** Wortlaut aus der Inhaltsdatei, nicht gegen
|
||||
* ausgedachte Zeichenketten – und im rohen Quelltext samt RSC-Nutzlast, nicht
|
||||
* im sichtbaren Text.
|
||||
*/
|
||||
|
||||
const BASIS = 'http://localhost:3311';
|
||||
const AZUBI = { email: 'jonas.berger@betrieb.de', pw: 'azubi-start-2026' };
|
||||
const AUSBILDER = { email: 'fw@wildeflorian.de', pw: 'ausbilder-start' };
|
||||
|
||||
// Musterlösungen direkt aus der Datei lesen – so kann der Test nicht veralten.
|
||||
const yaml = fs.readFileSync(path.join(process.cwd(), 'content/lernzielkontrollen/woche-01.yaml'), 'utf8');
|
||||
const loesungen = [...yaml.matchAll(/musterloesung:\s*>-\s*\n((?:\s{6}.+\n)+)/g)].map((t) =>
|
||||
t[1].replace(/\s+/g, ' ').trim(),
|
||||
);
|
||||
// Aussagekräftige Bruchstücke: lang genug, um nicht zufällig vorzukommen.
|
||||
const bruchstuecke = loesungen.map((l) => l.slice(40, 110)).filter((b) => b.length > 40);
|
||||
|
||||
console.log(`${loesungen.length} Musterlösungen aus woche-01.yaml gelesen.`);
|
||||
console.log('Geprüft wird auf Bruchstücke wie:', JSON.stringify(bruchstuecke[0]?.slice(0, 60)));
|
||||
|
||||
const browser = await chromium.launch();
|
||||
const seite = await (await browser.newContext({ locale: 'de-DE' })).newPage();
|
||||
|
||||
async function anmelden(k) {
|
||||
await seite.goto(`${BASIS}/anmelden`);
|
||||
await seite.fill('#email', k.email);
|
||||
await seite.fill('#passwort', k.pw);
|
||||
await seite.click('button[type=submit]');
|
||||
await seite.waitForURL(`${BASIS}/`);
|
||||
}
|
||||
async function abmelden() {
|
||||
await seite.click('button:has-text("Abmelden")');
|
||||
await seite.waitForURL(/anmelden/);
|
||||
}
|
||||
|
||||
/** Sucht im rohen HTML **und** in der RSC-Nutzlast. */
|
||||
async function lecksuche(beschriftung) {
|
||||
const html = await seite.content();
|
||||
const rsc = await seite.evaluate(() =>
|
||||
// Next legt die Server-Nutzlast in self.__next_f ab – dort steht alles,
|
||||
// was der Server an den Browser geschickt hat.
|
||||
(globalThis.self?.__next_f ?? []).map((t) => (Array.isArray(t) ? String(t[1] ?? '') : '')).join(''),
|
||||
);
|
||||
|
||||
const treffer = bruchstuecke.filter((b) => html.includes(b) || rsc.includes(b));
|
||||
const nullFelder = (rsc.match(/musterloesung.{0,12}null/g) ?? []).length;
|
||||
|
||||
console.log(
|
||||
` ${beschriftung.padEnd(34)} Leck: ${treffer.length === 0 ? 'nein' : `JA (${treffer.length})`}` +
|
||||
` | RSC-Größe ${rsc.length} | "musterloesung":null ${nullFelder}x`,
|
||||
);
|
||||
return treffer;
|
||||
}
|
||||
|
||||
console.log('\n1) Vor der Freigabe');
|
||||
await anmelden(AZUBI);
|
||||
await seite.goto(`${BASIS}/kontrollen/woche-01`);
|
||||
await seite.waitForSelector('h1');
|
||||
await lecksuche('gesperrt');
|
||||
|
||||
console.log('\n2) Ausbilder gibt frei');
|
||||
await abmelden();
|
||||
await anmelden(AUSBILDER);
|
||||
await seite.goto(`${BASIS}/kontrollen`);
|
||||
await seite.waitForSelector('.kontrollzeile');
|
||||
await seite.locator('.kontrollzeile', { hasText: 'Woche 1' }).locator('button:has-text("Freigeben")').click();
|
||||
await seite.waitForTimeout(1500);
|
||||
|
||||
console.log('\n3) Nach der Freigabe, vor der Abgabe – der entscheidende Fall');
|
||||
await abmelden();
|
||||
await anmelden(AZUBI);
|
||||
await seite.goto(`${BASIS}/kontrollen/woche-01`);
|
||||
await seite.waitForSelector('.frage-text');
|
||||
console.log(` Fragen sichtbar: ${(await seite.$$('.frage-text')).length}`);
|
||||
const leck = await lecksuche('freigegeben, nicht abgegeben');
|
||||
|
||||
console.log('\n4) Nach dem Zwischenspeichern einer Antwort');
|
||||
await seite.locator('textarea[id^=antwort-]').first().fill('Person, Gerät, Fehlerbild, Zeitpunkt.');
|
||||
await seite.waitForTimeout(1600);
|
||||
await seite.reload();
|
||||
await seite.waitForSelector('.frage-text');
|
||||
const leck2 = await lecksuche('nach Zwischenspeichern');
|
||||
|
||||
console.log('\n5) Nach der Abgabe muss sie da sein');
|
||||
await seite.click('button:has-text("Kontrolle abgeben")');
|
||||
await seite.waitForTimeout(2500);
|
||||
await seite.reload();
|
||||
await seite.waitForSelector('h1');
|
||||
const nachher = await lecksuche('abgegeben');
|
||||
console.log(` Musterlösungen jetzt sichtbar: ${nachher.length} von ${bruchstuecke.length}`);
|
||||
|
||||
await browser.close();
|
||||
|
||||
const gescheitert = leck.length + leck2.length;
|
||||
console.log(`\n${gescheitert === 0 ? 'BESTANDEN' : 'DURCHGEFALLEN'}: vor der Abgabe ${gescheitert} Leck(s).`);
|
||||
process.exit(gescheitert === 0 && nachher.length === bruchstuecke.length ? 0 : 1);
|
||||
Reference in New Issue
Block a user