Files
openchamber/packages/ui/src/lib/settings/registry.test.ts
T

114 lines
4.8 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { z } from 'zod';
import { useUIStore } from '@/stores/useUIStore';
import {
AUTO_SAVE_KEYS,
DESKTOP_SHELL_KEYS,
LOCAL_DEVICE_KEYS,
MIRRORED_KEYS,
SETTINGS_KEYS,
SETTINGS_REGISTRY,
applySettingsToStores,
buildSettingsRegistrySnapshot,
parseSettingsDocument,
} from './registry';
import { renderSettingsRegistrySnapshot, SETTINGS_REGISTRY_SNAPSHOT_PATHS } from './registry-snapshot';
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..', '..');
describe('settings registry', () => {
test('every key lives in exactly one table', () => {
const all = [...SETTINGS_KEYS, ...LOCAL_DEVICE_KEYS, ...DESKTOP_SHELL_KEYS];
expect(new Set(all).size).toBe(all.length);
});
test('covers every key the ui-store persists, under its settings name', () => {
const partialize = useUIStore.persist.getOptions().partialize;
expect(partialize).toBeTruthy();
// zustand types the persisted slice loosely; only its key names matter here.
const persistedKeys = Object.keys(z.object({}).passthrough().parse(partialize!(useUIStore.getInitialState())));
// The store's name for the shared `draftStarters` field.
const aliases = new Map([['globalDraftStarters', 'draftStarters']]);
const known = new Set<string>([...SETTINGS_KEYS, ...LOCAL_DEVICE_KEYS]);
const missing = persistedKeys.map((key) => aliases.get(key) ?? key).filter((key) => !known.has(key));
expect(missing).toEqual([]);
});
test('per-surface storage is a profile-only marker', () => {
for (const key of SETTINGS_KEYS) {
if (SETTINGS_REGISTRY[key].perSurface) {
expect(SETTINGS_REGISTRY[key].scope).toBe('profile');
}
}
});
test('computed and secret fields never reach the mirror; computed ones are never auto-saved', () => {
for (const key of MIRRORED_KEYS) {
expect(SETTINGS_REGISTRY[key].secret).toBe(undefined);
expect(SETTINGS_REGISTRY[key].computed).toBe(undefined);
expect(SETTINGS_REGISTRY[key].scope).not.toBe('device');
}
for (const key of AUTO_SAVE_KEYS) {
expect(SETTINGS_REGISTRY[key].computed).toBe(undefined);
}
});
test('parses a document at the boundary: unknown keys dropped, rejected values absent, legacy keys mapped', () => {
const parsed = parseSettingsDocument({
fontSize: 15,
toolJsonViewMode: 'invalid',
queueModeEnabled: false,
gitProviderId: 'anthropic',
markdownDisplayMode: 'x',
autoDeleteAfterDays: 900,
sttProvider: 'server',
});
expect(parsed).toEqual({
fontSize: 15,
followUpBehavior: 'steer',
queueModeEnabled: false,
autoDeleteAfterDays: 365,
gitProviderId: 'anthropic',
sttProvider: 'openai-compatible',
});
expect(parseSettingsDocument(null)).toBeNull();
expect(parseSettingsDocument([])).toBeNull();
});
test('applies only the fields a snapshot carries and leaves the rest alone', () => {
useUIStore.getState().setTerminalShell('fish');
useUIStore.getState().setShowReasoningTraces(true);
applySettingsToStores({ showReasoningTraces: false });
expect(useUIStore.getState().showReasoningTraces).toBe(false);
expect(useUIStore.getState().terminalShell).toBe('fish');
});
test('applies the hidden-sections list together with its explicit marker', () => {
applySettingsToStores({ workStatusHiddenSections: ['mcp', 'telemetry'] });
expect(useUIStore.getState().workStatusHiddenSections).toEqual(['mcp']);
expect(useUIStore.getState().workStatusHiddenSectionsExplicit).toBe(false);
applySettingsToStores({ workStatusHiddenSections: ['mcp', 'telemetry'], workStatusHiddenSectionsExplicit: true });
expect(useUIStore.getState().workStatusHiddenSections).toEqual(['mcp', 'telemetry']);
expect(useUIStore.getState().workStatusHiddenSectionsExplicit).toBe(true);
});
test('the checked-in JSON snapshots match the registry (run `bun run settings-registry:generate`)', () => {
const rendered = renderSettingsRegistrySnapshot();
for (const relativePath of SETTINGS_REGISTRY_SNAPSHOT_PATHS) {
expect(readFileSync(resolve(repoRoot, relativePath), 'utf8')).toBe(rendered);
}
});
test('the snapshot names every key of every table', () => {
const snapshot = buildSettingsRegistrySnapshot();
const keys = Object.keys(snapshot.fields);
expect(keys.length).toBe(SETTINGS_KEYS.length + LOCAL_DEVICE_KEYS.length + DESKTOP_SHELL_KEYS.length);
for (const key of LOCAL_DEVICE_KEYS) expect(snapshot.fields[key]).toEqual({ scope: 'device', local: true });
for (const key of DESKTOP_SHELL_KEYS) expect(snapshot.fields[key].owner).toBe('desktop-shell');
});
});