114 lines · 3.2 KB · TypeScript
RawDownload
import { type ModelSlug, type ProviderKind } from "@t3tools/contracts";import { page } from "vitest/browser";import { afterEach, describe, expect, it, vi } from "vitest";import { render } from "vitest-browser-react"; import { ProviderModelPicker } from "./ProviderModelPicker"; const MODEL_OPTIONS_BY_PROVIDER = {  claudeAgent: [    { slug: "claude-opus-4-6", name: "Claude Opus 4.6" },    { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },    { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5" },  ],  codex: [    { slug: "gpt-5-codex", name: "GPT-5 Codex" },    { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" },  ],} as const satisfies Record<ProviderKind, ReadonlyArray<{ slug: ModelSlug; name: string }>>; async function mountPicker(props: {  provider: ProviderKind;  model: ModelSlug;  lockedProvider: ProviderKind | null;}) {  const host = document.createElement("div");  document.body.append(host);  const onProviderModelChange = vi.fn();  const screen = await render(    <ProviderModelPicker      provider={props.provider}      model={props.model}      lockedProvider={props.lockedProvider}      modelOptionsByProvider={MODEL_OPTIONS_BY_PROVIDER}      onProviderModelChange={onProviderModelChange}    />,    { container: host },  );   return {    onProviderModelChange,    cleanup: async () => {      await screen.unmount();      host.remove();    },  };} describe("ProviderModelPicker", () => {  afterEach(() => {    document.body.innerHTML = "";  });   it("shows provider submenus when provider switching is allowed", async () => {    const mounted = await mountPicker({      provider: "claudeAgent",      model: "claude-opus-4-6",      lockedProvider: null,    });     try {      await page.getByRole("button").click();       await vi.waitFor(() => {        const text = document.body.textContent ?? "";        expect(text).toContain("Codex");        expect(text).toContain("Claude");        expect(text).not.toContain("Claude Sonnet 4.6");      });    } finally {      await mounted.cleanup();    }  });   it("shows models directly when the provider is locked mid-thread", async () => {    const mounted = await mountPicker({      provider: "claudeAgent",      model: "claude-opus-4-6",      lockedProvider: "claudeAgent",    });     try {      await page.getByRole("button").click();       await vi.waitFor(() => {        const text = document.body.textContent ?? "";        expect(text).toContain("Claude Sonnet 4.6");        expect(text).toContain("Claude Haiku 4.5");        expect(text).not.toContain("Codex");      });    } finally {      await mounted.cleanup();    }  });   it("dispatches the canonical slug when a model is selected", async () => {    const mounted = await mountPicker({      provider: "claudeAgent",      model: "claude-opus-4-6",      lockedProvider: "claudeAgent",    });     try {      await page.getByRole("button").click();      await page.getByRole("menuitemradio", { name: "Claude Sonnet 4.6" }).click();       expect(mounted.onProviderModelChange).toHaveBeenCalledWith(        "claudeAgent",        "claude-sonnet-4-6",      );    } finally {      await mounted.cleanup();    }  });});