94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
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;
|
|
}) => (
|
|
<div>
|
|
{children}
|
|
{footer}
|
|
</div>
|
|
),
|
|
}));
|
|
|
|
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(<PricingEditModal open model={model} onClose={() => {}} />);
|
|
|
|
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(<PricingEditModal open model={model} onClose={() => {}} />);
|
|
|
|
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(
|
|
<PricingEditModal open model={model} onClose={() => {}} isNew />,
|
|
);
|
|
|
|
const cacheReadInput = document.getElementById(
|
|
"cacheReadCost",
|
|
) as HTMLInputElement;
|
|
|
|
fireEvent.change(cacheReadInput, { target: { value: "0.0015" } });
|
|
expect(cacheReadInput.value).toBe("0.0015");
|
|
});
|
|
});
|