fix(e2e): detect update hand-off via marker file, not Playwright close event

Attempt 8 drove the ENTIRE GUI update click-path successfully: onboarding
dismissed, Settings opened, About opened, Update now clicked, updating
overlay shown. The hand-off log proves the real update then ran: desktop
(pid 8880) exited, venv unlocked, 'hermes update --yes --gateway --force
--branch main' fetched from serve.git, found 1 new commit, pulled, and
restored. Everything worked.

The only failure was the driver waiting on Playwright's app 'close'
event, which doesn't fire reliably when the Electron app self-quits for
the hand-off. Switch to the authoritative signal: poll for the
HERMES_HOME/.hermes-update-in-progress marker (or the result JSON, or a
genuine window-gone), which the hand-off writes ~4s after the click. The
PowerShell driver still owns asserting the OUTCOME (target sha, marker
cleanup, working hermes, relaunched app) after the driver returns.
This commit is contained in:
Teknium
2026-08-11 03:01:52 -07:00
committed by ethernet
parent 31b97289ae
commit 7ffc26ec56
+55 -11
View File
@@ -201,20 +201,64 @@ async function main() {
await page.waitForTimeout(1200)
await shot(page, '05-updating-overlay')
// ── Wait for the app to quit for the hand-off ─────────────────────────
await new Promise((resolve, reject) => {
const t = setTimeout(
() => reject(new Error('app did not quit within 120s of Update now — hand-off did not start')),
120_000
)
// ── Wait for the hand-off to take over ────────────────────────────────
// Clicking Update now spawns the detached updater (desktop-update.ps1 or
// the staged binary), which claims HERMES_HOME/.hermes-update-in-progress
// and then the desktop quits. We do NOT rely on Playwright's app 'close'
// event: when the app self-quits for the hand-off that event is
// unreliable (attempt 8 timed out on it even though the hand-off log
// proved the desktop had exited and `hermes update` was already running).
//
// The authoritative "hand-off started" signal is the marker file (or the
// result JSON, if the whole update finished fast). Poll for either, and
// also accept a genuine app close. Any one is success — the PowerShell
// driver owns asserting the update's OUTCOME (sha, marker cleanup,
// relaunch) after we return.
const hermesHome = process.env.HERMES_HOME
const markerPath = hermesHome ? path.join(hermesHome, '.hermes-update-in-progress') : null
const resultPath = hermesHome ? path.join(hermesHome, '.hermes-update-result.json') : null
app.on('close', () => {
clearTimeout(t)
resolve()
})
let appClosed = false
app.on('close', () => {
appClosed = true
})
log('app quit for updater hand-off — success, the detached updater owns the rest')
const handoffDeadline = Date.now() + 150_000
let handoffStarted = false
while (Date.now() < handoffDeadline) {
if (markerPath && fs.existsSync(markerPath)) {
log('hand-off marker present — updater has taken over')
handoffStarted = true
break
}
if (resultPath && fs.existsSync(resultPath)) {
log('update result JSON already present — updater finished fast')
handoffStarted = true
break
}
if (appClosed) {
log('app closed — hand-off in progress')
handoffStarted = true
break
}
// Secondary: if the renderer window is gone, evaluate throws.
try {
await page.evaluate(() => true)
} catch {
log('renderer window gone — app quit for hand-off')
handoffStarted = true
break
}
await new Promise(r => setTimeout(r, 2000))
}
if (!handoffStarted) {
await shot(page, 'ERROR-no-handoff')
throw new Error('no hand-off within 150s of Update now (no marker, no result, app still alive)')
}
log('hand-off confirmed — detached updater owns the rest')
}
main()