From 227f7ca95f8cd38b95311c1a89816b252b17a09c Mon Sep 17 00:00:00 2001 From: yoniebans Date: Tue, 25 Aug 2026 09:47:23 +0300 Subject: [PATCH] fix(install-e2e): nudge Check now until Update now appears The boot-time auto-check can fail transiently and latch the error UI even though a fresh check succeeds. Click Check now whenever it is clickable, re-test Update now, 3 minute ceiling. On final failure, pull the update status over the same IPC the About panel uses so the log carries the real git error instead of the UI's generic one. --- tests/install/e2e-assets/drive-update.cjs | 26 ++++++++++++----- tests/install/e2e-assets/launch-from-spec.mjs | 29 ++++++++++++++++++- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/tests/install/e2e-assets/drive-update.cjs b/tests/install/e2e-assets/drive-update.cjs index ac01da8539..edf4838e1b 100644 --- a/tests/install/e2e-assets/drive-update.cjs +++ b/tests/install/e2e-assets/drive-update.cjs @@ -239,18 +239,28 @@ async function main() { let visible = await updateNow.isVisible().catch(() => false) if (!visible) { - log('Update now not visible yet — clicking Check now') - await clickFirstVisible(page, [p => p.getByRole('button', { name: 'Check now' })], 'Check now', 20_000) - - try { - await updateNow.waitFor({ state: 'visible', timeout: 120_000 }) - visible = true - } catch { - visible = false + // The boot-time auto-check can fail transiently and latch the error + // UI, while a fresh check succeeds. Nudge loop: click Check now when + // clickable, re-test Update now, 3 minute ceiling. + log('Update now not visible yet — nudging Check now') + const deadline = Date.now() + 180_000 + while (!visible && Date.now() < deadline) { + await page.getByRole('button', { name: 'Check now' }).first() + .click({ timeout: 5_000 }) + .then(() => log('nudged Check now')) + .catch(() => {}) + await page.waitForTimeout(15_000) + visible = await updateNow.isVisible().catch(() => false) } } if (!visible) { + // Surface the real git error behind the UI's generic "couldn't reach + // the update server" line. + const status = await page.evaluate(() => + window.hermesDesktop?.updates?.check?.() ?? Promise.resolve('no updates.check bridge') + ).catch((err) => `updates.check failed: ${err?.message || err}`) + log(`[update-status] ${JSON.stringify(status)}`) await shot(page, 'ERROR-no-update-now') throw new Error('"Update now" never appeared — update check did not report behind > 0') } diff --git a/tests/install/e2e-assets/launch-from-spec.mjs b/tests/install/e2e-assets/launch-from-spec.mjs index 0781f5203e..7dbf064e19 100644 --- a/tests/install/e2e-assets/launch-from-spec.mjs +++ b/tests/install/e2e-assets/launch-from-spec.mjs @@ -212,7 +212,34 @@ async function main() { await window.getByRole('tab', { name: /about/i }).or( window.getByRole('button', { name: /about/i })).first().click(); const updateNow = window.getByRole('button', { name: /update now/i }).first(); - await updateNow.waitFor({ state: 'visible', timeout: 60_000 }); + // "Update now" only renders once a check reports behind > 0, and the + // About panel starts at "Last checked: never". The boot-time auto-check + // can also fail transiently and latch the error UI, while a fresh check + // succeeds. Nudge like an impatient user: click Check now whenever it is + // clickable (not a spinner), re-test Update now, 3 minute ceiling. + const checkNow = window.getByRole('button', { name: /check now/i }).first(); + const nudgeDeadline = Date.now() + 180_000; + let updateVisible = await updateNow.isVisible().catch(() => false); + while (!updateVisible && Date.now() < nudgeDeadline) { + await checkNow.click({ timeout: 5_000 }) + .then(() => log('nudged Check now')) + .catch(() => {}); // spinner or mid-transition - fine, just wait + await window.waitForTimeout(15_000); + updateVisible = await updateNow.isVisible().catch(() => false); + } + try { + await updateNow.waitFor({ state: 'visible', timeout: 15_000 }); + } catch (e) { + // The About UI flattens every check failure to a generic "couldn't + // reach the update server", hiding the git stderr the main process + // captured. Pull the full status over the same IPC the panel uses so + // the log names the real error. + const status = await window.evaluate(() => + window.hermesDesktop?.updates?.check?.() ?? Promise.resolve('no updates.check bridge') + ).catch((err) => `updates.check failed: ${err?.message || err}`); + log(`[update-status] ${JSON.stringify(status)}`); + throw e; + } await updateNow.click(); log('clicked Update now; polling for result file');