Files
aiturk-hermes-ide/apps/desktop/electron/hud-hyprland.test.ts
T

256 lines
7.0 KiB
TypeScript

/**
* Unit tests for the Hyprland HUD overlay promote. The socket itself needs a
* live compositor; what is covered here is the grammar (classic vs Lua), the
* client lookup, and which dispatchers fire for a tiled vs already-floating bar.
*/
import assert from 'node:assert/strict'
import { afterEach, test } from 'vitest'
import {
classifyHyprlandDispatchReply,
hudOverlayCommands,
parseHudHyprlandClient,
promoteHudOnHyprland,
resetHyprlandDispatchSyntax
} from './hud-hyprland'
const TITLE = 'Hermes HUD'
const ADDRESS = '0x55d1'
const SOCKET_ENV = { HYPRLAND_INSTANCE_SIGNATURE: 'abc123', XDG_RUNTIME_DIR: '/run/user/1000' }
const LUA_REJECT =
"error: [string \"return hl.dispatch(setfloating address:0x55d1)\"]:1: ')' expected near 'address'\n\n → Note: dispatch in lua is a shorthand for hl.dispatch(...), your syntax might need to be updated."
afterEach(() => {
resetHyprlandDispatchSyntax()
})
const hudClient = (over: Record<string, unknown> = {}) => ({
address: ADDRESS,
floating: false,
pinned: false,
title: TITLE,
...over
})
test('classifies Hyprland dispatch replies the way 0.54 and 0.56 actually write them', () => {
assert.equal(classifyHyprlandDispatchReply('ok'), 'ok')
assert.equal(classifyHyprlandDispatchReply('ok\n'), 'ok')
assert.equal(classifyHyprlandDispatchReply('Invalid dispatcher'), 'wrong-syntax')
assert.equal(classifyHyprlandDispatchReply(LUA_REJECT), 'wrong-syntax')
assert.equal(classifyHyprlandDispatchReply('No such window found'), 'failed')
assert.equal(classifyHyprlandDispatchReply('warning: =[C]:-1: hl.focus: window not found'), 'failed')
})
test('finds the HUD by exact title among other windows of the same pid', () => {
const found = parseHudHyprlandClient(
JSON.stringify([
{ address: '0x111', pid: 42, title: 'Hermes', floating: true, pinned: false },
hudClient({ pid: 42 })
]),
TITLE
)
assert.deepEqual(found, { address: ADDRESS, floating: false, pinned: false })
})
test('prefixes a bare hex address so the selector is well-formed', () => {
const found = parseHudHyprlandClient(JSON.stringify([hudClient({ address: '55d1' })]), TITLE)
assert.equal(found?.address, ADDRESS)
})
test('ignores a payload that is not the client list or has the wrong title', () => {
assert.equal(parseHudHyprlandClient('not json', TITLE), null)
assert.equal(parseHudHyprlandClient('{}', TITLE), null)
assert.equal(parseHudHyprlandClient(JSON.stringify([hudClient({ title: 'other' })]), TITLE), null)
})
test('legacy float is setfloating (idempotent), not togglefloating', () => {
const commands = hudOverlayCommands(ADDRESS, 'float')
assert.equal(commands.legacy, 'dispatch setfloating address:0x55d1')
assert.equal(commands.lua, 'dispatch hl.dsp.window.float({ action = "enable", window = "address:0x55d1" })')
})
test('lua pin uses enable so a second promote does not unpin', () => {
const commands = hudOverlayCommands(ADDRESS, 'pin')
assert.equal(commands.legacy, 'dispatch pin address:0x55d1')
assert.equal(commands.lua, 'dispatch hl.dsp.window.pin({ action = "enable", window = "address:0x55d1" })')
})
test('skips compositors that are not Hyprland', async () => {
const calls: string[] = []
const promoted = await promoteHudOnHyprland({
title: TITLE,
env: {},
uid: 1000,
request: async (_socket, command) => {
calls.push(command)
return 'ok'
}
})
assert.equal(promoted, false)
assert.deepEqual(calls, [])
})
test('floats then pins a tiled HUD on a classic hyprlang session', async () => {
const calls: string[] = []
const promoted = await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 1,
delayMs: 0,
request: async (_socket, command) => {
calls.push(command)
if (command === 'j/clients') {
return JSON.stringify([hudClient()])
}
return 'ok'
}
})
assert.equal(promoted, true)
assert.deepEqual(calls, ['j/clients', 'dispatch setfloating address:0x55d1', 'dispatch pin address:0x55d1'])
})
test('falls back to Lua dispatch when the classic session grammar is rejected', async () => {
const calls: string[] = []
const promoted = await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 1,
delayMs: 0,
request: async (_socket, command) => {
calls.push(command)
if (command === 'j/clients') {
return JSON.stringify([hudClient()])
}
if (command.startsWith('dispatch setfloating') || command.startsWith('dispatch pin ')) {
return LUA_REJECT
}
return 'ok'
}
})
assert.equal(promoted, true)
assert.deepEqual(calls, [
'j/clients',
'dispatch setfloating address:0x55d1',
'dispatch hl.dsp.window.float({ action = "enable", window = "address:0x55d1" })',
'dispatch hl.dsp.window.pin({ action = "enable", window = "address:0x55d1" })'
])
})
test('caches Lua syntax so the next promote does not probe classic first', async () => {
const request = async (_socket: string, command: string) => {
if (command === 'j/clients') {
return JSON.stringify([hudClient()])
}
if (command.startsWith('dispatch setfloating') || command.startsWith('dispatch pin ')) {
return LUA_REJECT
}
return 'ok'
}
await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 1,
delayMs: 0,
request
})
const calls: string[] = []
await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 1,
delayMs: 0,
request: async (_socket, command) => {
calls.push(command)
return request(_socket, command)
}
})
assert.deepEqual(calls, [
'j/clients',
'dispatch hl.dsp.window.float({ action = "enable", window = "address:0x55d1" })',
'dispatch hl.dsp.window.pin({ action = "enable", window = "address:0x55d1" })'
])
})
test('does not pin a window that is already pinned, and does not float one that already is', async () => {
const calls: string[] = []
const promoted = await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 1,
delayMs: 0,
request: async (_socket, command) => {
calls.push(command)
if (command === 'j/clients') {
return JSON.stringify([hudClient({ floating: true, pinned: true })])
}
return 'ok'
}
})
assert.equal(promoted, true)
assert.deepEqual(calls, ['j/clients'])
})
test('retries until Hyprland lists the HUD', async () => {
let lookups = 0
const promoted = await promoteHudOnHyprland({
title: TITLE,
env: SOCKET_ENV,
uid: 1000,
attempts: 3,
delayMs: 0,
sleep: async () => undefined,
request: async (_socket, command) => {
if (command === 'j/clients') {
lookups += 1
if (lookups < 3) {
return JSON.stringify([{ address: '0x111', title: 'Hermes', floating: true }])
}
return JSON.stringify([hudClient({ floating: true, pinned: true })])
}
return 'ok'
}
})
assert.equal(promoted, true)
assert.equal(lookups, 3)
})