diff options
| author | Adam Malczewski <[email protected]> | 2026-08-26 00:08:40 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-08-26 00:08:40 +0900 |
| commit | 33c7245f18346553f660434bc3ac589cff3e80c2 (patch) | |
| tree | 202002771681259446ed95506b4fbb6adece2fd8 /src/app/store.test.ts | |
| parent | 4e56e548872a162129efee1b09987af7893b0e0c (diff) | |
| download | dispatch-web-33c7245f18346553f660434bc3ac589cff3e80c2.tar.gz dispatch-web-33c7245f18346553f660434bc3ac589cff3e80c2.zip | |
fix(tabs): stamp tabs with the conversation's persisted model (conv.model), not activeModel
Diffstat (limited to 'src/app/store.test.ts')
| -rw-r--r-- | src/app/store.test.ts | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/app/store.test.ts b/src/app/store.test.ts index c41efc2..f8b878a 100644 --- a/src/app/store.test.ts +++ b/src/app/store.test.ts @@ -799,6 +799,88 @@ describe("createAppStore", () => { store.dispose(); }); + it("fetchOpenConversations stamps tabs with the conversation's persisted model (not the global active model)", async () => { + const ws = fakeSocket(); + const fetchImpl: typeof fetch = async ( + input: string | URL | Request, + init?: RequestInit, + ): Promise<Response> => { + const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url; + if (url.endsWith("/models")) { + return new Response(JSON.stringify({ models: ["opencode-1/deepseek-v4-flash"] }), { + status: 200, + }); + } + // The authoritative open-conversation list — one conversation whose + // persisted model differs from the global activeModel. + if (url.includes("/conversations?status=")) { + return new Response( + JSON.stringify({ + conversations: [ + { + id: "conv-model", + createdAt: 1000, + lastActivityAt: 2000, + title: "Model conv", + status: "idle", + workspaceId: "default", + model: "openrouter/stealth/ox-alpha", + }, + ], + }), + { status: 200 }, + ); + } + return new Response(JSON.stringify({ chunks: [], latestSeq: 0 }), { status: 200 }); + }; + + const store = createAppStore({ + socketFactory: () => ws, + fetchImpl, + localStorage: createFakeStorage(), + }); + ws.resolveOpen(); + + // global activeModel is the default until anything changes it + expect(store.activeModel).toBe("opencode-1/deepseek-v4-flash"); + + // fetchOpenConversations (boot reconcile) opens the conversation's tab — + // stamped with the PERSISTED model from the list, not activeModel. + await vi.waitFor(() => { + const tab = store.tabs.find((t) => t.conversationId === "conv-model"); + expect(tab?.model).toBe("openrouter/stealth/ox-alpha"); + }); + + store.dispose(); + }); + + it("conversation.open WS message carrying a model stamps the tab with it", async () => { + const ws = fakeSocket(); + const store = createAppStore({ + socketFactory: () => ws, + fetchImpl: fakeFetchImpl(), + localStorage: createFakeStorage(), + }); + ws.resolveOpen(); + + // The user stays on their current (draft) tab; the backend broadcasts + // `conversation.open` with the conversation's persisted model. + ws.feedServerMessage({ + type: "conversation.open", + conversationId: "conv-ws", + workspaceId: "default", + model: "openrouter/stealth/ox-alpha", + }); + + await vi.waitFor(() => { + const tab = store.tabs.find((t) => t.conversationId === "conv-ws"); + expect(tab?.model).toBe("openrouter/stealth/ox-alpha"); + expect(tab?.workspaceId).toBe("default"); + }); + + store.dispose(); + }); + it("chat.delta routes to the matching tab only", () => { const ws = fakeSocket(); const store = createAppStore({ |
