hermes-agent/apps/desktop/src/themes/install.test.ts
Brooklyn Nicholson 62fe9fd101 style(desktop,tui): fix all lint/type/formatting issues
Bring apps/desktop and ui-tui to a clean state for typecheck, eslint,
and prettier:

- Run prettier across both trees (printWidth/wrap drift; prettier is not
  CI-enforced for these JS projects, so main had accumulated drift).
- Apply eslint --fix for padding-line-between-statements and perfectionist
  import/export sorting.
- Manual fixes for non-auto-fixable rules:
  - remove unused node:net import in electron/main.cjs (uses Electron net)
  - replace inline `typeof import(...)` annotations with top-level
    `import type * as EnvModule` in two ui-tui test files
  - scoped eslint-disable no-control-regex on intentional sentinel/ANSI
    regexes (mathUnicode.ts, text.ts)
  - resolve react-hooks/exhaustive-deps per-case: correct swapped/missing
    deps, collapse redundant session.* members, and justified disables on
    settings mount-only data-load effects to preserve run-once behavior

No behavior changes; test pass/fail counts are unchanged from the main
baseline.
2026-06-26 01:04:33 -05:00

132 lines
4.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type { DesktopMarketplaceThemeResult } from '@/global'
import { luminance } from './color'
import { buildThemeFromMarketplace } from './install'
const themeJson = (type: 'light' | 'dark', background: string, foreground: string) =>
JSON.stringify({ type, colors: { 'editor.background': background, 'editor.foreground': foreground } })
// A full base-8 ANSI set keyed off `red` so each variant is distinguishable.
const ansiColors = (red: string) => ({
'terminal.ansiBlack': '#000000',
'terminal.ansiRed': red,
'terminal.ansiGreen': '#00aa00',
'terminal.ansiYellow': '#aaaa00',
'terminal.ansiBlue': '#0000aa',
'terminal.ansiMagenta': '#aa00aa',
'terminal.ansiCyan': '#00aaaa',
'terminal.ansiWhite': '#aaaaaa'
})
const themeJsonWithAnsi = (type: 'light' | 'dark', background: string, foreground: string, red: string) =>
JSON.stringify({
type,
colors: { 'editor.background': background, 'editor.foreground': foreground, ...ansiColors(red) }
})
describe('buildThemeFromMarketplace', () => {
it('folds a light + dark variant into one family with both slots', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'ryanolsonx.solarized',
displayName: 'Solarized',
themes: [
{ label: 'Solarized Light', uiTheme: 'vs', contents: themeJson('light', '#fdf6e3', '#586e75') },
{ label: 'Solarized Dark', uiTheme: 'vs-dark', contents: themeJson('dark', '#002b36', '#93a1a1') }
]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.label).toBe('Solarized')
expect(theme.name).toBe('vsc-solarized')
// colors = the light variant, darkColors = the dark variant → the toggle works.
expect(theme.colors.background).toBe('#fdf6e3')
expect(theme.darkColors?.background).toBe('#002b36')
expect(luminance(theme.colors.background)).toBeGreaterThan(0.5)
expect(luminance(theme.darkColors!.background)).toBeLessThan(0.5)
})
it('orders variants by contribution regardless of light/dark sequence', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'github.github-vscode-theme',
displayName: 'GitHub Theme',
themes: [
{ label: 'GitHub Dark Default', uiTheme: 'vs-dark', contents: themeJson('dark', '#0d1117', '#e6edf3') },
{ label: 'GitHub Light Default', uiTheme: 'vs', contents: themeJson('light', '#ffffff', '#1f2328') }
]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.colors.background).toBe('#ffffff')
expect(theme.darkColors?.background).toBe('#0d1117')
})
it('fills both slots with the sole palette for a single-variant extension', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'dracula-theme.theme-dracula',
displayName: 'Dracula',
themes: [{ label: 'Dracula', uiTheme: 'vs-dark', contents: themeJson('dark', '#282a36', '#f8f8f2') }]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.colors.background).toBe('#282a36')
expect(theme.darkColors).toBe(theme.colors)
})
it('keys each variant terminal palette to its mode (terminal / darkTerminal)', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'ryanolsonx.solarized',
displayName: 'Solarized',
themes: [
{
label: 'Solarized Light',
uiTheme: 'vs',
contents: themeJsonWithAnsi('light', '#fdf6e3', '#586e75', '#dc322f')
},
{
label: 'Solarized Dark',
uiTheme: 'vs-dark',
contents: themeJsonWithAnsi('dark', '#002b36', '#93a1a1', '#ff5f56')
}
]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.terminal?.red).toBe('#dc322f')
expect(theme.darkTerminal?.red).toBe('#ff5f56')
})
it('reuses the sole variant terminal palette for both modes', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'dracula-theme.theme-dracula',
displayName: 'Dracula',
themes: [
{ label: 'Dracula', uiTheme: 'vs-dark', contents: themeJsonWithAnsi('dark', '#282a36', '#f8f8f2', '#ff5555') }
]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.terminal?.red).toBe('#ff5555')
expect(theme.darkTerminal?.red).toBe('#ff5555')
})
it('leaves terminal slots unset when no variant ships an ANSI palette', () => {
const result: DesktopMarketplaceThemeResult = {
extensionId: 'x.plain',
displayName: 'Plain',
themes: [{ label: 'Plain', uiTheme: 'vs-dark', contents: themeJson('dark', '#101010', '#fafafa') }]
}
const theme = buildThemeFromMarketplace(result)
expect(theme.terminal).toBeUndefined()
expect(theme.darkTerminal).toBeUndefined()
})
it('throws when the extension contributes no themes', () => {
expect(() => buildThemeFromMarketplace({ extensionId: 'x.y', displayName: 'X', themes: [] })).toThrow(
/does not contribute/i
)
})
})