Files
hermes-agent/apps/desktop/scripts/click-session-helpers.test.mjs
Brooklyn Nicholson 959c7649fd fix(updates/win): click-session poll, Intel-Mac installer docs, cua-driver opt-in autostart
click-session flake (#97982): a bare scrollIntoView() smooth scroll could be dropped under load, and the script
slept a fixed 3000ms before reading state. Extract click-session-helpers.mjs:
instant centered scroll, a bounded poll-for-composer loop instead of the
fixed sleep, and correct nested CDP envelope unwrapping (the old read logged
undefined).

Intel-Mac installer docs (#99033): the Hermes-Setup.dmg bootstrap installer
is built for Apple Silicon only, so Intel Macs hit "not supported on this
Mac". The desktop release pipeline already builds a native darwin-x64
bundle, so the docs now scope the arm64 limit to the bootstrap installer and
name the darwin-x64 bundle (or the CLI plus `hermes desktop`) as the Intel
path, in the desktop README and the platform-support build-targets section.

cua-driver autostart opt-in (#97389): Windows installs registered the
cua-driver-serve scheduled task on every install, with no opt-out, and
treated the task as an install-readiness requirement. Gate the
install-ready check and _repair_cua_driver_autostart_windows on the new
computer_use.autostart config key (default false = on-demand, fails
closed), extract the registration PowerShell into a testable helper, and
document the opt-in (EN + zh-Hans). Windows-only code path: unit tests
cover the registration args and the config gate; live Windows
verification pending.
2026-09-26 17:09:16 -05:00

75 lines
2.7 KiB
JavaScript

import assert from 'node:assert/strict'
import { test } from 'vitest'
import {
buildFindClickExpression,
CLICK_POLL_TIMEOUT_MS,
evaluateJsonValue,
pollUntil,
POST_CLICK_READY_EXPRESSION
} from './click-session-helpers.mjs'
function cdpMessage(value) {
// The shape send() resolves with: the whole CDP WebSocket message.
return { id: 1, result: { result: { type: 'string', value } } }
}
test('buildFindClickExpression scrolls instantly and centered, then clicks', () => {
const expr = buildFindClickExpression('Phaser particle')
assert.ok(expr.includes("scrollIntoView({ behavior: 'auto', block: 'center' })"),
'must use an instant, centered scroll (no default smooth scroll to drop)')
assert.ok(expr.includes('found.click()'))
assert.ok(expr.includes('JSON.stringify'))
// The title must be embedded as JSON, so quotes/newlines in it cannot break
// the expression.
assert.ok(expr.includes(JSON.stringify('Phaser particle')))
})
test('evaluateJsonValue unwraps the nested CDP envelope', () => {
assert.deepEqual(evaluateJsonValue(cdpMessage('{"found":true}')), { found: true })
})
test('evaluateJsonValue returns null on a truncated envelope, not undefined', () => {
// The old script read `message.result.value` — one level short — and logged
// undefined. Any missing level must yield null.
assert.equal(evaluateJsonValue({}), null)
assert.equal(evaluateJsonValue({ result: {} }), null)
assert.equal(evaluateJsonValue({ result: { result: {} } }), null)
assert.equal(evaluateJsonValue(cdpMessage('not-json')), null)
})
function fakeSend(answers) {
let i = 0
return async () => cdpMessage(answers[Math.min(i++, answers.length - 1)])
}
test('pollUntil resolves true as soon as the predicate answers true (no fixed sleep)', async () => {
const send = fakeSend(['false', 'false', 'true'])
const started = Date.now()
assert.equal(await pollUntil(send, POST_CLICK_READY_EXPRESSION, { intervalMs: 5 }), true)
// Three polls at 5ms apart: bounded by readiness, not a fixed 3000ms sleep.
assert.ok(Date.now() - started < 500)
})
test('pollUntil returns false at the bound instead of hanging when never ready', async () => {
const send = fakeSend(['false'])
const started = Date.now()
assert.equal(
await pollUntil(send, POST_CLICK_READY_EXPRESSION, { timeoutMs: 200, intervalMs: 50 }),
false
)
assert.ok(Date.now() - started >= 150, 'waited for the full bound')
assert.ok(Date.now() - started < 3000, 'did not fall back to a fixed sleep')
})
test('default poll bound matches the old sleep ceiling', () => {
// The readiness poll replaces the fixed 3000ms sleep: same ceiling, but it
// exits early when the session is ready.
assert.equal(CLICK_POLL_TIMEOUT_MS, 3000)
})