waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ app tests laufwaechter.test.ts

3,6 KB Rohdatei
app/tests/laufwaechter.test.ts — 115 Zeilen
1 // @vitest-environment node
2 /**
3 * Der Wächter über die laufende Prüfung.
4 *
5 * Er entscheidet, ob das Fenster beim Schließen nachfragt. Bis Fassung 0.24.1
6 * hatte er **keinen einzigen Test** – weder hier noch in Playwright –, obwohl
7 * an ihm zwei gegenläufige Fehler hängen: Vergisst er zu früh, geht ein
8 * Prüfungsbogen ohne Rückfrage verloren; vergisst er zu spät, hängt das
9 * Fenster für immer an einer Frage zu einer Prüfung, die es nicht mehr gibt.
10 *
11 * Geprüft wird gegen Attrappen von `WebContents` und `BrowserWindow`: Der
12 * Wächter benutzt von beiden nur `id` und `isDestroyed()`, und ein echtes
13 * Electron-Fenster für diese Rechnung zu starten wäre teuer ohne Gewinn.
14 */
15
16 import { beforeEach, describe, expect, it } from 'vitest';
17
18 import type { BrowserWindow, WebContents } from 'electron';
19
20 import {
21 laeuftPruefung,
22 laufMelden,
23 laufVergessen,
24 laufwaechterLeeren,
25 } from '../src/main/laufwaechter';
26
27 /** Nur die beiden Felder, die der Wächter anfasst. */
28 function inhalt(id: number, zerstoert = false): WebContents {
29 return { id, isDestroyed: () => zerstoert } as unknown as WebContents;
30 }
31
32 function fenster(webContents: WebContents): BrowserWindow {
33 return { webContents } as unknown as BrowserWindow;
34 }
35
36 beforeEach(() => {
37 laufwaechterLeeren();
38 });
39
40 describe('Laufwächter', () => {
41 it('meldet ohne jede Meldung keine laufende Prüfung', () => {
42 expect(laeuftPruefung(fenster(inhalt(1)))).toBe(false);
43 });
44
45 it('merkt sich eine laufende Prüfung', () => {
46 const eins = inhalt(1);
47 laufMelden(eins, true);
48
49 expect(laeuftPruefung(fenster(eins))).toBe(true);
50 });
51
52 /*
53 Der Renderer schickt seinen Zustand auch beim Aufbau – also `false` nach
54 einem Neuladen. Ein Wächter, der nur Kanten meldete, bliebe hängen.
55 */
56 it('nimmt den Merker auf eine Meldung „läuft nicht“ zurück', () => {
57 const eins = inhalt(1);
58 laufMelden(eins, true);
59 laufMelden(eins, false);
60
61 expect(laeuftPruefung(fenster(eins))).toBe(false);
62 });
63
64 it('verträgt dieselbe Meldung mehrfach', () => {
65 const eins = inhalt(1);
66 laufMelden(eins, true);
67 laufMelden(eins, true);
68 laufMelden(eins, false);
69
70 expect(laeuftPruefung(fenster(eins))).toBe(false);
71 });
72
73 it('hält die Fenster auseinander', () => {
74 /* Zwei Fenster sind erreichbar – die Hilfe ist zwar ein Dialog, aber ein
75 zweiter Programmstart legt ein eigenes an. Der Merker des einen darf
76 das andere nicht betreffen. */
77 const eins = inhalt(1);
78 const zwei = inhalt(2);
79 laufMelden(eins, true);
80
81 expect(laeuftPruefung(fenster(eins))).toBe(true);
82 expect(laeuftPruefung(fenster(zwei))).toBe(false);
83 });
84
85 it('vergisst den Merker bei neuem Dokument oder Absturz', () => {
86 const eins = inhalt(1);
87 laufMelden(eins, true);
88 laufVergessen(eins);
89
90 expect(laeuftPruefung(fenster(eins))).toBe(false);
91 });
92
93 /*
94 Die zweite, unabhängige Sperre: Ein zerstörtes `webContents` liefert
95 niemals „es läuft eine Prüfung“. Ohne sie könnte ein abgestürzter Renderer
96 das Fenster unschließbar machen – und der Nutzer säße vor einem Fenster,
97 das weder arbeitet noch zugeht.
98 */
99 it('meldet für ein zerstörtes Fenster nie eine laufende Prüfung', () => {
100 const eins = inhalt(1);
101 laufMelden(eins, true);
102
103 expect(laeuftPruefung(fenster(inhalt(1, true)))).toBe(false);
104 });
105
106 it('räumt mit „leeren“ alles weg', () => {
107 laufMelden(inhalt(1), true);
108 laufMelden(inhalt(2), true);
109
110 laufwaechterLeeren();
111
112 expect(laeuftPruefung(fenster(inhalt(1)))).toBe(false);
113 expect(laeuftPruefung(fenster(inhalt(2)))).toBe(false);
114 });
115 });