fix(ui): reject non-finite soft budget values instead of clearing

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-08-31 20:03:57 +00:00
parent 3bc91b9016
commit 80e8079be5
2 changed files with 25 additions and 0 deletions

View file

@ -1,5 +1,10 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { toast } from "@/lib/toast";
vi.mock("@/lib/toast", () => ({
toast: { error: vi.fn(), success: vi.fn() },
}));
// ---- Hoisted shared mocks (safe to use inside vi.mock factories) ----
const { keyUpdateCallMock, keyDeleteCallMock, mockUseAuthorized } = vi.hoisted(() => {
@ -565,4 +570,20 @@ describe("KeyInfoView handleKeyUpdate soft_budget", () => {
expect(sentPayload.soft_budget).toBeNull();
expect(JSON.stringify({ ...sentPayload })).toContain('"soft_budget":null');
});
it("should reject an overflowing soft_budget instead of silently clearing it", async () => {
renderWithSoftBudget(25);
fireEvent.click(screen.getByText("Settings"));
fireEvent.click(screen.getByText("Edit Settings"));
(globalThis as any).__TEST_FORM_VALUES = {
token: "tok_123",
soft_budget: "1e309",
};
fireEvent.click(screen.getByText("Mock Submit"));
await waitFor(() => expect(toast.error).toHaveBeenCalled());
expect(keyUpdateCallMock).not.toHaveBeenCalled();
});
});

View file

@ -217,6 +217,10 @@ export default function KeyInfoView({
null;
const nextSoftBudget =
formValues.soft_budget === "" || formValues.soft_budget == null ? null : Number(formValues.soft_budget);
if (nextSoftBudget !== null && !Number.isFinite(nextSoftBudget)) {
toast.error("Soft Budget must be a finite number");
return;
}
if (nextSoftBudget === previousSoftBudget) {
delete formValues.soft_budget;
} else {