Upload via GUI (69 Dateien)

This commit is contained in:
2026-10-16 18:53:04 +00:00
parent e6d437ecf9
commit 7d82ca66ac
50 changed files with 8916 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
// UI-Tests der Desktop-App: lädt test/mock.html in einem unsichtbaren Electron-Fenster
// (mit Mock-API statt Server) und steuert die echte Oberfläche per Skript.
// Start: npm test
const { app, BrowserWindow } = require('electron');
const path = require('path');
const failures = [];
let passed = 0;
const consoleErrors = [];
function check(name, ok, detail) {
if (ok) { passed++; console.log(' ok ' + name); }
else { failures.push(name); console.log(' FAIL ' + name + (detail ? ' – ' + detail : '')); }
}
app.whenReady().then(async () => {
const win = new BrowserWindow({ show: false, width: 1280, height: 800, webPreferences: { contextIsolation: false, nodeIntegration: false } });
win.webContents.on('console-message', (_e, level, message) => { if (level >= 3) consoleErrors.push(message); });
win.webContents.on('render-process-gone', (_e, d) => { failures.push('Renderer abgestürzt: ' + d.reason); });
const run = (code) => win.webContents.executeJavaScript(code);
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const waitFor = async (code, ms = 4000) => {
const end = Date.now() + ms;
while (Date.now() < end) { if (await run(code).catch(() => false)) return true; await wait(50); }
return false;
};
try {
await win.loadFile(path.join(__dirname, 'mock.html'));
// Mock-Routen, die für die Admin-Seiten fehlen, liefern eine leere Liste statt eines Fehlers
await run(`(() => { const o = window.deskhub.api; window.deskhub.api = async (r) => { const res = await o(r); return res.error && /^Mock:/.test(res.error.message) ? { data: { items: [], rules: [], holidays: [], hours: [], staffOptions: [], departments: [], permissionKeys: [], fieldOptions: [], operatorOptions: [], actionOptions: [] } } : res; }; })()`);
console.log('Start & Navigation');
check('App startet und zeigt das Hauptgerüst', await waitFor(`!!document.querySelector('.side') && !!document.getElementById('main')`));
check('Seitenleiste enthält Hauptpunkte', await run(`['Übersicht','Tickets','Kunden'].every(t => document.querySelector('.side').innerText.includes(t))`));
await run(`go('dashboard')`);
check('Dashboard zeigt Kennzahlen', await waitFor(`document.getElementById('main').innerText.includes('Drucker druckt nicht')`));
await run(`go('tickets')`);
check('Ticketliste zeigt alle Tickets', await waitFor(`['Drucker druckt nicht','Passwort zurücksetzen','Rechnung fehlt','VPN Verbindung bricht ab'].every(t => document.getElementById('main').innerText.includes(t))`));
check('Gespeicherte Ansicht erscheint als Chip', await run(`document.getElementById('main').innerText.includes('Meine überfälligen')`));
await run(`go('ticket', 1)`);
check('Ticketdetail zeigt Betreff und Verlauf', await waitFor(`['Drucker druckt nicht', 'Mein Drucker druckt nichts mehr', 'Treiber prüfen'].every(x => document.getElementById('main').innerText.includes(x))`));
check('Ticketdetail zeigt Eigenschaften und Aktionen', await run(`['eigenschaften', 'schließen'].every(x => document.getElementById('main').innerText.toLowerCase().includes(x))`));
check('Interne Notiz ist gekennzeichnet', await run(`!!document.querySelector('.thread.note')`));
await run(`go('reports')`);
check('Berichte laden Tabelle mit Summen', await waitFor(`['Technik', 'Vertrieb', '59'].every(x => document.getElementById('main').innerText.includes(x))`));
console.log('Verwaltung');
await run(`state.staff.role = 'admin'`);
const sections = await run(`adminSections().map(s => s.key)`);
check('Verwaltungsbereiche vorhanden', sections.length >= 10, 'gefunden: ' + sections.length);
for (const key of sections) {
await run(`go('admin', '${key}')`);
const ok = await waitFor(`document.getElementById('main').children.length > 0 && !document.querySelector('#main .warnbox')`, 3000);
check('Verwaltung „' + key + '“ rendert ohne Fehler', ok, await run(`(document.querySelector('#main .warnbox')||{}).innerText || ''`));
}
console.log('Theme');
await run(`window.deskhub.setSettings({ theme: 'light' }).then(() => { state.prefs = { ...state.prefs, theme: 'light' }; applyTheme(); })`);
check('Hell-Modus setzt data-theme', await waitFor(`document.documentElement.dataset.theme === 'light'`));
await run(`window.deskhub.setSettings({ theme: 'dark' }).then(() => { state.prefs = { ...state.prefs, theme: 'dark' }; applyTheme(); })`);
check('Dunkel-Modus setzt data-theme', await waitFor(`document.documentElement.dataset.theme === 'dark'`));
console.log('Verbindung & Überwachung');
await run(`go('dashboard')`);
await run(`window.__origApi = window.deskhub.api; window.deskhub.api = async () => ({ error: { code: 'NETWORK', status: 0, message: 'Server nicht erreichbar.' } }); pollActivity()`);
check('Fehlende Verbindung zeigt Banner', await waitFor(`document.getElementById('banners').innerText.includes('Keine Verbindung zum Server')`, 6000));
check('Banner bietet „Jetzt erneut versuchen“', await run(`document.getElementById('banners').innerText.includes('Jetzt erneut versuchen')`));
await run(`window.deskhub.api = window.__origApi; retryNow()`);
check('Banner verschwindet nach Wiederherstellung', await waitFor(`!document.getElementById('banners').innerText.includes('Keine Verbindung zum Server')`, 6000));
await run(`window.__health = [{ level: 'error', code: 'mailbox_down', message: 'Postfach „support@example.de“ ist nicht erreichbar.' }]; pollActivity()`);
check('Serverstörung (Mailabruf) wird als Banner gezeigt', await waitFor(`document.getElementById('banners').innerText.includes('support@example.de')`, 6000));
check('Keine JavaScript-Fehler in der Konsole', consoleErrors.length === 0, consoleErrors.slice(0, 3).join(' | '));
} catch (e) {
failures.push('Testlauf abgebrochen: ' + e.message);
console.log(' FAIL ' + e.message);
}
console.log(`\n${passed} bestanden, ${failures.length} fehlgeschlagen`);
app.exit(failures.length ? 1 : 0);
});