hermes-agent/ui-tui/src/__tests__/wheelAccel.test.ts
Brooklyn Nicholson b1c49d5e73 chore(tui): /clean recent perf work — KISS/DRY pass
24 files, -319 LoC. Behaviour preserved, 369/369 tests green.

- hermes-ink caches: shared lruEvict helper for the four parallel LRU
  caches (stringWidth, wrapText, sliceAnsi, lineWidth); touch-on-read
  stays inlined per cache; tightened output.ts skip-slice fast path.
- wheelAccel: trimmed provenance header, collapsed env parsing, ternary
  dispatch in computeWheelStep.
- perfPane: folded ensureLogDir into once-flag, spread-with-overrides
  for fastPath/phases instead of full rebuilds.
- env: extracted truthy() (used 4×).
- virtualHeights: collapsed user/diff/slash height bumps; trail+todos
  estimate.
- useInputHandlers: scrollIdleTimer cleanup on unmount, ?? undefined
  shorthand.
- useMainApp: dropped dead liveTailVisible IIFE and liveProgress
  indirection.
- appLayout, markdown, messageLine, entry: vertical rhythm, dropped
  narration comments, inlined one-shot vars.
- fix: empty catch blocks → /* best-effort */ for no-empty lint.
2026-04-26 20:38:47 -05:00

138 lines
3.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { computeWheelStep, initWheelAccel } from '../lib/wheelAccel.js'
describe('wheelAccel — native path', () => {
it('first click after init returns base', () => {
const s = initWheelAccel(false, 1)
expect(computeWheelStep(s, 1, 1000)).toBe(1)
})
it('same-direction fast events ramp mult (window-mode)', () => {
const s = initWheelAccel(false, 1)
computeWheelStep(s, 1, 1000)
computeWheelStep(s, 1, 1020)
computeWheelStep(s, 1, 1040)
// Key property: doesn't shrink below base.
expect(computeWheelStep(s, 1, 1060)).toBeGreaterThanOrEqual(1)
})
it('gap beyond window resets mult to base', () => {
const s = initWheelAccel(false, 1)
for (let t = 1000; t < 1100; t += 20) {
computeWheelStep(s, 1, t)
}
expect(computeWheelStep(s, 1, 2000)).toBe(1)
})
it('direction flip defers one event for bounce detection', () => {
const s = initWheelAccel(false, 1)
computeWheelStep(s, 1, 1000)
expect(computeWheelStep(s, -1, 1050)).toBe(0)
})
it('flip-back within bounce window engages wheelMode', () => {
const s = initWheelAccel(false, 1)
computeWheelStep(s, 1, 1000)
computeWheelStep(s, -1, 1050)
computeWheelStep(s, 1, 1100)
expect(s.wheelMode).toBe(true)
})
it('flip-back outside bounce window is a real reversal (no wheelMode)', () => {
const s = initWheelAccel(false, 1)
computeWheelStep(s, 1, 1000)
computeWheelStep(s, -1, 1050)
computeWheelStep(s, 1, 1400)
expect(s.wheelMode).toBe(false)
})
it('5 consecutive sub-5ms events disengage wheelMode (trackpad signature)', () => {
const s = initWheelAccel(false, 1)
s.wheelMode = true
s.dir = 1
s.time = 1000
for (let t = 1002; t <= 1010; t += 2) {
computeWheelStep(s, 1, t)
}
expect(s.wheelMode).toBe(false)
})
it('1.5s idle disengages wheelMode', () => {
const s = initWheelAccel(false, 1)
s.wheelMode = true
s.dir = 1
s.time = 1000
computeWheelStep(s, 1, 3000)
expect(s.wheelMode).toBe(false)
})
})
describe('wheelAccel — xterm.js path', () => {
it('first click returns 2 after long idle', () => {
const s = initWheelAccel(true, 1)
expect(computeWheelStep(s, 1, 1000)).toBeGreaterThanOrEqual(1)
})
it('sub-5ms burst returns 1 (same-direction, same-batch)', () => {
const s = initWheelAccel(true, 1)
computeWheelStep(s, 1, 1000)
expect(computeWheelStep(s, 1, 1002)).toBe(1)
})
it('slow steady scroll stays in precision range', () => {
const s = initWheelAccel(true, 1)
for (let t = 1000; t < 2000; t += 33) {
const r = computeWheelStep(s, 1, t)
expect(r).toBeGreaterThanOrEqual(1)
expect(r).toBeLessThanOrEqual(6)
}
})
it('direction reversal resets mult', () => {
const s = initWheelAccel(true, 1)
for (let t = 1000; t < 1100; t += 20) {
computeWheelStep(s, 1, t)
}
const beforeFlip = s.mult
computeWheelStep(s, -1, 1200)
expect(s.mult).toBeLessThanOrEqual(beforeFlip)
expect(s.mult).toBe(2)
})
it('frac stays in [0,1) across events', () => {
const s = initWheelAccel(true, 1)
// Correctness invariant of fractional carry: never negative, never reaches 1.
for (let t = 1000; t < 1200; t += 30) {
computeWheelStep(s, 1, t)
expect(s.frac).toBeGreaterThanOrEqual(0)
expect(s.frac).toBeLessThan(1)
}
})
})