Upload via GUI (85 Dateien)

This commit is contained in:
2026-10-22 09:13:16 +00:00
parent ce5a655758
commit 2ad8777311
19 changed files with 1429 additions and 135 deletions
+133
View File
@@ -0,0 +1,133 @@
const test = require('node:test');
const assert = require('node:assert');
const { buildTrayTemplate, trayTooltip } = require('../src/features/trayMenu.js');
const noop = () => {};
const base = { version: '2.2.1', onOpen: noop, onHistory: noop, onCancel: noop, onAutostart: noop, onQuit: noop };
const labels = (tpl) => tpl.filter(i => i.label).map(i => i.label);
const find = (tpl, label) => tpl.find(i => i.label === label);
test('Tooltip nennt Version und zeigt eine laufende Übertragung', () => {
assert.strictEqual(trayTooltip('2.2.1', 0), 'Git Manager Explorer Pro v2.2.1');
assert.match(trayTooltip('2.2.1', 2), /Übertragung läuft/);
assert.match(trayTooltip('2.2.1', 1, true), /Übertragung pausiert/);
assert.strictEqual(trayTooltip('2.2.1', 0, true), 'Git Manager Explorer Pro v2.2.1');
});
test('Menü im Ruhezustand: Kopfzeile, Status, Aktionen; Abbrechen gesperrt', () => {
const tpl = buildTrayTemplate(base);
assert.deepStrictEqual(labels(tpl), [
'Git Manager Explorer Pro v2.2.1',
'Keine laufende Übertragung',
'Fenster öffnen',
'Upload-Verlauf',
'Übertragung pausieren',
'Laufende Übertragung abbrechen',
'Mit Windows starten',
'Beenden'
]);
assert.strictEqual(find(tpl, 'Laufende Übertragung abbrechen').enabled, false);
assert.strictEqual(tpl[0].enabled, false);
});
test('Menü bei laufender Übertragung: Zähler, Abbrechen freigeschaltet', () => {
const one = buildTrayTemplate({ ...base, active: 1 });
assert.ok(labels(one).includes('1 Übertragung läuft'));
assert.strictEqual(find(one, 'Laufende Übertragung abbrechen').enabled, true);
assert.ok(labels(buildTrayTemplate({ ...base, active: 3 })).includes('3 Übertragungen laufen'));
});
test('Retry-Queue erscheint nur, wenn etwas wartet', () => {
assert.ok(!labels(buildTrayTemplate(base)).some(l => l.startsWith('Retry-Queue')));
assert.ok(labels(buildTrayTemplate({ ...base, queued: 4 })).includes('Retry-Queue: 4 wartend'));
});
test('Autostart ist ein Häkchen und spiegelt den Zustand', () => {
assert.strictEqual(find(buildTrayTemplate({ ...base, autostart: true }), 'Mit Windows starten').checked, true);
const off = find(buildTrayTemplate(base), 'Mit Windows starten');
assert.strictEqual(off.type, 'checkbox');
assert.strictEqual(off.checked, false);
});
test('Einträge rufen die übergebenen Aktionen auf', () => {
const calls = [];
const tpl = buildTrayTemplate({
...base,
active: 1,
onOpen: () => calls.push('open'),
onHistory: () => calls.push('history'),
onCancel: () => calls.push('cancel'),
onQuit: () => calls.push('quit')
});
for (const l of ['Fenster öffnen', 'Upload-Verlauf', 'Laufende Übertragung abbrechen', 'Beenden']) find(tpl, l).click();
assert.deepStrictEqual(calls, ['open', 'history', 'cancel', 'quit']);
});
const { serializeTemplate, runAction } = require('../src/features/trayMenu.js');
const { computePosition } = require('../src/features/trayPopup.js');
test('serializeTemplate: nur Daten, keine Funktionen, Trenner bleiben erhalten', () => {
const plain = serializeTemplate(buildTrayTemplate({ ...base, active: 1, autostart: true }));
assert.ok(plain.every(i => Object.values(i).every(v => typeof v !== 'function')));
assert.strictEqual(plain.filter(i => i.type === 'separator').length, 3);
const cancel = plain.find(i => i.id === 'cancel');
assert.deepStrictEqual(cancel, { id: 'cancel', label: 'Laufende Übertragung abbrechen', type: 'normal', enabled: true, checked: false });
assert.strictEqual(plain.find(i => i.id === 'autostart').checked, true);
assert.doesNotThrow(() => JSON.stringify(plain));
});
test('runAction: führt Aktionen per id aus, Häkchen wird umgeschaltet', () => {
const calls = [];
const tpl = buildTrayTemplate({
...base,
active: 1,
autostart: false,
onOpen: () => calls.push('open'),
onAutostart: (item) => calls.push(`autostart:${item.checked}`)
});
assert.strictEqual(runAction(tpl, 'open'), true);
assert.strictEqual(runAction(tpl, 'autostart'), true);
assert.deepStrictEqual(calls, ['open', 'autostart:true']);
});
test('runAction: gesperrte oder unbekannte Einträge tun nichts', () => {
let cancelled = false;
const tpl = buildTrayTemplate({ ...base, active: 0, onCancel: () => { cancelled = true; } });
assert.strictEqual(runAction(tpl, 'cancel'), false);
assert.strictEqual(runAction(tpl, 'gibt-es-nicht'), false);
assert.strictEqual(runAction(tpl, 'header'), false);
assert.strictEqual(cancelled, false);
});
test('computePosition: Menü bleibt im sichtbaren Bereich', () => {
const wa = { x: 0, y: 0, width: 1920, height: 1040 };
// Zeiger in der Taskleiste unten rechts: Menü sitzt direkt über der Taskleiste, nicht außerhalb rechts
const bottomRight = computePosition({ x: 1900, y: 1060 }, wa, 286, 300);
assert.strictEqual(bottomRight.y, 1040 - 300 - 8);
assert.ok(bottomRight.x + 286 <= 1920 - 8);
// Zeiger weit links: nicht links aus dem Bildschirm
assert.ok(computePosition({ x: 2, y: 1060 }, wa, 286, 300).x >= 8);
// Taskleiste oben
assert.strictEqual(computePosition({ x: 500, y: 10 }, { ...wa, y: 40, height: 1000 }, 286, 300).y, 48);
});
test('Pause: Eintrag wechselt zwischen pausieren und fortsetzen, nur bei laufender Übertragung wählbar', () => {
const idle = buildTrayTemplate(base);
assert.strictEqual(find(idle, 'Übertragung pausieren').enabled, false);
const running = buildTrayTemplate({ ...base, active: 1 });
assert.strictEqual(find(running, 'Übertragung pausieren').enabled, true);
const paused = buildTrayTemplate({ ...base, active: 2, paused: true });
assert.ok(labels(paused).includes('Übertragung fortsetzen'));
assert.ok(labels(paused).includes('2 Übertragungen pausiert'));
assert.ok(!labels(paused).includes('Übertragung pausieren'));
assert.ok(labels(buildTrayTemplate({ ...base, active: 1, paused: true })).includes('1 Übertragung pausiert'));
});
test('Pause-Eintrag ruft onPause auf', () => {
const calls = [];
const tpl = buildTrayTemplate({ ...base, active: 1, onPause: () => calls.push('pause') });
assert.strictEqual(runAction(tpl, 'pause'), true);
assert.deepStrictEqual(calls, ['pause']);
});