Files
epaper-dashboard/tests/test_autopack_undo.js
T
ki a465912b55 BUG-06: Auto-Pack Undo via Snapshot + actionable Toast
Auto-Pack rief vorher layout_mod.pack() auf und schickte einen
simplen success-Toast. Wer aus Versehen klickte, hatte alle
manuellen Positionen verloren — kein Undo, kein Recovery.

Fix:
- packAll() speichert layoutItems als JSON-Snapshot in einer
  local closure (vor dem pack-Call).
- Nach erfolgreichem Pack: toast() bekommt einen 4. Parameter
  action={label, onClick}.
- Neues toast()-Feature: action-Button im Toast, clickbar trotz
  dismiss-on-click. Klick ruft onClick und dismissed den Toast.
- Bei Undo-Klick: POST /api/layout mit den snapshot-Items →
  Server restored → renderGrid() → 'Layout wiederhergestellt'.
- Modal-Text weist auf die 10s Undo-Möglichkeit hin.

Vorteile:
- Versehentlicher Klick auf Auto-Pack ist recoverable.
- Kein sessionStorage-Bloat, kein Multi-Tab-Konflikt
  (Closure-Variable statt global Storage).
- Toast-Pattern ist jetzt generisch — andere Aktionen
  (z.B. 'Snapshot wiederherstellen' aus Sidebar) können
  denselben Mechanismus nutzen.

Beweis: tests/test_autopack_undo.js (8/8 grün)
  1. Snapshot (JSON.stringify(layoutItems)) wird erstellt
  2. Toast mit action={label:'Rückgängig'}
  3. Undo ruft POST /api/layout mit snapshot-Items
  4. Modal-Body erwähnt 'rückgängig'
  5. CSS .toast-action Klasse vorhanden
  6. toast() unterstützt 4-Args (action-Parameter)
  7. Action-Button Click ruft onClick + dismiss
  8. .toast-action hat pointer-events:auto

Live-Test: GET /?demo=1 → 200, 90847 bytes
  toast-action: 6 occurrences (CSS + JS)
  Rückgängig: 1 mention
  JSON.stringify(layoutItems): 1

Closes #8
2026-08-29 17:44:58 +04:00

59 lines
2.3 KiB
JavaScript

// BUG-06 Test: Auto-Pack Undo via Snapshot
//
// Erwartung:
// 1) packAll() speichert layoutItems als JSON vor dem Pack
// 2) Toast wird mit action={label:"Rückgängig", onClick} aufgerufen (statt nur Text)
// 3) onClick sendet POST /api/layout mit den snapshot-Items
// 4) Modal-Text erwähnt "10 Sekunden lang rückgängig"
// 5) CSS: .toast-action Klasse vorhanden
// 6) toast()-Funktion unterstützt action-Parameter (4-Args-Signatur)
const fs = require('fs');
const html = fs.readFileSync('templates/index.html', 'utf8');
const js = html.match(/<script>\s*\n([\s\S]*?)<\/script>/)[1];
function check(name, fn) {
const r = fn();
console.log((r ? '✓' : '✗') + ' ' + name);
if (!r) process.exitCode = 1;
}
// 1) Snapshot wird erstellt (JSON.stringify vor pack-Call)
check('packAll speichert Snapshot (JSON.stringify(layoutItems))', () =>
/async function packAll[\s\S]*?JSON\.stringify\(layoutItems\)/.test(js));
// 2) Toast mit action-Parameter
check('Toast wird mit action-Parameter aufgerufen', () =>
/toast\([^,]+,\s*['"]success['"],\s*\d+,\s*\{[\s\S]*?label:\s*['"]Rückgängig['"]/.test(js));
// 3) Undo-Click ruft POST /api/layout mit snapshot
check('Undo ruft POST /api/layout mit snapshot-Items', () =>
/fetch\(['"]\/api\/layout['"][\s\S]*?JSON\.parse\(snapshot\)/.test(js));
// 4) Modal-Body erwähnt Undo-Möglichkeit
check('Modal-Body erwähnt "rückgängig"', () =>
/rückgängig machen/i.test(js));
// 5) CSS: .toast-action Klasse
check('.toast-action CSS-Klasse vorhanden', () => {
const css = html.match(/<style>([\s\S]*?)<\/style>/g).join('\n');
return /\.toast-action\s*\{/.test(css);
});
// 6) toast() hat 4-Args Signatur
check('toast() unterstützt 4-Args (action-Parameter)', () =>
/function toast\(\s*text[^)]*\)\s*\{/.test(js) && /action\s*=/.test(js));
// 7) Undo-Button ruft bei Click onClick und dismissed Toast
check('Action-Button: Click ruft onClick + dismiss', () =>
/\.toast-action['"]\)\.addEventListener\(['"]click['"][\s\S]*?action\.onClick\(\)/.test(js));
// 8) Pointer-events:auto auf Action-Button (sonst klickt Toast-Click-Handler)
check('.toast-action hat pointer-events:auto', () => {
const css = html.match(/<style>([\s\S]*?)<\/style>/g).join('\n');
return /\.toast-action\s*\{[^}]*pointer-events:\s*auto/.test(css);
});
console.log('\n========');
process.exit(process.exitCode || 0);