From 16ad2ad379ad93518f7679734675cd1a24809d5f Mon Sep 17 00:00:00 2001 From: Sucukdeluxe <259325684+Sucukdeluxe@users.noreply.github.com> Date: Tue, 22 Sep 2026 06:37:15 +0200 Subject: [PATCH] Synchronize Electron test assertions with completed input and queue events --- PROJECT_MEMORY.md | 1 + tests/startup-renderer.test.js | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/PROJECT_MEMORY.md b/PROJECT_MEMORY.md index f3dd4d1..fb11fc0 100644 --- a/PROJECT_MEMORY.md +++ b/PROJECT_MEMORY.md @@ -98,6 +98,7 @@ npm audit --omit=dev ## Zuletzt verifiziert +- CI-Timingkorrektur nach `2.1.50`: Checkbox-Test wartet begrenzt auf native Klick-, Tab- und Leertastenverarbeitung und meldet bei Zeitüberschreitung Aktion und letzten Zustand; Hintergrunddrosselung im isolierten Testfenster deaktiviert. Start-/Reload-Test akzeptiert einen leeren, noch nicht belieferten Renderer nicht mehr als abgeschlossen, sondern wartet auf den Dateikandidaten und die abgearbeitete Ereigniswarteschlange. Bestehende Zustands-, Fokus-, Stil-, Duplikat- und Generationenprüfungen unverändert. Beide betroffenen Tests zehnmal hintereinander erfolgreich; Lint und 18 Servertests erfolgreich. Reine Teständerung, kein App-Release erforderlich. - Release `2.1.50`: englischer GitHub- und inhaltlich gleichwertiger deutscher Forgejo-Changelog mit allen Änderungen seit `2.1.49`, Titel, Tag, jeweils vier Assets und Update-Metadaten verifiziert. Alle acht veröffentlichten Assets erneut heruntergeladen und per Größe/SHA-512 mit lokalen Dateien verglichen. Echter Updater mit Version `2.1.49` erkennt `2.1.50`, akzeptiert englische Release Notes, gültigen Veröffentlichungszeitpunkt und Forgejo-Manifest. Installer 98.034.441 Bytes, Portable 97.809.731 Bytes; beide Produktversion `2.1.50`. Öffentlicher Quellcheck einschließlich Screenshots erfolgreich (164 Dateien). Release-Commit `e51a4c5`, annotierter Tag `0c32d9a` auf beiden Remotes identisch. Lokaler Update-Anzeigetest vollständig entfernt; keine produktive Serveränderung. - Releasevorbereitung `2.1.50`: 845 Haupttests und 18 Backup-API-Tests erfolgreich, Lint erfolgreich, Produktionsaudit ohne Schwachstellen. Ausführliche englische/deutsche Release-Texte decken Änderungen seit `2.1.49` ab. Lokale Update-Simulation deaktiviert; Entwicklungslauncher verwendet wieder den echten Updater. Keine produktive Serveränderung erforderlich. - Update-Dialog nach `2.1.49`: Versionsmeldung von 12 auf 14 px erhöht. Updater reicht `published_at` als `publishedAt` weiter; Anzeige ergänzt lokale Veröffentlichungszeit als `TT.MM.JJJJ - HH:mm`, fehlende/ungültige Werte bleiben ausgeblendet. Deutsche und englische Übersetzung mit Datum geprüft. 40 Übersetzungs-/Updater-Tests, zwei gezielte Renderer-Tests und Lint ohne Warnungen erfolgreich. Laufende Entwicklung zeigt im lokalen Test `Update v2.1.50 verfügbar (22.09.2026 - 19:30)`; kein Release veröffentlicht. diff --git a/tests/startup-renderer.test.js b/tests/startup-renderer.test.js index 4bd4979..79d62ff 100644 --- a/tests/startup-renderer.test.js +++ b/tests/startup-renderer.test.js @@ -44,15 +44,25 @@ const fs = require('node:fs'); const assert = require('node:assert/strict'); app.whenReady().then(async () => { const css = fs.readFileSync(process.env.MHU_CHECKBOX_CSS, 'utf8'); - const win = new BrowserWindow({ show: false, width: 500, height: 400 }); + const win = new BrowserWindow({ show: false, width: 500, height: 400, webPreferences: { backgroundThrottling: false } }); const wc = win.webContents; + async function waitForState(expression, accepts, action) { + const deadline = Date.now() + 3000; + let state; + do { + state = await wc.executeJavaScript(expression); + if (accepts(state)) return state; + await new Promise(resolve => setTimeout(resolve, 20)); + } while (Date.now() < deadline); + throw new Error(action + ' did not complete: ' + JSON.stringify(state)); + } await win.loadURL('data:text/html;charset=utf-8,' + encodeURIComponent('')); wc.focus(); const point = await wc.executeJavaScript('(() => { const r = document.getElementById("check").getBoundingClientRect(); return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) }; })()'); for (const expected of [true, false]) { wc.sendInputEvent({ type: 'mouseDown', button: 'left', clickCount: 1, ...point }); wc.sendInputEvent({ type: 'mouseUp', button: 'left', clickCount: 1, ...point }); - const state = await wc.executeJavaScript('(() => { const c = document.getElementById("check"); const s = getComputedStyle(c); return { checked: c.checked, shadow: s.boxShadow, outline: s.outlineStyle }; })()'); + const state = await waitForState('(() => { const c = document.getElementById("check"); const s = getComputedStyle(c); return { checked: c.checked, shadow: s.boxShadow, outline: s.outlineStyle }; })()', state => state.checked === expected, 'Checkbox mouse click'); assert.equal(state.checked, expected); assert.equal(state.shadow, 'none'); assert.equal(state.outline, 'none'); @@ -60,13 +70,13 @@ app.whenReady().then(async () => { await wc.executeJavaScript('document.getElementById("before").focus()'); wc.sendInputEvent({ type: 'keyDown', keyCode: 'Tab' }); wc.sendInputEvent({ type: 'keyUp', keyCode: 'Tab' }); - const keyboard = await wc.executeJavaScript('(() => { const c = document.getElementById("check"); return { active: document.activeElement === c, visible: c.matches(":focus-visible"), outline: getComputedStyle(c).outlineStyle }; })()'); + const keyboard = await waitForState('(() => { const c = document.getElementById("check"); return { active: document.activeElement === c, visible: c.matches(":focus-visible"), outline: getComputedStyle(c).outlineStyle }; })()', state => state.active, 'Checkbox Tab focus'); assert.equal(keyboard.active, true); assert.equal(keyboard.visible, true); assert.notEqual(keyboard.outline, 'none'); wc.sendInputEvent({ type: 'keyDown', keyCode: 'Space' }); wc.sendInputEvent({ type: 'keyUp', keyCode: 'Space' }); - assert.equal(await wc.executeJavaScript('document.getElementById("check").checked'), true); + assert.equal(await waitForState('document.getElementById("check").checked', checked => checked, 'Checkbox Space toggle'), true); assert.notEqual(await wc.executeJavaScript('document.getElementById("number").focus(); getComputedStyle(document.getElementById("number")).boxShadow'), 'none'); win.destroy(); fs.writeFileSync(process.env.MHU_CHECKBOX_RESULT, JSON.stringify({ ok: true })); @@ -4889,7 +4899,7 @@ async function waitFor(read, timeoutMs = 20000) { rendererState = await waitFor(async () => { try { const state = await window.webContents.executeJavaScript("(() => { if (typeof queueJobs === 'undefined' || typeof automationEventQueue === 'undefined') return null; return { candidateNames: queueJobs.filter(job => job.fileName === 'scenario-ready.mkv').map(job => job.fileName), draining: Boolean(automationEventDrainPromise), pendingCandidates: automationEventQueue.size }; })()"); - return state && !state.draining && state.pendingCandidates === 0 ? state : null; + return state && state.candidateNames.length > 0 && !state.draining && state.pendingCandidates === 0 ? state : null; } catch { return null; }