114 lines
3.9 KiB
TypeScript
114 lines
3.9 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import {
|
|
applyVoiceRecordResponse,
|
|
handleIdleHotkeyExit,
|
|
shouldAllowIdleHotkeyExit,
|
|
shouldFallThroughForScroll
|
|
} from '../app/useInputHandlers.js'
|
|
|
|
const baseKey = {
|
|
downArrow: false,
|
|
pageDown: false,
|
|
pageUp: false,
|
|
shift: false,
|
|
upArrow: false,
|
|
wheelDown: false,
|
|
wheelUp: false
|
|
}
|
|
|
|
describe('shouldFallThroughForScroll — keep transcript scrolling alive during prompt overlays', () => {
|
|
it('falls through for wheel scrolls', () => {
|
|
expect(shouldFallThroughForScroll({ ...baseKey, wheelUp: true })).toBe(true)
|
|
expect(shouldFallThroughForScroll({ ...baseKey, wheelDown: true })).toBe(true)
|
|
})
|
|
|
|
it('falls through for PageUp / PageDown', () => {
|
|
expect(shouldFallThroughForScroll({ ...baseKey, pageUp: true })).toBe(true)
|
|
expect(shouldFallThroughForScroll({ ...baseKey, pageDown: true })).toBe(true)
|
|
})
|
|
|
|
it('falls through for Shift+ArrowUp / Shift+ArrowDown', () => {
|
|
expect(shouldFallThroughForScroll({ ...baseKey, shift: true, upArrow: true })).toBe(true)
|
|
expect(shouldFallThroughForScroll({ ...baseKey, shift: true, downArrow: true })).toBe(true)
|
|
})
|
|
|
|
it('does NOT fall through for plain arrows — those drive in-prompt selection', () => {
|
|
expect(shouldFallThroughForScroll({ ...baseKey, upArrow: true })).toBe(false)
|
|
expect(shouldFallThroughForScroll({ ...baseKey, downArrow: true })).toBe(false)
|
|
})
|
|
|
|
it('does NOT fall through for plain Shift — without an arrow it is a no-op', () => {
|
|
expect(shouldFallThroughForScroll({ ...baseKey, shift: true })).toBe(false)
|
|
})
|
|
|
|
it('does NOT fall through for unrelated state (no scroll keys held)', () => {
|
|
expect(shouldFallThroughForScroll(baseKey)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('shouldAllowIdleHotkeyExit', () => {
|
|
it('keeps idle exit hotkeys enabled in normal terminals', () => {
|
|
expect(shouldAllowIdleHotkeyExit(false)).toBe(true)
|
|
})
|
|
|
|
it('disables idle exit hotkeys in dashboard chat', () => {
|
|
expect(shouldAllowIdleHotkeyExit(true)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('handleIdleHotkeyExit', () => {
|
|
it('exits in normal terminals', () => {
|
|
const actions = { die: vi.fn(), sys: vi.fn() }
|
|
|
|
handleIdleHotkeyExit(actions, false)
|
|
|
|
expect(actions.die).toHaveBeenCalledTimes(1)
|
|
expect(actions.sys).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('asks the dashboard for a fresh chat instead of leaving a ghost session', () => {
|
|
const actions = { die: vi.fn(), sys: vi.fn() }
|
|
const requestDashboardNewSession = vi.fn()
|
|
|
|
handleIdleHotkeyExit(actions, true, requestDashboardNewSession)
|
|
|
|
expect(actions.die).not.toHaveBeenCalled()
|
|
expect(requestDashboardNewSession).toHaveBeenCalledTimes(1)
|
|
expect(actions.sys).toHaveBeenCalledWith('starting a fresh dashboard chat...')
|
|
})
|
|
})
|
|
|
|
describe('applyVoiceRecordResponse', () => {
|
|
it('reverts optimistic REC state when the gateway reports voice busy', () => {
|
|
const setProcessing = vi.fn()
|
|
const setRecording = vi.fn()
|
|
const sys = vi.fn()
|
|
|
|
applyVoiceRecordResponse({ status: 'busy' }, true, { setProcessing, setRecording }, sys)
|
|
|
|
expect(setRecording).toHaveBeenCalledWith(false)
|
|
expect(setProcessing).toHaveBeenCalledWith(true)
|
|
expect(sys).toHaveBeenCalledWith('voice: still transcribing; try again shortly')
|
|
})
|
|
|
|
it('keeps optimistic REC state for successful recording starts', () => {
|
|
const setProcessing = vi.fn()
|
|
const setRecording = vi.fn()
|
|
|
|
applyVoiceRecordResponse({ status: 'recording' }, true, { setProcessing, setRecording }, vi.fn())
|
|
|
|
expect(setRecording).not.toHaveBeenCalled()
|
|
expect(setProcessing).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('reverts optimistic REC state when the gateway returns null', () => {
|
|
const setProcessing = vi.fn()
|
|
const setRecording = vi.fn()
|
|
|
|
applyVoiceRecordResponse(null, true, { setProcessing, setRecording }, vi.fn())
|
|
|
|
expect(setRecording).toHaveBeenCalledWith(false)
|
|
expect(setProcessing).toHaveBeenCalledWith(false)
|
|
})
|
|
})
|