Files
immich-folio/lib/__tests__/theme-scalars.test.ts

63 lines
2.5 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from 'vitest';
import { resolveTheme, THEME_PRESETS, DEFAULT_PRESET } from '@/lib/config/theme';
/**
* `radius` reaches CSS as `${radius}px` and `${radius * 1.5}px` (app/layout.tsx),
* so a value that is not actually a number does not fail loudly — it becomes
* `8pxpx` and `NaNpx` (#633). Hand-edited YAML can hand resolveTheme anything;
* only the panel-save boundary (settingsSchema.ts) already caught the type
* half of this, and only for a save from the panel.
*/
describe('resolveTheme scalar coercion (#633)', () => {
const base = THEME_PRESETS[DEFAULT_PRESET];
it('falls back to the preset radius when the value is a string', () => {
// as unknown as number: simulating hand-edited YAML, which yaml.load()
// hands back with no runtime guarantee it matches SettingsYaml's types.
const theme = resolveTheme({ radius: '8px' as unknown as number });
expect(theme.radius).toBe(base.radius);
expect(Number.isFinite(theme.radius)).toBe(true);
});
it('falls back to the preset radius when the value is NaN', () => {
expect(resolveTheme({ radius: NaN }).radius).toBe(base.radius);
});
it('clamps an out-of-range radius rather than passing it through', () => {
expect(resolveTheme({ radius: 999 }).radius).toBeLessThanOrEqual(64);
expect(resolveTheme({ radius: -5 }).radius).toBe(0);
});
it('keeps a legitimate radius override', () => {
expect(resolveTheme({ radius: 24 }).radius).toBe(24);
});
it('falls back to the preset accent when the value is not a string', () => {
const theme = resolveTheme({ accent: 42 as unknown as string });
expect(theme.accent).toBe(base.accent);
});
it('falls back to the preset accent for an empty string', () => {
expect(resolveTheme({ accent: '' }).accent).toBe(base.accent);
});
it('keeps a legitimate accent override', () => {
expect(resolveTheme({ accent: '#123456' }).accent).toBe('#123456');
});
it('falls back to the preset grain/headerDot when not a boolean', () => {
const theme = resolveTheme({
grain: 'yes' as unknown as boolean,
headerDot: 1 as unknown as boolean,
});
expect(theme.grain).toBe(base.grain);
expect(theme.headerDot).toBe(base.headerDot);
});
it('keeps legitimate grain/headerDot overrides', () => {
const theme = resolveTheme({ grain: !base.grain, headerDot: !base.headerDot });
expect(theme.grain).toBe(!base.grain);
expect(theme.headerDot).toBe(!base.headerDot);
});
});