import { type ProviderModelOptions, ThreadId } from "@t3tools/contracts";
import "../../index.css";
import { page } from "vitest/browser";
import { afterEach, describe, expect, it, vi } from "vitest";
import { render } from "vitest-browser-react";
import { CompactComposerControlsMenu } from "./CompactComposerControlsMenu";
import { ClaudeTraitsMenuContent } from "./ClaudeTraitsPicker";
import { CodexTraitsMenuContent } from "./CodexTraitsPicker";
import { useComposerDraftStore } from "../../composerDraftStore";
async function mountMenu(props?: {
model?: string;
prompt?: string;
provider?: "codex" | "claudeAgent";
modelOptions?: ProviderModelOptions | null;
}) {
const threadId = ThreadId.makeUnsafe("thread-compact-menu");
const provider = props?.provider ?? "claudeAgent";
const draftsByThreadId = {} as ReturnType<
typeof useComposerDraftStore.getState
>["draftsByThreadId"];
draftsByThreadId[threadId] = {
prompt: props?.prompt ?? "",
images: [],
nonPersistedImageIds: [],
persistedAttachments: [],
terminalContexts: [],
provider,
model: props?.model ?? "claude-opus-4-6",
modelOptions: props?.modelOptions ?? null,
runtimeMode: null,
interactionMode: null,
};
useComposerDraftStore.setState({
draftsByThreadId,
draftThreadsByThreadId: {},
projectDraftThreadIdByProjectId: {},
});
const host = document.createElement("div");
document.body.append(host);
const onPromptChange = vi.fn();
const screen = await render(
) : (
)
}
onToggleInteractionMode={vi.fn()}
onTogglePlanSidebar={vi.fn()}
onToggleRuntimeMode={vi.fn()}
/>,
{ container: host },
);
return {
cleanup: async () => {
await screen.unmount();
host.remove();
},
};
}
describe("CompactComposerControlsMenu", () => {
afterEach(() => {
document.body.innerHTML = "";
useComposerDraftStore.setState({
draftsByThreadId: {},
draftThreadsByThreadId: {},
projectDraftThreadIdByProjectId: {},
});
});
it("shows fast mode controls for Opus", async () => {
const mounted = await mountMenu();
try {
await page.getByLabelText("More composer controls").click();
await vi.waitFor(() => {
const text = document.body.textContent ?? "";
expect(text).toContain("Fast Mode");
expect(text).toContain("off");
expect(text).toContain("on");
});
} finally {
await mounted.cleanup();
}
});
it("hides fast mode controls for non-Opus Claude models", async () => {
const mounted = await mountMenu({ model: "claude-sonnet-4-6" });
try {
await page.getByLabelText("More composer controls").click();
await vi.waitFor(() => {
expect(document.body.textContent ?? "").not.toContain("Fast Mode");
});
} finally {
await mounted.cleanup();
}
});
it("shows only the provided effort options", async () => {
const mounted = await mountMenu({
model: "claude-sonnet-4-6",
});
try {
await page.getByLabelText("More composer controls").click();
await vi.waitFor(() => {
const text = document.body.textContent ?? "";
expect(text).toContain("Low");
expect(text).toContain("Medium");
expect(text).toContain("High");
expect(text).not.toContain("Max");
expect(text).toContain("Ultrathink");
});
} finally {
await mounted.cleanup();
}
});
it("shows a Claude thinking on/off section for Haiku", async () => {
const mounted = await mountMenu({
model: "claude-haiku-4-5",
modelOptions: {
claudeAgent: {
thinking: true,
},
},
});
try {
await page.getByLabelText("More composer controls").click();
await vi.waitFor(() => {
const text = document.body.textContent ?? "";
expect(text).toContain("Thinking");
expect(text).toContain("On (default)");
expect(text).toContain("Off");
});
} finally {
await mounted.cleanup();
}
});
it("shows prompt-controlled Ultrathink messaging with disabled effort controls", async () => {
const mounted = await mountMenu({
model: "claude-opus-4-6",
prompt: "Ultrathink:\nInvestigate this",
modelOptions: {
claudeAgent: {
effort: "high",
},
},
});
try {
await page.getByLabelText("More composer controls").click();
await vi.waitFor(() => {
const text = document.body.textContent ?? "";
expect(text).toContain("Effort");
expect(text).toContain("Remove Ultrathink from the prompt to change effort.");
expect(text).not.toContain("Fallback Effort");
});
} finally {
await mounted.cleanup();
}
});
});