See CHANGELOG.md for the full v0.16.0 entry. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: ralksta <ralksta@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Ralf <rohlenbo79@gmail.com> Co-authored-by: Paul Thies <110185070+ImScheinox@users.noreply.github.com> Co-authored-by: lancetm714 <108419425+lancetm714@users.noreply.github.com>
63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
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);
|
|
});
|
|
});
|