Files
orca/src/shared/plugin-theme-settings.test.ts
T
Neil d10ab00f3c feat(themes): Match Terminal becomes a real app theme for the whole window (#36567)
* feat(themes): make Match Terminal a real app theme painted at :root

Match Terminal used to be an inline override on three left-column
elements, so the tab bar, right sidebar, status bar, titlebar, menus and
editors kept the built-in palette, and its fixed color mixes became
unreadable on low-contrast palettes.

It is now a light/dark app theme slot value synthesized from the active
terminal palette (read through resolveTerminalPalette, so each mode's
color overrides apply) and painted through the plugin theme pipeline
(derivation, contrast gate, startup cache, Monaco theme). The document
mode follows the terminal background, including onboarding's restore.
The legacy leftSidebarAppearanceMode='match-terminal' value fills the
empty slots on load and on writes (desktop and web), and it is kept
mirrored while a slot matches the terminal so older Orca still matches
its sidebar. The pickers mark the option with a muted "(dynamic)" label.

* fix(onboarding): sync the painted-theme ref in an effect, not during render

* feat(themes): use a lightning icon for Match Terminal's dynamic label

* perf(themes): reuse the Match Terminal theme when its content is unchanged
2026-11-01 01:19:38 -07:00

168 lines
5.8 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type { GlobalSettings } from './global-settings-types'
import {
hasLegacyMatchTerminalSidebar,
legacyMatchTerminalSidebarWrite,
syncLegacyMatchTerminalSidebar,
normalizePluginThemeSettings,
pluginThemeSettingsAfterRemoval
} from './plugin-theme-settings'
const colors = { background: '#1b1430', foreground: '#e8e0ff', red: '#ff6b8b' }
describe('plugin theme settings', () => {
it('bounds what a client may write', () => {
expect(
normalizePluginThemeSettings({
pluginAppTheme: 'plugin:samples.dusk/dusk',
themeBeforePlugin: 'system',
terminalPluginPalettes: [
{ id: 'plugin:samples.dusk/dusk', colors },
{ id: 'plugin:samples.dusk/dusk', colors },
{ id: 'not-a-plugin', colors },
{ id: 'plugin:samples.other/a', colors: { background: 'red;' } },
{ id: 'plugin:samples.b/b', colors },
{ id: 'plugin:samples.c/c', colors }
]
})
).toEqual({
pluginAppTheme: 'plugin:samples.dusk/dusk',
themeBeforePlugin: 'system',
terminalPluginPalettes: [
{ id: 'plugin:samples.dusk/dusk', colors },
{ id: 'plugin:samples.b/b', colors }
]
})
expect(
normalizePluginThemeSettings({
pluginAppTheme: 'plugin:../x',
pluginAppThemeLight: 'plugin:samples.dawn/dawn',
pluginAppThemeDark: 'match-terminal',
pluginIconTheme: 'x'.repeat(10_000),
themeBeforePlugin: 'neon',
editorThemeLight: 'dark',
editorThemeDark: 'vs-dark'
})
).toEqual({
pluginAppTheme: null,
pluginAppThemeLight: 'plugin:samples.dawn/dawn',
pluginAppThemeDark: 'match-terminal',
editorThemeLight: 'dark',
editorThemeDark: null,
pluginIconTheme: null,
themeBeforePlugin: null
})
const unrelated: Partial<GlobalSettings> = { editorAutoSave: true }
expect(normalizePluginThemeSettings(unrelated)).toEqual({})
})
it('forgets an uninstalled plugin and restores the earlier Theme choice', () => {
expect(
pluginThemeSettingsAfterRemoval(
{
theme: 'dark',
themeBeforePlugin: 'system',
pluginAppTheme: 'plugin:samples.dusk/dusk',
pluginIconTheme: 'plugin:samples.dusk/icons',
terminalThemeDark: 'plugin:samples.dusk/dusk',
terminalThemeLight: 'Builtin Tango Light',
terminalPluginPalettes: [{ id: 'plugin:samples.dusk/dusk', colors }]
},
'samples.dusk'
)
).toEqual({
pluginAppTheme: null,
themeBeforePlugin: null,
theme: 'system',
pluginIconTheme: null,
terminalThemeDark: '',
terminalPluginPalettes: []
})
expect(
pluginThemeSettingsAfterRemoval(
{
theme: 'light',
pluginAppTheme: 'plugin:samples.dusk-two/dusk',
terminalThemeDark: '',
terminalThemeLight: ''
},
'samples.dusk'
)
).toEqual({})
})
it("clears only the removed plugin's light or dark slot", () => {
expect(
pluginThemeSettingsAfterRemoval(
{
theme: 'system',
pluginAppThemeLight: 'plugin:other.dawn/dawn',
pluginAppThemeDark: 'plugin:samples.dusk/dusk',
editorThemeLight: 'plugin:samples.dusk/dusk',
editorThemeDark: 'light',
terminalThemeDark: '',
terminalThemeLight: ''
},
'samples.dusk'
)
).toEqual({ pluginAppThemeDark: null, editorThemeLight: null })
})
it('moves the legacy Match Terminal sidebar into the empty app theme slots', () => {
const legacy = {
leftSidebarAppearanceMode: 'match-terminal' as const,
pluginAppThemeLight: null,
pluginAppThemeDark: 'plugin:samples.dusk/dusk' as const
}
expect(hasLegacyMatchTerminalSidebar(legacy)).toBe(true)
expect(syncLegacyMatchTerminalSidebar(legacy, true)).toEqual({
leftSidebarAppearanceMode: 'match-terminal',
pluginAppThemeLight: 'match-terminal',
pluginAppThemeDark: 'plugin:samples.dusk/dusk'
})
})
it('keeps the sidebar value in step with the slots so older Orca still matches the terminal', () => {
const current = {
leftSidebarAppearanceMode: 'match-terminal' as const,
pluginAppThemeLight: 'match-terminal' as const,
pluginAppThemeDark: 'match-terminal' as const
}
// Choosing Built-in for one mode keeps the mirror; for both, it clears it without refilling.
expect(legacyMatchTerminalSidebarWrite(current, { pluginAppThemeLight: null })).toMatchObject({
leftSidebarAppearanceMode: 'match-terminal',
pluginAppThemeLight: null
})
const builtIn = legacyMatchTerminalSidebarWrite(current, {
pluginAppThemeLight: null,
pluginAppThemeDark: null
})
expect(builtIn.leftSidebarAppearanceMode).toBe('default')
expect(hasLegacyMatchTerminalSidebar({ ...current, ...builtIn })).toBe(false)
// A full-settings write keeps the mirror beside the cleared slots; that is not legacy intent.
expect(
legacyMatchTerminalSidebarWrite(current, {
...current,
pluginAppThemeLight: null,
pluginAppThemeDark: null
})
).toMatchObject({
pluginAppThemeLight: null,
pluginAppThemeDark: null,
leftSidebarAppearanceMode: 'default'
})
expect(
legacyMatchTerminalSidebarWrite(
{ ...current, pluginAppThemeLight: null, pluginAppThemeDark: null },
{ leftSidebarAppearanceMode: 'match-terminal' }
)
).toMatchObject({ pluginAppThemeLight: 'match-terminal', pluginAppThemeDark: 'match-terminal' })
expect(
legacyMatchTerminalSidebarWrite(current, { leftSidebarAppearanceMode: 'tinted' })
).toMatchObject({
leftSidebarAppearanceMode: 'tinted'
})
expect(legacyMatchTerminalSidebarWrite(current, { editorAutoSave: true })).toEqual({})
})
})