From cb2fc70741e4c56ebff1552a255109781c1f8eaf Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 17:23:29 +0100 Subject: [PATCH] test: share chat model select state fixtures --- ui/src/ui/chat-model-select-state.test.ts | 96 ++++++++++++----------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/ui/src/ui/chat-model-select-state.test.ts b/ui/src/ui/chat-model-select-state.test.ts index 537c9a4f8aa..6fd586ced20 100644 --- a/ui/src/ui/chat-model-select-state.test.ts +++ b/ui/src/ui/chat-model-select-state.test.ts @@ -10,101 +10,113 @@ import { DEFAULT_CHAT_MODEL_CATALOG, } from "./chat-model.test-helpers.ts"; +type ChatModelStateInput = Parameters[0]; +type ResolvedChatModelState = ReturnType; + +function createChatModelState( + params: Partial> = {}, +): ChatModelStateInput { + return { + sessionKey: "main", + chatModelOverrides: {}, + chatModelCatalog: [], + sessionsResult: createSessionsListResult({ model: null, modelProvider: null }), + ...params, + }; +} + +function expectOptionValues( + resolved: ResolvedChatModelState, + params: { include?: string[]; exclude?: string[] }, +) { + const values = resolved.options.map((option) => option.value); + for (const value of params.include ?? []) { + expect(values).toContain(value); + } + for (const value of params.exclude ?? []) { + expect(values).not.toContain(value); + } +} + describe("chat-model-select-state", () => { it("uses the server-qualified value when the active session provider is present", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog(DEEPSEEK_CHAT_MODEL), sessionsResult: createSessionsListResult({ model: "deepseek-chat", modelProvider: "deepseek", }), - }; + }); expect(resolveChatModelOverrideValue(state)).toBe("deepseek/deepseek-chat"); }); it("falls back to the server-qualified value when catalog lookup fails", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, - chatModelCatalog: [], + const state = createChatModelState({ sessionsResult: createSessionsListResult({ model: "gpt-5-mini", modelProvider: "openai", }), - }; + }); expect(resolveChatModelOverrideValue(state)).toBe("openai/gpt-5-mini"); }); it("normalizes cached bare overrides to the matching catalog option", () => { - const state = { - sessionKey: "main", + const state = createChatModelState({ chatModelOverrides: { main: { kind: "raw", value: "gpt-5-mini" } }, chatModelCatalog: createModelCatalog(...DEFAULT_CHAT_MODEL_CATALOG), - sessionsResult: createSessionsListResult({ model: null, modelProvider: null }), - } as const; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).toContain("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).not.toContain("gpt-5-mini"); + expectOptionValues(resolved, { include: ["openai/gpt-5-mini"], exclude: ["gpt-5-mini"] }); }); it("prefers catalog provider matches over stale session providers", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog(DEEPSEEK_CHAT_MODEL), sessionsResult: createSessionsListResult({ model: "deepseek-chat", modelProvider: "zai", }), - }; + }); expect(resolveChatModelSelectState(state).currentOverride).toBe("deepseek/deepseek-chat"); }); it("preserves already-qualified active-session models when the provider is stale and the catalog is empty", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, - chatModelCatalog: [], + const state = createChatModelState({ sessionsResult: createSessionsListResult({ model: "openai/gpt-5-mini", modelProvider: "zai", }), - }; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).toContain("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).not.toContain("zai/openai/gpt-5-mini"); + expectOptionValues(resolved, { + include: ["openai/gpt-5-mini"], + exclude: ["zai/openai/gpt-5-mini"], + }); }); it("builds picker options without introducing a bare duplicate", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog(...DEFAULT_CHAT_MODEL_CATALOG), sessionsResult: createSessionsListResult({ model: "gpt-5-mini", modelProvider: "openai", }), - }; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).toContain("openai/gpt-5-mini"); - expect(resolved.options.map((option) => option.value)).not.toContain("gpt-5-mini"); + expectOptionValues(resolved, { include: ["openai/gpt-5-mini"], exclude: ["gpt-5-mini"] }); }); it("uses catalog names for the default label and matching picker options", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog({ id: "moonshotai/kimi-k2.5", alias: "Kimi K2.5 (NVIDIA)", @@ -117,7 +129,7 @@ describe("chat-model-select-state", () => { defaultsModel: "moonshotai/kimi-k2.5", defaultsProvider: "nvidia", }), - }; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("nvidia/moonshotai/kimi-k2.5"); @@ -129,9 +141,7 @@ describe("chat-model-select-state", () => { }); it("disambiguates duplicate friendly names in picker options and default labels", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog( { id: "claude-3-7-sonnet", @@ -150,7 +160,7 @@ describe("chat-model-select-state", () => { defaultsModel: "claude-3-7-sonnet", defaultsProvider: "openrouter", }), - }; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("anthropic/claude-3-7-sonnet"); @@ -166,9 +176,7 @@ describe("chat-model-select-state", () => { }); it("falls back to id and provider when duplicate names share the same provider", () => { - const state = { - sessionKey: "main", - chatModelOverrides: {}, + const state = createChatModelState({ chatModelCatalog: createModelCatalog( { id: "claude-3-7-sonnet", @@ -187,7 +195,7 @@ describe("chat-model-select-state", () => { defaultsModel: "claude-3-7-sonnet-thinking", defaultsProvider: "anthropic", }), - }; + }); const resolved = resolveChatModelSelectState(state); expect(resolved.currentOverride).toBe("anthropic/claude-3-7-sonnet");