Files
omarchycn/test/shell.d/menu-test.sh
T

163 lines
5.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
run_node_test <<'JS'
const fs = require('fs')
const menu = requireFromRoot('shell/plugins/menu/MenuModel.js')
const menuQml = fs.readFileSync(path.join(root, 'shell/plugins/menu/Menu.qml'), 'utf8')
const defaultMenuJsonc = fs.readFileSync(path.join(root, 'default/omarchy/omarchy-menu.jsonc'), 'utf8')
const parsed = menu.parseMenuJsonc(`
{
// comment
"items": {
"root": { "label": "Go" },
"style": { "label": "Style" },
"style.theme": {
"label": "Themes",
"aliases": "theme",
"keywords": "appearance appearance colors",
"action": "omarchy-theme-set"
},
},
}
`)
assertEqual(parsed.length, 3, 'menu parses JSONC with comments and trailing commas')
assertDeepEqual(
parsed.find(item => item.id === 'style.theme'),
{
id: 'style.theme',
parent: 'style',
kind: 'action',
icon: '',
iconFont: '',
label: 'Themes',
target: '',
keywords: 'appearance colors',
description: '',
action: 'omarchy-theme-set',
provider: '',
aliases: ['theme'],
when: '',
checked: ''
},
'menu normalizes parsed items'
)
const user = [
menu.normalizeItem('style.theme', { label: 'Theme picker', aliases: ['theme', 'colors'], action: 'custom-theme' }),
menu.normalizeItem('tools', { label: 'Tools' })
]
const merged = menu.mergeMenuSources(parsed, user)
assertEqual(merged.items['style.theme'].label, 'Theme picker', 'menu user entries override default entries')
assertEqual(merged.items['style.theme'].order, 2, 'menu preserves original order on override')
assert(merged.items.root, 'menu injects root when merging sources')
assertEqual(menu.slugify('Power Saver!'), 'power-saver', 'menu slugifies provider rows')
assertEqual(menu.pathFor(merged.items, 'style.theme'), 'Style Theme picker', 'menu builds item paths')
assertEqual(menu.parentPathFor(merged.items, 'style.theme'), 'Style', 'menu builds parent paths')
assert(menu.isDescendantOf(merged.items, 'style.theme', 'style'), 'menu detects descendants')
assertEqual(menu.childCount(merged.items, merged.itemOrder, 'style'), 1, 'menu counts children')
assertEqual(menu.labelFor({ id: 'style.theme', label: 'Theme', checked: 'cmd' }, { 'style.theme': true }), 'Theme ✓', 'menu appends checked marker')
const entry = merged.items['style.theme']
assert(menu.matchesQuery(entry, 'theme', true), 'menu matches labels and aliases')
assert(menu.matchesQuery(entry, 'colors', true), 'menu matches aliases')
assert(!menu.matchesQuery(entry, 'missing', true), 'menu rejects missing terms')
assert(!menu.matchesQuery(entry, 'theme', false), 'menu hides invisible matches')
assert(menu.searchScore(merged.items, entry, 'theme') < menu.searchScore(merged.items, entry, 'appearance'), 'menu scores name matches above keyword matches')
assertDeepEqual(
menu.displayRow(merged.items, merged.itemOrder, {}, entry, 'Style', 12, 'search'),
{
itemId: 'style.theme',
kind: 'action',
icon: '',
iconFont: '',
label: 'Theme picker',
target: 'style.theme',
detail: 'Style',
path: 'Style Theme picker',
childCount: 0,
action: 'custom-theme',
provider: '',
score: 12,
section: 'search'
},
'menu builds display rows'
)
const defaultItems = menu.parseMenuJsonc(defaultMenuJsonc)
const defaultById = Object.fromEntries(defaultItems.map(item => [item.id, item]))
assert(
defaultById['update.omarchy'].icon === '\ue900',
'menu update Omarchy entry uses the Omarchy glyph'
)
assert(
defaultById['update.omarchy'].iconFont === 'omarchy',
'menu update Omarchy entry renders the private glyph with the Omarchy font'
)
assert(
defaultById['setup.input'].action.includes('input.lua'),
'menu keeps Input as a direct config action'
)
assert(
defaultById['setup.direct-boot'].action.includes('omarchy-config-direct-boot'),
'menu places Direct Boot directly under Setup'
)
assertEqual(
defaultItems.findIndex(item => item.id === 'setup.direct-boot'),
defaultItems.findIndex(item => item.id === 'setup.input') + 1,
'menu lists Direct Boot immediately below Input'
)
assert(
defaultById['setup.security.passwordless-sudo'].action.includes('omarchy-sudo-passwordless'),
'menu places Passwordless Sudo under Setup > Security'
)
assert(
!defaultById['trigger.toggle.direct-boot'] && !defaultById['trigger.toggle.passwordless-sudo'],
'menu removes the relocated toggles from Trigger > Toggle'
)
assert(
/font\.family: row\.iconFont\.length > 0 \? row\.iconFont : root\.fontFamily/.test(menuQml),
'menu rows support per-icon font families'
)
assert(
/function select\(delta\)[\s\S]*root\.disarmPointer\(\)[\s\S]*selectedIndex =/.test(menuQml),
'menu keyboard navigation disarms pointer selection'
)
assert(
/function setFilter\(nextFilter\)[\s\S]*root\.disarmPointer\(\)/.test(menuQml),
'menu filter changes disarm pointer selection'
)
assert(
/function setActiveMenu\(id, pushHistory\)[\s\S]*root\.disarmPointer\(\)/.test(menuQml),
'menu route changes disarm pointer selection'
)
assert(
/\(event\.key === Qt\.Key_Backspace \|\| event\.key === Qt\.Key_Left\) && !root\.filterText[\s\S]*root\.goBack\(\)/.test(menuQml),
'menu Left key follows empty-filter Backspace navigation'
)
assert(
/PointerMoveGate\s*\{[\s\S]*id: pointerGate[\s\S]*referenceItem: card[\s\S]*\}/.test(menuQml),
'menu uses shared pointer movement gate in card coordinates'
)
assert(
/function disarmPointer\(\)[\s\S]*pointerGate\.reset\(\)/.test(menuQml),
'menu resets pointer movement gate when pointer selection is disarmed'
)
assert(
/function selectFromPointer\(index, item, mouse\)[\s\S]*pointerGate\.moved\(item, mouse\)[\s\S]*root\.selectedIndex = index/.test(menuQml),
'menu only selects from pointer after real movement'
)
assert(
/onPositionChanged: function\(mouse\) \{\s*root\.selectFromPointer\(row\.index, row, mouse\)\s*\}/.test(menuQml),
'menu row hover routes through pointer movement gate'
)
JS