fix(canvas): use explicit empty-string check in BudgetSection to preserve zero-credit budget

parseInt("0", 10) || null evaluates to null, silently converting a
zero-credit budget to unlimited. Switch to raw !== "" ? parseInt() : null
so budget_limit: 0 is sent correctly. Adds regression test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Molecule AI Frontend Engineer 2026-04-17 02:02:12 +00:00
parent e22d2d2257
commit 6668a95d6f
2 changed files with 21 additions and 1 deletions

View File

@ -229,6 +229,24 @@ describe("BudgetSection — save", () => {
expect(body.budget_limit).toBe(800);
});
it("sends budget_limit: 0 (not null) when input is '0' — zero-credit budget", async () => {
// Regression for QA bug report: `parseInt("0") || null` would yield null.
// The correct form `raw !== "" ? parseInt(raw, 10) : null` must return 0.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mockPatch.mockResolvedValueOnce(budgetResponse({ budget_limit: 0, budget_used: 0, budget_remaining: 0 }) as any);
await renderLoaded(budgetResponse({ budget_limit: 1000 }));
fireEvent.change(screen.getByTestId("budget-limit-input"), {
target: { value: "0" },
});
fireEvent.click(screen.getByTestId("budget-save-btn"));
await waitFor(() => expect(mockPatch).toHaveBeenCalled());
const body = mockPatch.mock.calls[0][1] as Record<string, unknown>;
expect(body.budget_limit).toBe(0);
expect(body.budget_limit).not.toBeNull();
});
it("sends budget_limit: null when input is blank", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mockPatch.mockResolvedValueOnce(budgetResponse({ budget_limit: null, budget_remaining: null }) as any);

View File

@ -80,7 +80,9 @@ export function BudgetSection({ workspaceId }: Props) {
setSaving(true);
setSaveError(null);
const raw = limitInput.trim();
const parsedLimit = raw ? parseInt(raw, 10) : null;
// Use explicit empty-string check (not falsy check) so that a
// user-entered "0" is sent as budget_limit: 0, not null (unlimited).
const parsedLimit = raw !== "" ? parseInt(raw, 10) : null;
try {
const updated = await api.patch<BudgetData>(`/workspaces/${workspaceId}/budget`, {