murashit_codex-panel/tests/settings/settings.test.ts

159 lines
6.3 KiB
TypeScript
Raw Normal View History

2026-05-12 15:05:56 +00:00
import { describe, expect, it } from "vitest";
import { FileSystemAdapter, type App } from "obsidian";
import {
DEFAULT_SETTINGS,
getVaultPath,
normalizeSettings,
settingsMatchNormalizedData,
type CodexPanelSettings,
} from "../../src/settings/model";
2026-05-12 15:05:56 +00:00
describe("settings", () => {
it("normalizes empty data", () => {
expect(normalizeSettings(null)).toEqual(DEFAULT_SETTINGS);
});
it("persists only panel-owned settings, not Codex runtime policy", () => {
const storedData = {
2026-05-12 15:05:56 +00:00
codexPath: "/usr/local/bin/codex",
threadNamingModel: "gpt-5.4-mini",
threadNamingEffort: "low",
2026-05-18 02:55:43 +00:00
rewriteSelectionModel: "gpt-5.4-mini",
rewriteSelectionEffort: "minimal",
2026-06-05 04:43:00 +00:00
showToolbar: false,
sendShortcut: "mod-enter",
scrollThreadFromComposerEdges: true,
2026-05-18 08:20:16 +00:00
archiveExportEnabled: true,
archiveExportFolderTemplate: "Codex Archives/{{date}}",
archiveExportFilenameTemplate: "{{title}} {{shortId}}.md",
2026-05-19 00:27:23 +00:00
archiveExportTags: "codex, archive",
model: "gpt-5.5",
sandboxMode: "workspace-write",
approvalPolicy: "on-request",
hooks: [{ event: "postToolUse" }],
extraPanelState: { threadId: "thread-1" },
};
const normalized: CodexPanelSettings = {
codexPath: "/usr/local/bin/codex",
threadNamingModel: "gpt-5.4-mini",
threadNamingEffort: "low",
2026-05-18 02:55:43 +00:00
rewriteSelectionModel: "gpt-5.4-mini",
rewriteSelectionEffort: "minimal",
2026-06-05 04:43:00 +00:00
showToolbar: false,
sendShortcut: "mod-enter",
scrollThreadFromComposerEdges: true,
2026-05-18 08:20:16 +00:00
archiveExportEnabled: true,
archiveExportFolderTemplate: "Codex Archives/{{date}}",
archiveExportFilenameTemplate: "{{title}} {{shortId}}.md",
2026-05-19 00:27:23 +00:00
archiveExportTags: "codex, archive",
};
expect(normalizeSettings(storedData)).toEqual(normalized);
expect(settingsMatchNormalizedData(storedData, normalized)).toBe(false);
2026-05-12 15:05:56 +00:00
});
it("uses the default codex path when the stored path is empty", () => {
expect(normalizeSettings({ codexPath: " " }).codexPath).toBe(DEFAULT_SETTINGS.codexPath);
});
it("detects when normalized settings need to be written back", () => {
const settings = normalizeSettings({
codexPath: "/usr/local/bin/codex",
threadNamingModel: "gpt-5.4-mini",
threadNamingEffort: "low",
2026-05-18 02:55:43 +00:00
rewriteSelectionModel: "gpt-5.4-mini",
rewriteSelectionEffort: "minimal",
2026-06-05 04:43:00 +00:00
showToolbar: true,
sendShortcut: "mod-enter",
scrollThreadFromComposerEdges: true,
2026-05-18 08:20:16 +00:00
archiveExportEnabled: true,
archiveExportFolderTemplate: "Codex Archives",
archiveExportFilenameTemplate: "{{date}} {{time}} {{title}} {{shortId}}.md",
2026-05-19 00:27:23 +00:00
archiveExportTags: "codex, archive",
2026-05-12 15:05:56 +00:00
});
expect(settingsMatchNormalizedData({ ...settings }, settings)).toBe(true);
expect(settingsMatchNormalizedData({ ...settings, extraPanelState: {} }, settings)).toBe(false);
expect(settingsMatchNormalizedData({ ...settings, codexPath: " " }, settings)).toBe(false);
});
it("normalizes thread naming helper preferences", () => {
2026-05-12 15:05:56 +00:00
expect(normalizeSettings({ threadNamingModel: " gpt-5.4-mini ", threadNamingEffort: "low" })).toMatchObject({
threadNamingModel: "gpt-5.4-mini",
threadNamingEffort: "low",
});
expect(normalizeSettings({ threadNamingModel: 1, threadNamingEffort: "invalid" })).toMatchObject({
threadNamingModel: DEFAULT_SETTINGS.threadNamingModel,
threadNamingEffort: "invalid",
2026-05-12 15:05:56 +00:00
});
});
it("normalizes selection rewrite helper preferences", () => {
2026-05-18 02:55:43 +00:00
expect(normalizeSettings({ rewriteSelectionModel: " gpt-5.4-mini ", rewriteSelectionEffort: "minimal" })).toMatchObject({
rewriteSelectionModel: "gpt-5.4-mini",
rewriteSelectionEffort: "minimal",
});
expect(normalizeSettings({ rewriteSelectionModel: 1, rewriteSelectionEffort: "invalid" })).toMatchObject({
rewriteSelectionModel: DEFAULT_SETTINGS.rewriteSelectionModel,
rewriteSelectionEffort: "invalid",
2026-05-18 02:55:43 +00:00
});
});
it("normalizes the send shortcut", () => {
expect(normalizeSettings({ sendShortcut: "mod-enter" }).sendShortcut).toBe("mod-enter");
expect(normalizeSettings({ sendShortcut: "invalid" }).sendShortcut).toBe(DEFAULT_SETTINGS.sendShortcut);
});
2026-06-05 04:43:00 +00:00
it("shows the chat toolbar by default", () => {
expect(normalizeSettings({}).showToolbar).toBe(true);
expect(normalizeSettings({ showToolbar: false }).showToolbar).toBe(false);
expect(normalizeSettings({ showToolbar: "no" }).showToolbar).toBe(DEFAULT_SETTINGS.showToolbar);
});
it("normalizes composer edge scrolling", () => {
expect(normalizeSettings({ scrollThreadFromComposerEdges: true }).scrollThreadFromComposerEdges).toBe(true);
expect(normalizeSettings({ scrollThreadFromComposerEdges: "yes" }).scrollThreadFromComposerEdges).toBe(
DEFAULT_SETTINGS.scrollThreadFromComposerEdges,
);
});
2026-05-18 08:20:16 +00:00
it("normalizes archive export settings", () => {
expect(
normalizeSettings({
archiveExportEnabled: true,
archiveExportFolderTemplate: " Exports ",
archiveExportFilenameTemplate: " {{title}}.md ",
2026-05-19 00:27:23 +00:00
archiveExportTags: ' #codex, "archive" ',
2026-05-18 08:20:16 +00:00
}),
).toMatchObject({
archiveExportEnabled: true,
archiveExportFolderTemplate: "Exports",
archiveExportFilenameTemplate: "{{title}}.md",
2026-05-19 00:27:23 +00:00
archiveExportTags: '#codex, "archive"',
2026-05-18 08:20:16 +00:00
});
expect(
normalizeSettings({
archiveExportEnabled: "yes",
archiveExportFolderTemplate: 1,
archiveExportFilenameTemplate: " ",
2026-05-19 00:27:23 +00:00
archiveExportTags: 1,
2026-05-18 08:20:16 +00:00
}),
).toMatchObject({
archiveExportEnabled: DEFAULT_SETTINGS.archiveExportEnabled,
archiveExportFolderTemplate: DEFAULT_SETTINGS.archiveExportFolderTemplate,
archiveExportFilenameTemplate: DEFAULT_SETTINGS.archiveExportFilenameTemplate,
2026-05-19 00:27:23 +00:00
archiveExportTags: DEFAULT_SETTINGS.archiveExportTags,
2026-05-18 08:20:16 +00:00
});
});
2026-05-12 15:05:56 +00:00
it("requires a desktop filesystem vault path", () => {
const adapter = Object.create(FileSystemAdapter.prototype) as FileSystemAdapter;
Object.defineProperty(adapter, "getBasePath", { value: () => "/vault" });
expect(getVaultPath({ vault: { adapter } } as unknown as App)).toBe("/vault");
expect(() => getVaultPath({ vault: { adapter: {} } } as unknown as App)).toThrow(
"This plugin requires a desktop vault with a local basePath.",
);
});
});