diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/add_margin_form.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/add_margin_form.test.tsx
new file mode 100644
index 00000000000..d61f0987ac2
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/add_margin_form.test.tsx
@@ -0,0 +1,148 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import AddMarginForm from "./add_margin_form";
+import { MarginConfig } from "./types";
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: {
+ OpenAI: "OpenAI",
+ Anthropic: "Anthropic",
+ },
+ provider_map: {
+ OpenAI: "openai",
+ Anthropic: "anthropic",
+ },
+ providerLogoMap: {
+ OpenAI: "https://example.com/openai.png",
+ Anthropic: "https://example.com/anthropic.png",
+ },
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ handleImageError: vi.fn(),
+}));
+
+const DEFAULT_PROPS = {
+ marginConfig: {} as MarginConfig,
+ selectedProvider: undefined,
+ marginType: "percentage" as const,
+ percentageValue: "",
+ fixedAmountValue: "",
+ onProviderChange: vi.fn(),
+ onMarginTypeChange: vi.fn(),
+ onPercentageChange: vi.fn(),
+ onFixedAmountChange: vi.fn(),
+ onAddProvider: vi.fn(),
+};
+
+describe("AddMarginForm", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getByRole("button", { name: /add provider margin/i })).toBeInTheDocument();
+ });
+
+ it("should show the percentage input when marginType is percentage", () => {
+ renderWithProviders();
+ expect(screen.getByPlaceholderText("10")).toBeInTheDocument();
+ });
+
+ it("should show the fixed amount input when marginType is fixed", () => {
+ renderWithProviders();
+ expect(screen.getByPlaceholderText("0.001")).toBeInTheDocument();
+ });
+
+ it("should not show the fixed amount input when marginType is percentage", () => {
+ renderWithProviders();
+ expect(screen.queryByPlaceholderText("0.001")).not.toBeInTheDocument();
+ });
+
+ it("should not show the percentage input when marginType is fixed", () => {
+ renderWithProviders();
+ expect(screen.queryByPlaceholderText("10")).not.toBeInTheDocument();
+ });
+
+ it("should show the Percentage-based and Fixed Amount radio options", () => {
+ renderWithProviders();
+ expect(screen.getByText("Percentage-based")).toBeInTheDocument();
+ expect(screen.getByText("Fixed Amount")).toBeInTheDocument();
+ });
+
+ it("should disable the submit button when no provider is selected (percentage mode)", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider margin/i })).toBeDisabled();
+ });
+
+ it("should disable the submit button when provider is selected but no percentage value (percentage mode)", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider margin/i })).toBeDisabled();
+ });
+
+ it("should enable the submit button when provider and percentage value are both provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled();
+ });
+
+ it("should disable the submit button in fixed mode when no fixed amount is provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider margin/i })).toBeDisabled();
+ });
+
+ it("should enable the submit button in fixed mode when provider and fixed amount are provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled();
+ });
+
+ it("should call onAddProvider when the enabled submit button is clicked", async () => {
+ const onAddProvider = vi.fn();
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /add provider margin/i }));
+ expect(onAddProvider).toHaveBeenCalledTimes(1);
+ });
+
+ it("should call onMarginTypeChange when the Fixed Amount radio is clicked", async () => {
+ const onMarginTypeChange = vi.fn();
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByText("Fixed Amount"));
+ expect(onMarginTypeChange).toHaveBeenCalledWith("fixed");
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/add_provider_form.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/add_provider_form.test.tsx
new file mode 100644
index 00000000000..611c8609c36
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/add_provider_form.test.tsx
@@ -0,0 +1,98 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import AddProviderForm from "./add_provider_form";
+import { DiscountConfig } from "./types";
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: {
+ OpenAI: "OpenAI",
+ Anthropic: "Anthropic",
+ },
+ provider_map: {
+ OpenAI: "openai",
+ Anthropic: "anthropic",
+ },
+ providerLogoMap: {
+ OpenAI: "https://example.com/openai.png",
+ Anthropic: "https://example.com/anthropic.png",
+ },
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ handleImageError: vi.fn(),
+}));
+
+const DEFAULT_PROPS = {
+ discountConfig: {} as DiscountConfig,
+ selectedProvider: undefined,
+ newDiscount: "",
+ onProviderChange: vi.fn(),
+ onDiscountChange: vi.fn(),
+ onAddProvider: vi.fn(),
+};
+
+describe("AddProviderForm", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getByRole("button", { name: /add provider discount/i })).toBeInTheDocument();
+ });
+
+ it("should render the discount percentage input field", () => {
+ renderWithProviders();
+ expect(screen.getByPlaceholderText("5")).toBeInTheDocument();
+ });
+
+ it("should disable the submit button when no provider is selected and no discount is entered", () => {
+ renderWithProviders();
+ expect(screen.getByRole("button", { name: /add provider discount/i })).toBeDisabled();
+ });
+
+ it("should disable the submit button when a provider is selected but no discount is entered", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider discount/i })).toBeDisabled();
+ });
+
+ it("should disable the submit button when a discount is entered but no provider is selected", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider discount/i })).toBeDisabled();
+ });
+
+ it("should enable the submit button when both a provider and a discount value are provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("button", { name: /add provider discount/i })).not.toBeDisabled();
+ });
+
+ it("should call onAddProvider when the enabled submit button is clicked", async () => {
+ const onAddProvider = vi.fn();
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /add provider discount/i }));
+ expect(onAddProvider).toHaveBeenCalledTimes(1);
+ });
+
+ it("should show the percent sign next to the discount input", () => {
+ renderWithProviders();
+ expect(screen.getByText("%")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/cost_tracking_settings.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/cost_tracking_settings.test.tsx
new file mode 100644
index 00000000000..db6899ba17f
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/cost_tracking_settings.test.tsx
@@ -0,0 +1,201 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import CostTrackingSettings from "./cost_tracking_settings";
+
+// Mock sub-hooks so we can control their state without network calls
+const mockDiscountConfig = vi.fn(() => ({}));
+const mockMarginConfig = vi.fn(() => ({}));
+
+vi.mock("./use_discount_config", () => ({
+ useDiscountConfig: () => ({
+ discountConfig: mockDiscountConfig(),
+ fetchDiscountConfig: vi.fn().mockResolvedValue(undefined),
+ handleAddProvider: vi.fn().mockResolvedValue(true),
+ handleRemoveProvider: vi.fn().mockResolvedValue(undefined),
+ handleDiscountChange: vi.fn().mockResolvedValue(undefined),
+ }),
+}));
+
+vi.mock("./use_margin_config", () => ({
+ useMarginConfig: () => ({
+ marginConfig: mockMarginConfig(),
+ fetchMarginConfig: vi.fn().mockResolvedValue(undefined),
+ handleAddMargin: vi.fn().mockResolvedValue(true),
+ handleRemoveMargin: vi.fn().mockResolvedValue(undefined),
+ handleMarginChange: vi.fn().mockResolvedValue(undefined),
+ }),
+}));
+
+vi.mock("./pricing_calculator/index", () => ({
+ default: () =>
Pricing Calculator
,
+}));
+
+vi.mock("../playground/llm_calls/fetch_models", () => ({
+ fetchAvailableModels: vi.fn().mockResolvedValue([]),
+}));
+
+vi.mock("../HelpLink", () => ({
+ DocsMenu: () => null,
+}));
+
+vi.mock("./how_it_works", () => ({
+ default: () => How It Works
,
+}));
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: { OpenAI: "OpenAI" },
+ provider_map: { OpenAI: "openai" },
+ providerLogoMap: {},
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ getProviderDisplayInfo: vi.fn(() => ({ displayName: "OpenAI", logo: "", enumKey: "OpenAI" })),
+ handleImageError: vi.fn(),
+}));
+
+const ADMIN_PROPS = {
+ userID: "user-1",
+ userRole: "proxy_admin",
+ accessToken: "test-token",
+};
+
+describe("CostTrackingSettings", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockDiscountConfig.mockReturnValue({});
+ mockMarginConfig.mockReturnValue({});
+ });
+
+ it("should return nothing when accessToken is null", () => {
+ const { container } = renderWithProviders(
+
+ );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should render the page title", () => {
+ renderWithProviders();
+ expect(screen.getByText("Cost Tracking Settings")).toBeInTheDocument();
+ });
+
+ it("should show the Provider Discounts accordion header for proxy_admin", () => {
+ renderWithProviders();
+ expect(screen.getByText("Provider Discounts")).toBeInTheDocument();
+ });
+
+ it("should show the Fee/Price Margin accordion header for proxy_admin", () => {
+ renderWithProviders();
+ expect(screen.getByText("Fee/Price Margin")).toBeInTheDocument();
+ });
+
+ it("should always show the Pricing Calculator section", () => {
+ renderWithProviders();
+ // The accordion header text appears in the DOM; getAllByText tolerates duplicates
+ expect(screen.getAllByText("Pricing Calculator").length).toBeGreaterThan(0);
+ });
+
+ it("should show the pricing calculator component", async () => {
+ renderWithProviders();
+ expect(await screen.findByTestId("pricing-calculator")).toBeInTheDocument();
+ });
+
+ it("should not show Provider Discounts section for a non-admin role", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.queryByText("Provider Discounts")).not.toBeInTheDocument();
+ });
+
+ it("should not show Fee/Price Margin section for a non-admin role", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.queryByText("Fee/Price Margin")).not.toBeInTheDocument();
+ });
+
+ it("should show Provider Discounts for the 'Admin' role as well", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Provider Discounts")).toBeInTheDocument();
+ });
+
+ it("should show the subtitle describing discount/margin configuration", () => {
+ renderWithProviders();
+ expect(
+ screen.getByText(/configure cost discounts and margins/i)
+ ).toBeInTheDocument();
+ });
+
+ describe("Add Provider Discount modal", () => {
+ it("should open the Add Provider Discount modal when the button is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ // The button lives inside the Provider Discounts accordion — click the header to expand first
+ const accordionHeader = screen.getByText("Provider Discounts").closest("button");
+ if (accordionHeader) {
+ await user.click(accordionHeader);
+ }
+
+ const addButton = await screen.findByRole("button", { name: /add provider discount/i });
+ await user.click(addButton);
+
+ expect(
+ await screen.findByText("Add Provider Discount", { selector: "h2" })
+ ).toBeInTheDocument();
+ });
+ });
+
+ describe("Add Provider Margin modal", () => {
+ it("should open the Add Provider Margin modal when the button is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const accordionHeader = screen.getByText("Fee/Price Margin").closest("button");
+ if (accordionHeader) {
+ await user.click(accordionHeader);
+ }
+
+ const addButton = await screen.findByRole("button", { name: /add provider margin/i });
+ await user.click(addButton);
+
+ expect(
+ await screen.findByText("Add Provider Margin", { selector: "h2" })
+ ).toBeInTheDocument();
+ });
+ });
+
+ describe("empty state messages", () => {
+ it("should show the empty state message when no discount config is loaded", async () => {
+ mockDiscountConfig.mockReturnValue({});
+ renderWithProviders();
+
+ const accordionHeader = screen.getByText("Provider Discounts").closest("button");
+ if (accordionHeader) {
+ await userEvent.setup().click(accordionHeader);
+ }
+
+ expect(
+ await screen.findByText(/no provider discounts configured/i)
+ ).toBeInTheDocument();
+ });
+
+ it("should show the empty state message when no margin config is loaded", async () => {
+ mockMarginConfig.mockReturnValue({});
+ renderWithProviders();
+
+ const accordionHeader = screen.getByText("Fee/Price Margin").closest("button");
+ if (accordionHeader) {
+ await userEvent.setup().click(accordionHeader);
+ }
+
+ expect(
+ await screen.findByText(/no provider margins configured/i)
+ ).toBeInTheDocument();
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/how_it_works.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/how_it_works.test.tsx
new file mode 100644
index 00000000000..fa608f555ce
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/how_it_works.test.tsx
@@ -0,0 +1,95 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import HowItWorks from "./how_it_works";
+
+vi.mock("@/app/(dashboard)/api-reference/components/CodeBlock", () => ({
+ default: ({ code }: { code: string }) => {code},
+}));
+
+describe("HowItWorks", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getByText("Cost Calculation")).toBeInTheDocument();
+ });
+
+ it("should display the cost calculation formula", () => {
+ renderWithProviders();
+ expect(screen.getByText(/final_cost = base_cost/i)).toBeInTheDocument();
+ });
+
+ it("should display the valid range information", () => {
+ renderWithProviders();
+ expect(screen.getByText(/0% and 100%/i)).toBeInTheDocument();
+ });
+
+ it("should render the code block with a curl example", () => {
+ renderWithProviders();
+ expect(screen.getByTestId("code-block")).toBeInTheDocument();
+ expect(screen.getByTestId("code-block").textContent).toContain("curl");
+ });
+
+ it("should show the response header names for discount verification", () => {
+ renderWithProviders();
+ expect(screen.getByText("x-litellm-response-cost")).toBeInTheDocument();
+ expect(screen.getByText("x-litellm-response-cost-original")).toBeInTheDocument();
+ expect(screen.getByText("x-litellm-response-cost-discount-amount")).toBeInTheDocument();
+ });
+
+ it("should not show calculated results initially when no input is provided", () => {
+ renderWithProviders();
+ expect(screen.queryByText("Calculated Results")).not.toBeInTheDocument();
+ });
+
+ it("should not show calculated results when only response cost is entered", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const responseCostInput = screen.getByPlaceholderText("0.0171938125");
+ await user.type(responseCostInput, "0.01");
+
+ expect(screen.queryByText("Calculated Results")).not.toBeInTheDocument();
+ });
+
+ it("should not show calculated results when only discount amount is entered", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const discountAmountInput = screen.getByPlaceholderText("0.0009049375");
+ await user.type(discountAmountInput, "0.001");
+
+ expect(screen.queryByText("Calculated Results")).not.toBeInTheDocument();
+ });
+
+ it("should show calculated results when both fields are filled", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ const responseCostInput = screen.getByPlaceholderText("0.0171938125");
+ const discountAmountInput = screen.getByPlaceholderText("0.0009049375");
+
+ await user.type(responseCostInput, "0.0171938125");
+ await user.type(discountAmountInput, "0.0009049375");
+
+ expect(await screen.findByText("Calculated Results")).toBeInTheDocument();
+ });
+
+ it("should show original cost, final cost, and discount amount in results", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+
+ await user.type(screen.getByPlaceholderText("0.0171938125"), "0.0171938125");
+ await user.type(screen.getByPlaceholderText("0.0009049375"), "0.0009049375");
+
+ expect(await screen.findByText("Original Cost:")).toBeInTheDocument();
+ expect(screen.getByText("Final Cost:")).toBeInTheDocument();
+ expect(screen.getByText("Discount Amount:")).toBeInTheDocument();
+ expect(screen.getByText("Discount Applied:")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_discount_table.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_discount_table.test.tsx
new file mode 100644
index 00000000000..7697c6e7686
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_discount_table.test.tsx
@@ -0,0 +1,241 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen, within } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import ProviderDiscountTable from "./provider_discount_table";
+
+vi.mock("@heroicons/react/outline", () => ({
+ TrashIcon: function TrashIcon() { return null; },
+ PencilAltIcon: function PencilAltIcon() { return null; },
+ CheckIcon: function CheckIcon() { return null; },
+ XIcon: function XIcon() { return null; },
+}));
+
+vi.mock("@tremor/react", () => ({
+ Table: ({ children }: any) => ,
+ TableHead: ({ children }: any) => {children},
+ TableRow: ({ children }: any) => {children}
,
+ TableHeaderCell: ({ children }: any) => {children} | ,
+ TableBody: ({ children }: any) => {children},
+ TableCell: ({ children }: any) => {children} | ,
+ Text: ({ children }: any) => {children},
+ TextInput: ({ value, onValueChange, onKeyDown, placeholder, ...rest }: any) => (
+ onValueChange?.(e.target.value)}
+ onKeyDown={onKeyDown}
+ placeholder={placeholder}
+ {...rest}
+ />
+ ),
+ Icon: ({ icon: IconComponent, onClick }: any) => {
+ const name = IconComponent?.displayName ?? IconComponent?.name ?? "icon";
+ return ;
+ },
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ getProviderDisplayInfo: vi.fn((providerValue: string) => ({
+ displayName: providerValue === "openai" ? "OpenAI" : providerValue,
+ logo: providerValue === "openai" ? "https://example.com/openai.png" : "",
+ enumKey: providerValue === "openai" ? "OpenAI" : null,
+ })),
+ handleImageError: vi.fn(),
+}));
+
+const DEFAULT_DISCOUNT_CONFIG = {
+ openai: 0.05,
+ anthropic: 0.1,
+};
+
+describe("ProviderDiscountTable", () => {
+ const onDiscountChange = vi.fn();
+ const onRemoveProvider = vi.fn();
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("table")).toBeInTheDocument();
+ });
+
+ it("should render the table headers", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Provider")).toBeInTheDocument();
+ expect(screen.getByText("Discount Percentage")).toBeInTheDocument();
+ expect(screen.getByText("Actions")).toBeInTheDocument();
+ });
+
+ it("should display provider display names in the table", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("OpenAI")).toBeInTheDocument();
+ });
+
+ it("should display the formatted discount percentage", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("5.0%")).toBeInTheDocument();
+ });
+
+ it("should show a text input when the edit icon is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ const pencilButton = screen.getByRole("button", { name: /PencilAltIcon/i });
+ await user.click(pencilButton);
+
+ expect(screen.getByPlaceholderText("5")).toBeInTheDocument();
+ });
+
+ it("should hide the formatted percentage when in edit mode", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+
+ expect(screen.queryByText("5.0%")).not.toBeInTheDocument();
+ });
+
+ it("should call onDiscountChange with the new value when the save icon is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+
+ const input = screen.getByPlaceholderText("5");
+ await user.clear(input);
+ await user.type(input, "10");
+
+ await user.click(screen.getByRole("button", { name: /CheckIcon/i }));
+
+ expect(onDiscountChange).toHaveBeenCalledWith("openai", "0.1");
+ });
+
+ it("should restore the display view after saving", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+ await user.click(screen.getByRole("button", { name: /CheckIcon/i }));
+
+ expect(screen.queryByPlaceholderText("5")).not.toBeInTheDocument();
+ });
+
+ it("should cancel edit mode when the cancel icon is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+ await user.click(screen.getByRole("button", { name: /XIcon/i }));
+
+ expect(screen.queryByPlaceholderText("5")).not.toBeInTheDocument();
+ expect(onDiscountChange).not.toHaveBeenCalled();
+ expect(screen.getByText("5.0%")).toBeInTheDocument();
+ });
+
+ it("should not call onDiscountChange when canceling edit", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+ await user.click(screen.getByRole("button", { name: /XIcon/i }));
+
+ expect(onDiscountChange).not.toHaveBeenCalled();
+ });
+
+ it("should call onRemoveProvider with the provider key and display name when the trash icon is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /TrashIcon/i }));
+
+ expect(onRemoveProvider).toHaveBeenCalledWith("openai", "OpenAI");
+ });
+
+ it("should not call onDiscountChange when the entered value is out of range", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+ const input = screen.getByPlaceholderText("5");
+ await user.clear(input);
+ await user.type(input, "150");
+ await user.click(screen.getByRole("button", { name: /CheckIcon/i }));
+
+ expect(onDiscountChange).not.toHaveBeenCalled();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_display_helpers.test.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_display_helpers.test.ts
new file mode 100644
index 00000000000..9668f07c2c5
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_display_helpers.test.ts
@@ -0,0 +1,91 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { getProviderDisplayInfo, getProviderBackendValue, handleImageError } from "./provider_display_helpers";
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: {
+ OpenAI: "OpenAI",
+ Anthropic: "Anthropic",
+ Azure: "Azure",
+ },
+ provider_map: {
+ OpenAI: "openai",
+ Anthropic: "anthropic",
+ Azure: "azure",
+ },
+ providerLogoMap: {
+ OpenAI: "https://example.com/openai.png",
+ Anthropic: "https://example.com/anthropic.png",
+ Azure: "https://example.com/azure.png",
+ },
+}));
+
+describe("getProviderDisplayInfo", () => {
+ it("should return display name and logo for a known backend provider value", () => {
+ const info = getProviderDisplayInfo("openai");
+ expect(info.displayName).toBe("OpenAI");
+ expect(info.logo).toBe("https://example.com/openai.png");
+ expect(info.enumKey).toBe("OpenAI");
+ });
+
+ it("should return the raw value as display name for an unknown provider", () => {
+ const info = getProviderDisplayInfo("my-custom-provider");
+ expect(info.displayName).toBe("my-custom-provider");
+ expect(info.logo).toBe("");
+ expect(info.enumKey).toBeNull();
+ });
+
+ it("should match a provider by its backend value regardless of casing", () => {
+ const info = getProviderDisplayInfo("anthropic");
+ expect(info.displayName).toBe("Anthropic");
+ expect(info.enumKey).toBe("Anthropic");
+ });
+});
+
+describe("getProviderBackendValue", () => {
+ it("should return the backend value for a known provider enum key", () => {
+ expect(getProviderBackendValue("OpenAI")).toBe("openai");
+ });
+
+ it("should return the backend value for another known provider", () => {
+ expect(getProviderBackendValue("Anthropic")).toBe("anthropic");
+ });
+
+ it("should return null for an unknown enum key", () => {
+ expect(getProviderBackendValue("UnknownProvider")).toBeNull();
+ });
+});
+
+describe("handleImageError", () => {
+ it("should replace the img element with a fallback div showing the first letter", () => {
+ const img = document.createElement("img");
+ const parent = document.createElement("div");
+ parent.appendChild(img);
+
+ const event = { target: img } as any;
+ handleImageError(event, "OpenAI");
+
+ expect(parent.querySelector("img")).toBeNull();
+ const fallback = parent.firstChild as HTMLElement;
+ expect(fallback.tagName).toBe("DIV");
+ expect(fallback.textContent).toBe("O");
+ });
+
+ it("should use the first character of the fallback text as the label", () => {
+ const img = document.createElement("img");
+ const parent = document.createElement("div");
+ parent.appendChild(img);
+
+ const event = { target: img } as any;
+ handleImageError(event, "Anthropic");
+
+ const fallback = parent.firstChild as HTMLElement;
+ expect(fallback.textContent).toBe("A");
+ });
+
+ it("should do nothing if the image has no parent element", () => {
+ const img = document.createElement("img");
+ const event = { target: img } as any;
+ // Should not throw
+ expect(() => handleImageError(event, "OpenAI")).not.toThrow();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_margin_table.test.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_margin_table.test.tsx
new file mode 100644
index 00000000000..1ad937e6cb4
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/provider_margin_table.test.tsx
@@ -0,0 +1,246 @@
+import React from "react";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { renderWithProviders } from "../../../tests/test-utils";
+import ProviderMarginTable from "./provider_margin_table";
+
+vi.mock("@heroicons/react/outline", () => ({
+ TrashIcon: function TrashIcon() { return null; },
+ PencilAltIcon: function PencilAltIcon() { return null; },
+ CheckIcon: function CheckIcon() { return null; },
+ XIcon: function XIcon() { return null; },
+}));
+
+vi.mock("@tremor/react", () => ({
+ Table: ({ children }: any) => ,
+ TableHead: ({ children }: any) => {children},
+ TableRow: ({ children }: any) => {children}
,
+ TableHeaderCell: ({ children }: any) => {children} | ,
+ TableBody: ({ children }: any) => {children},
+ TableCell: ({ children }: any) => {children} | ,
+ Text: ({ children }: any) => {children},
+ TextInput: ({ value, onValueChange, placeholder, autoFocus, className }: any) => (
+ onValueChange?.(e.target.value)}
+ placeholder={placeholder}
+ autoFocus={autoFocus}
+ className={className}
+ />
+ ),
+ Icon: ({ icon: IconComponent, onClick }: any) => {
+ const name = IconComponent?.displayName ?? IconComponent?.name ?? "icon";
+ return ;
+ },
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ getProviderDisplayInfo: vi.fn((providerValue: string) => {
+ if (providerValue === "openai") return { displayName: "OpenAI", logo: "", enumKey: "OpenAI" };
+ if (providerValue === "anthropic") return { displayName: "Anthropic", logo: "", enumKey: "Anthropic" };
+ return { displayName: providerValue, logo: "", enumKey: null };
+ }),
+ handleImageError: vi.fn(),
+}));
+
+describe("ProviderMarginTable", () => {
+ const onMarginChange = vi.fn();
+ const onRemoveProvider = vi.fn();
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByRole("table")).toBeInTheDocument();
+ });
+
+ it("should render the table headers", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Provider")).toBeInTheDocument();
+ expect(screen.getByText("Margin")).toBeInTheDocument();
+ expect(screen.getByText("Actions")).toBeInTheDocument();
+ });
+
+ it("should display the provider display name", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("OpenAI")).toBeInTheDocument();
+ });
+
+ it("should display the global provider as 'Global (All Providers)'", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Global (All Providers)")).toBeInTheDocument();
+ });
+
+ it("should display a numeric margin as a percentage", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("10.0%")).toBeInTheDocument();
+ });
+
+ it("should display a fixed amount margin with dollar sign", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("$0.001000")).toBeInTheDocument();
+ });
+
+ it("should display a combined percentage and fixed margin", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText(/10\.0%.*\$0\.001000/)).toBeInTheDocument();
+ });
+
+ it("should show edit inputs when the pencil icon is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+
+ expect(screen.getByPlaceholderText("10")).toBeInTheDocument();
+ expect(screen.getByPlaceholderText("0.001")).toBeInTheDocument();
+ });
+
+ it("should call onMarginChange with a percentage value when save is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+
+ const percentInput = screen.getByPlaceholderText("10");
+ await user.clear(percentInput);
+ await user.type(percentInput, "20");
+
+ await user.click(screen.getByRole("button", { name: /CheckIcon/i }));
+
+ expect(onMarginChange).toHaveBeenCalledWith("openai", 0.2);
+ });
+
+ it("should cancel edit mode without calling onMarginChange when X is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+ await user.click(screen.getByRole("button", { name: /XIcon/i }));
+
+ expect(onMarginChange).not.toHaveBeenCalled();
+ expect(screen.queryByPlaceholderText("10")).not.toBeInTheDocument();
+ });
+
+ it("should call onRemoveProvider with provider key and display name when trash is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /TrashIcon/i }));
+
+ expect(onRemoveProvider).toHaveBeenCalledWith("openai", "OpenAI");
+ });
+
+ it("should call onRemoveProvider with 'Global' display name for the global provider", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /TrashIcon/i }));
+
+ expect(onRemoveProvider).toHaveBeenCalledWith("global", "Global");
+ });
+
+ describe("when both percentage and fixed amount are entered", () => {
+ it("should call onMarginChange with an object containing both values", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /PencilAltIcon/i }));
+
+ const percentInput = screen.getByPlaceholderText("10");
+ await user.clear(percentInput);
+ await user.type(percentInput, "5");
+
+ const fixedInput = screen.getByPlaceholderText("0.001");
+ await user.type(fixedInput, "0.002");
+
+ await user.click(screen.getByRole("button", { name: /CheckIcon/i }));
+
+ expect(onMarginChange).toHaveBeenCalledWith("openai", {
+ percentage: 0.05,
+ fixed_amount: 0.002,
+ });
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/use_discount_config.test.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/use_discount_config.test.ts
new file mode 100644
index 00000000000..9161d78e56e
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/use_discount_config.test.ts
@@ -0,0 +1,244 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { renderHook, act } from "@testing-library/react";
+import { useDiscountConfig } from "./use_discount_config";
+import NotificationsManager from "@/components/molecules/notifications_manager";
+
+vi.mock("@/components/networking", () => ({
+ getProxyBaseUrl: vi.fn(() => ""),
+ getGlobalLitellmHeaderName: vi.fn(() => "Authorization"),
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ getProviderBackendValue: vi.fn((enumKey: string) => {
+ const map: Record = {
+ OpenAI: "openai",
+ Anthropic: "anthropic",
+ };
+ return map[enumKey] ?? null;
+ }),
+}));
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: {
+ OpenAI: "OpenAI",
+ Anthropic: "Anthropic",
+ },
+}));
+
+describe("useDiscountConfig", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe("fetchDiscountConfig", () => {
+ it("should populate discountConfig with fetched values on success", async () => {
+ vi.spyOn(global, "fetch").mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05, anthropic: 0.1 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ expect(result.current.discountConfig).toEqual({ openai: 0.05, anthropic: 0.1 });
+ });
+
+ it("should set an empty config when the response has no values", async () => {
+ vi.spyOn(global, "fetch").mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: {} }),
+ } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ expect(result.current.discountConfig).toEqual({});
+ });
+
+ it("should show an error notification when the fetch throws", async () => {
+ vi.spyOn(global, "fetch").mockRejectedValueOnce(new Error("Network error"));
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/failed to fetch/i)
+ );
+ });
+ });
+
+ describe("handleAddProvider", () => {
+ it("should return false and notify when no provider is selected", async () => {
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddProvider(undefined, "5");
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalled();
+ });
+
+ it("should return false and notify when no discount is provided", async () => {
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddProvider("OpenAI", "");
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalled();
+ });
+
+ it("should return false and notify when the discount exceeds 100", async () => {
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddProvider("OpenAI", "150");
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/0%.*100%/i)
+ );
+ });
+
+ it("should return false and notify when the provider already exists in the config", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05 } }),
+ } as Response)
+ .mockResolvedValue({ ok: true, json: async () => ({}) } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddProvider("OpenAI", "10");
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/already exists/i)
+ );
+ });
+
+ it("should save the config and return true on a valid new provider", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: {} }) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: { openai: 0.05 } }) } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddProvider("OpenAI", "5");
+ });
+
+ expect(success!).toBe(true);
+ expect(NotificationsManager.success).toHaveBeenCalled();
+ });
+ });
+
+ describe("handleRemoveProvider", () => {
+ it("should remove the provider from the config and save", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05, anthropic: 0.1 } }),
+ } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { anthropic: 0.1 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ expect(result.current.discountConfig).toHaveProperty("openai");
+
+ await act(async () => {
+ await result.current.handleRemoveProvider("openai");
+ });
+
+ // The optimistic update removes openai immediately
+ expect(result.current.discountConfig).not.toHaveProperty("openai");
+ });
+ });
+
+ describe("handleDiscountChange", () => {
+ it("should update the discount value and save when the value is valid", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05 } }),
+ } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.1 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ await act(async () => {
+ await result.current.handleDiscountChange("openai", "0.1");
+ });
+
+ // Optimistic update applied immediately
+ expect(result.current.discountConfig["openai"]).toBe(0.1);
+ });
+
+ it("should not save when the value is greater than 1 (invalid fraction)", async () => {
+ vi.spyOn(global, "fetch").mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useDiscountConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchDiscountConfig();
+ });
+
+ // Clear mocks after the initial fetch so we can check that no PATCH was made
+ vi.clearAllMocks();
+
+ await act(async () => {
+ await result.current.handleDiscountChange("openai", "1.5");
+ });
+
+ expect(global.fetch).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/use_margin_config.test.ts b/ui/litellm-dashboard/src/components/CostTrackingSettings/use_margin_config.test.ts
new file mode 100644
index 00000000000..3363bc58d93
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/use_margin_config.test.ts
@@ -0,0 +1,316 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { renderHook, act } from "@testing-library/react";
+import { useMarginConfig } from "./use_margin_config";
+import NotificationsManager from "@/components/molecules/notifications_manager";
+
+vi.mock("@/components/networking", () => ({
+ getProxyBaseUrl: vi.fn(() => ""),
+ getGlobalLitellmHeaderName: vi.fn(() => "Authorization"),
+}));
+
+vi.mock("./provider_display_helpers", () => ({
+ getProviderBackendValue: vi.fn((enumKey: string) => {
+ const map: Record = {
+ OpenAI: "openai",
+ Anthropic: "anthropic",
+ };
+ return map[enumKey] ?? null;
+ }),
+}));
+
+vi.mock("../provider_info_helpers", () => ({
+ Providers: {
+ OpenAI: "OpenAI",
+ Anthropic: "Anthropic",
+ },
+}));
+
+describe("useMarginConfig", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe("fetchMarginConfig", () => {
+ it("should populate marginConfig with fetched values on success", async () => {
+ vi.spyOn(global, "fetch").mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.1, global: 0.05 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ expect(result.current.marginConfig).toEqual({ openai: 0.1, global: 0.05 });
+ });
+
+ it("should set an empty config when the response has no values", async () => {
+ vi.spyOn(global, "fetch").mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: {} }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ expect(result.current.marginConfig).toEqual({});
+ });
+
+ it("should show an error notification when fetch throws", async () => {
+ vi.spyOn(global, "fetch").mockRejectedValueOnce(new Error("Network error"));
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/failed to fetch/i)
+ );
+ });
+ });
+
+ describe("handleAddMargin", () => {
+ it("should return false and notify when no provider is selected", async () => {
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: undefined,
+ marginType: "percentage",
+ percentageValue: "10",
+ fixedAmountValue: "",
+ });
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalled();
+ });
+
+ it("should return false and notify when percentage is out of range", async () => {
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: "OpenAI",
+ marginType: "percentage",
+ percentageValue: "2000",
+ fixedAmountValue: "",
+ });
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/0%.*1000%/i)
+ );
+ });
+
+ it("should return false when the provider already has a margin configured", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.05 } }),
+ } as Response)
+ .mockResolvedValue({ ok: true, json: async () => ({}) } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: "OpenAI",
+ marginType: "percentage",
+ percentageValue: "10",
+ fixedAmountValue: "",
+ });
+ });
+
+ expect(success!).toBe(false);
+ expect(NotificationsManager.fromBackend).toHaveBeenCalledWith(
+ expect.stringMatching(/already exists/i)
+ );
+ });
+
+ it("should save a percentage margin and return true for a valid new provider", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: {} }) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: { openai: 0.1 } }) } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: "OpenAI",
+ marginType: "percentage",
+ percentageValue: "10",
+ fixedAmountValue: "",
+ });
+ });
+
+ expect(success!).toBe(true);
+ expect(NotificationsManager.success).toHaveBeenCalled();
+ });
+
+ it("should save a fixed amount margin and return true for a valid new provider", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: {} }) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: { fixed_amount: 0.001 } } }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: "OpenAI",
+ marginType: "fixed",
+ percentageValue: "",
+ fixedAmountValue: "0.001",
+ });
+ });
+
+ expect(success!).toBe(true);
+ expect(NotificationsManager.success).toHaveBeenCalled();
+ });
+
+ it("should accept the global provider without provider_map lookup", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({ ok: true, json: async () => ({ values: {} }) } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { global: 0.05 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ let success: boolean;
+ await act(async () => {
+ success = await result.current.handleAddMargin({
+ selectedProvider: "global",
+ marginType: "percentage",
+ percentageValue: "5",
+ fixedAmountValue: "",
+ });
+ });
+
+ expect(success!).toBe(true);
+ });
+ });
+
+ describe("handleRemoveMargin", () => {
+ it("should remove the provider from the config and save", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.1, anthropic: 0.05 } }),
+ } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { anthropic: 0.05 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ expect(result.current.marginConfig).toHaveProperty("openai");
+
+ await act(async () => {
+ await result.current.handleRemoveMargin("openai");
+ });
+
+ expect(result.current.marginConfig).not.toHaveProperty("openai");
+ });
+ });
+
+ describe("handleMarginChange", () => {
+ it("should update the margin value for a provider and save", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.1 } }),
+ } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.2 } }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ await act(async () => {
+ await result.current.handleMarginChange("openai", 0.2);
+ });
+
+ // Optimistic update applied immediately
+ expect(result.current.marginConfig["openai"]).toBe(0.2);
+ });
+
+ it("should update the margin with a complex value (percentage + fixed)", async () => {
+ vi.spyOn(global, "fetch")
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({ values: { openai: 0.1 } }),
+ } as Response)
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ json: async () => ({
+ values: { openai: { percentage: 0.05, fixed_amount: 0.001 } },
+ }),
+ } as Response);
+
+ const { result } = renderHook(() => useMarginConfig({ accessToken: "test-token" }));
+
+ await act(async () => {
+ await result.current.fetchMarginConfig();
+ });
+
+ await act(async () => {
+ await result.current.handleMarginChange("openai", { percentage: 0.05, fixed_amount: 0.001 });
+ });
+
+ expect(result.current.marginConfig["openai"]).toEqual({
+ percentage: 0.05,
+ fixed_amount: 0.001,
+ });
+ });
+ });
+});