import { render, screen, fireEvent } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import { PricingEditModal } from "@/components/usage/PricingEditModal"; import type { ModelPricing } from "@/types/usage"; vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string, options?: string | { defaultValue?: string }) => typeof options === "string" ? options : options?.defaultValue ?? key, }), })); vi.mock("sonner", () => ({ toast: { success: vi.fn(), error: vi.fn(), }, })); vi.mock("@/lib/query/usage", () => ({ useUpdateModelPricing: () => ({ mutateAsync: vi.fn(), isPending: false, }), })); vi.mock("@/components/common/FullScreenPanel", () => ({ FullScreenPanel: ({ children, footer, }: { children: React.ReactNode; footer?: React.ReactNode; }) => (
{children} {footer}
), })); const model: ModelPricing = { modelId: "deepseek-v4", displayName: "DeepSeek V4", inputCostPerMillion: "1", outputCostPerMillion: "3", cacheReadCostPerMillion: "0.0028", cacheCreationCostPerMillion: "0", }; const PRICE_FIELDS = [ { id: "inputCost", label: "输入成本" }, { id: "outputCost", label: "输出成本" }, { id: "cacheReadCost", label: "缓存读取成本" }, { id: "cacheCreationCost", label: "缓存写入成本" }, ] as const; describe("PricingEditModal", () => { it("all price inputs have step=0.0001", () => { render( {}} />); for (const { id } of PRICE_FIELDS) { const input = screen.getByLabelText(/每百万 tokens/ as unknown as string, { selector: `#${id}`, }) as HTMLInputElement; expect(input).toHaveAttribute("step", "0.0001"); } }); it("accepts precise cache read cost like 0.0028", () => { render( {}} />); const cacheReadInput = document.getElementById( "cacheReadCost", ) as HTMLInputElement; expect(cacheReadInput.value).toBe("0.0028"); expect(cacheReadInput.checkValidity()).toBe(true); }); it("allows user to input sub-cent prices via change event", () => { render( {}} isNew />, ); const cacheReadInput = document.getElementById( "cacheReadCost", ) as HTMLInputElement; fireEvent.change(cacheReadInput, { target: { value: "0.0015" } }); expect(cacheReadInput.value).toBe("0.0015"); }); });