Files
Git-Manager-Gui/scripts/ui-smoke-tray.js
T
2026-10-22 09:13:21 +00:00

102 lines
4.9 KiB
JavaScript

// Teil des UI-Testlaufs (scripts/ui-smoke.js): prüft das Tray-Menüfenster in echtem Electron, ohne das
// Tray-Symbol selbst. Zeigt das Fenster, fährt mit der Maus darüber, klickt, drückt Esc.
// Gibt „✓ …“ und „✗ …“ Zeilen aus; Aufruf durch ui-smoke.js.
const { app } = require('electron');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const { createTrayPopup } = require(path.join(ROOT, 'src', 'features', 'trayPopup.js'));
const trayMenu = require(path.join(ROOT, 'src', 'features', 'trayMenu.js'));
let failed = 0;
function check(name, ok, detail = '') {
if (!ok) failed++;
console.log(`${ok ? '✓' : '✗'} ${name}${detail ? ` — ${detail}` : ''}`);
}
app.disableHardwareAcceleration();
app.on('window-all-closed', (e) => e.preventDefault());
app.whenReady().then(async () => {
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const log = [];
let active = 1;
const template = () => trayMenu.buildTrayTemplate({
version: '0.0.0', active, queued: 2, paused: false, autostart: true,
onOpen: () => log.push('open'), onHistory: () => log.push('history'), onPause: () => log.push('pause'),
onCancel: () => log.push('cancel'), onAutostart: () => log.push('autostart'), onQuit: () => log.push('quit')
});
const popup = createTrayPopup({
htmlPath: path.join(ROOT, 'renderer', 'tray-menu.html'),
preloadPath: path.join(ROOT, 'tray-menu-preload.js'),
getModel: () => trayMenu.serializeTemplate(template()),
onAction: (id) => trayMenu.runAction(template(), id)
});
const js = (code) => popup.getWindow().webContents.executeJavaScript(code);
const items = async () => JSON.parse(await js(`JSON.stringify([...document.querySelectorAll('.item')].map(b => { const r = b.getBoundingClientRect(); return { text: b.innerText.trim(), disabled: b.disabled, x: r.x, y: r.y, h: r.height }; }))`));
const mid = (i) => ({ x: Math.round(i.x + 40), y: Math.round(i.y + i.h / 2) });
const bg = (label) => js(`(() => { const b = [...document.querySelectorAll('.item')].find(x => x.innerText.includes(${JSON.stringify(label)})); return getComputedStyle(b).backgroundColor; })()`);
const mouse = (type, p, extra = {}) => popup.getWindow().webContents.sendInputEvent({ type, x: p.x, y: p.y, ...extra });
try {
popup.warmUp();
await wait(6000); // erster Renderer-Start dauert mehrere Sekunden
popup.show();
await wait(800);
check('Menüfenster wird sichtbar', popup.isVisible());
let list = await items();
check('Menü zeigt Einträge mit Pausieren und Abbrechen',
['Fenster öffnen', 'Upload-Verlauf', 'Übertragung pausieren', 'Laufende Übertragung abbrechen', 'Beenden'].every((t) => list.some((i) => i.text.includes(t))));
// Hover folgt der Maus
const history = list.find((i) => i.text.includes('Upload-Verlauf'));
// Das frisch geöffnete Fenster braucht einen Moment, bis es sein erstes Bild gezeichnet hat und Hover annimmt.
let hovered = 'rgba(0, 0, 0, 0)';
for (let i = 0; i < 12 && hovered === 'rgba(0, 0, 0, 0)'; i++) {
mouse('mouseMove', { x: mid(history).x + (i % 2), y: mid(history).y });
await wait(250);
hovered = await bg('Upload-Verlauf');
}
const other = await bg('Fenster öffnen');
check('Hover markiert den Eintrag unter der Maus', hovered !== 'rgba(0, 0, 0, 0)' && other === 'rgba(0, 0, 0, 0)', `${hovered} / ${other}`);
// Gesperrter Eintrag bleibt unmarkiert und löst nichts aus
active = 0; popup.refresh(); await wait(400);
list = await items();
const cancel = list.find((i) => i.text.includes('abbrechen'));
mouse('mouseMove', mid(cancel));
await wait(300);
check('Gesperrter Eintrag wird nicht markiert', cancel.disabled && (await bg('abbrechen')) === 'rgba(0, 0, 0, 0)');
mouse('mouseDown', mid(cancel), { button: 'left', clickCount: 1 });
mouse('mouseUp', mid(cancel), { button: 'left', clickCount: 1 });
await wait(400);
check('Klick auf gesperrten Eintrag löst keine Aktion aus', log.length === 0 && popup.isVisible());
// Klick führt die Aktion aus und schließt das Fenster
const open = list.find((i) => i.text.includes('Fenster öffnen'));
mouse('mouseMove', mid(open));
mouse('mouseDown', mid(open), { button: 'left', clickCount: 1 });
mouse('mouseUp', mid(open), { button: 'left', clickCount: 1 });
await wait(600);
check('Klick führt die Aktion aus und schließt das Menü', log.join() === 'open' && !popup.isVisible());
// Esc schließt
popup.show();
await wait(900);
const reopened = popup.isVisible();
const win = popup.getWindow();
win.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' });
win.webContents.sendInputEvent({ type: 'keyUp', keyCode: 'Escape' });
await wait(500);
check('Esc schließt das Menü', reopened && !popup.isVisible());
} catch (e) {
check('Menüfenster-Test ohne Ausnahme', false, e.message);
}
popup.destroy();
app.exit(failed ? 1 : 0);
});