fix(quick-pane): load fresh categorized models

This commit is contained in:
2026-08-26 18:27:05 +02:00
parent ad66067a31
commit 05874a0be1
2 changed files with 160 additions and 4 deletions
+141
View File
@@ -134,6 +134,41 @@ function bridgeMock(
return { runtimeCount: () => runtimeCount };
}
function deferredCatalogBridge() {
const firstSnapshot = deferred<RuntimeSnapshot>();
const staleModels: Model[] = [
{ provider: "provider", id: "stale/model", name: "Stale" },
];
const freshModels: Model[] = [
{ provider: "provider", id: "fresh/model", name: "Fresh" },
];
let runtimeCount = 0;
mocks.invoke.mockImplementation(
(command: string, payload?: { runtimeId?: string }) => {
if (command === "load_ui_state") return Promise.resolve(uiState);
if (command === "create_quick_runtime") {
runtimeCount += 1;
return Promise.resolve({
runtime: {
agentId: `agent-${runtimeCount}`,
runtimeId: `runtime-${runtimeCount}`,
},
});
}
if (command === "get_session_runtime_snapshot") {
if (payload?.runtimeId === "runtime-1") return firstSnapshot.promise;
return Promise.resolve(runtimeSnapshot(freshModels));
}
return Promise.resolve(undefined);
},
);
return {
firstSnapshot,
staleModels,
runtimeCount: () => runtimeCount,
};
}
async function preparedTrigger() {
return screen.findByRole("button", { name: /provider ·/i });
}
@@ -578,6 +613,112 @@ describe("QuickPane fresh runtime catalog", () => {
});
});
it.each([
{
action: "Close",
dismiss: async () => {
await userEvent.click(
screen.getByRole("button", { name: "Close Quick Pane" }),
);
},
},
{
action: "Escape",
dismiss: async () => {
fireEvent.keyDown(window, { key: "Escape" });
},
},
])(
"discards deferred catalog preparation after $action dismissal",
async ({ dismiss }) => {
const tracker = deferredCatalogBridge();
render(<QuickPane />);
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith(
"get_session_runtime_snapshot",
{ runtimeId: "runtime-1" },
),
);
await dismiss();
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith("dismiss_quick_pane"),
);
await act(async () =>
tracker.firstSnapshot.resolve(runtimeSnapshot(tracker.staleModels)),
);
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith("close_quick_runtime", {
runtimeId: "runtime-1",
}),
);
expect(
screen.queryByRole("button", { name: /provider · Stale/i }),
).toBeNull();
await act(async () => mocks.focusHandler?.({ payload: true }));
expect(
await screen.findByRole("button", { name: /provider · Fresh/i }),
).toBeInTheDocument();
expect(tracker.runtimeCount()).toBe(2);
await ask();
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith("set_model", {
agentId: "agent-2",
provider: "provider",
modelId: "fresh/model",
}),
);
expect(mocks.invoke).not.toHaveBeenCalledWith(
"set_model",
expect.objectContaining({ agentId: "agent-1" }),
);
},
);
it("discards deferred catalog preparation after idle focus loss", async () => {
const tracker = deferredCatalogBridge();
render(<QuickPane />);
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith(
"get_session_runtime_snapshot",
{ runtimeId: "runtime-1" },
),
);
await act(async () => mocks.focusHandler?.({ payload: false }));
expect(mocks.invoke).not.toHaveBeenCalledWith("dismiss_quick_pane");
await act(async () =>
tracker.firstSnapshot.resolve(runtimeSnapshot(tracker.staleModels)),
);
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith("close_quick_runtime", {
runtimeId: "runtime-1",
}),
);
expect(
screen.queryByRole("button", { name: /provider · Stale/i }),
).toBeNull();
await act(async () => mocks.focusHandler?.({ payload: true }));
expect(
await screen.findByRole("button", { name: /provider · Fresh/i }),
).toBeInTheDocument();
expect(tracker.runtimeCount()).toBe(2);
await ask();
await waitFor(() =>
expect(mocks.invoke).toHaveBeenCalledWith("set_model", {
agentId: "agent-2",
provider: "provider",
modelId: "fresh/model",
}),
);
expect(mocks.invoke).not.toHaveBeenCalledWith(
"set_model",
expect.objectContaining({ agentId: "agent-1" }),
);
});
it("retains a prior runtime when close fails and retries before replacement", async () => {
let runtimeCount = 0;
let closeAttempts = 0;