fix(quick-pane): restore model catalog controls

This commit is contained in:
2026-08-25 22:34:58 +02:00
parent ab482d3daa
commit 1b0b34fad8
10 changed files with 706 additions and 170 deletions
+118
View File
@@ -0,0 +1,118 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { QuickPaneSettings, UiState } from "../workspace/types";
const mocks = vi.hoisted(() => ({
invoke: vi.fn(),
listen: vi.fn(),
hide: vi.fn(),
onFocusChanged: vi.fn(),
onCloseRequested: vi.fn(),
focusHandler: undefined as
| ((event: { payload: boolean }) => void)
| undefined,
}));
vi.mock("@tauri-apps/api/core", () => ({ invoke: mocks.invoke }));
vi.mock("@tauri-apps/api/event", () => ({ listen: mocks.listen }));
vi.mock("@tauri-apps/api/window", () => ({
getCurrentWindow: () => ({
hide: mocks.hide,
onFocusChanged: mocks.onFocusChanged,
onCloseRequested: mocks.onCloseRequested,
}),
}));
import QuickPane from "./QuickPane";
const settings: QuickPaneSettings = {
workspace: "/repo",
provider: "provider",
model: "quick/model",
followUpProvider: "provider",
followUpModel: "full/model",
instructions: "Stay read-only.",
maximumSeconds: 60,
maximumToolCalls: 6,
};
const uiState: UiState = {
version: 1,
directoryOrder: [],
runtimeOrderByDirectory: {},
drafts: {},
scroll: {},
lastSeen: {},
quickPane: settings,
};
describe("QuickPane model catalog errors", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.focusHandler = undefined;
mocks.listen.mockResolvedValue(vi.fn());
mocks.onFocusChanged.mockImplementation((handler) => {
mocks.focusHandler = handler;
return Promise.resolve(vi.fn());
});
mocks.onCloseRequested.mockResolvedValue(vi.fn());
});
it("clears a rejected focus reload after success without enabling handoff", async () => {
const user = userEvent.setup();
let catalogCalls = 0;
mocks.invoke.mockImplementation((command: string) => {
switch (command) {
case "load_ui_state":
return Promise.resolve(uiState);
case "get_model_catalog":
catalogCalls += 1;
if (catalogCalls === 2)
return Promise.reject(new Error("catalog unavailable"));
return Promise.resolve({
models: [{ provider: "provider", id: "quick/model" }],
});
case "create_quick_runtime":
return Promise.resolve({
runtime: { agentId: "agent-1", runtimeId: "runtime-1" },
});
case "get_session_runtime_snapshot":
return Promise.resolve({
runtime: {},
state: { data: { isStreaming: true } },
extensions: [],
});
default:
return Promise.resolve(undefined);
}
});
render(<QuickPane />);
await waitFor(() => expect(catalogCalls).toBe(1));
await user.type(
screen.getByPlaceholderText(/Ask a quick question/),
"Inspect",
);
await user.click(screen.getByRole("button", { name: "Ask" }));
await screen.findByText(/Quick request running/);
await act(async () => mocks.focusHandler?.({ payload: true }));
expect(
await screen.findByText(
"Could not load model catalog: Error: catalog unavailable",
),
).toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Continue" })).toBeNull();
await act(async () => mocks.focusHandler?.({ payload: true }));
await waitFor(() =>
expect(
screen.queryByText(
"Could not load model catalog: Error: catalog unavailable",
),
).toBeNull(),
);
expect(screen.queryByRole("button", { name: "Continue" })).toBeNull();
});
});