fix(ui): toggle unlimited budget when its text is clicked (#37547)

The checkbox and its visible text both sat inside the max_budget
FormField label, which renders a single <label htmlFor> pointing at the
number input, so clicking the text focused Max Budget instead of ticking
the box. The checkbox only carried an aria-label, so it had no label of
its own to catch the click.

Wrap the checkbox and its text in their own <label>, the association the
antd checkbox wrapper used to provide. The accessible name now comes
from that label, so the aria-label is dropped rather than duplicated,
and the outer field label still points at the number input.
This commit is contained in:
yuneng-jiang 2026-08-19 16:24:12 -07:00 • committed by GitHub
parent 663e647bc8
commit 94374beb6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 15 deletions

View file

@ -231,10 +231,25 @@ describe("UserEditView", () => {
renderWithProviders(<UserEditView {...defaultProps} />);
await waitFor(() => {
expect(screen.getByLabelText("Unlimited Budget")).toBeInTheDocument();
expect(screen.getByRole("checkbox", { name: "Unlimited Budget" })).toBeInTheDocument();
});
});
it("should check unlimited budget when clicking its visible text", async () => {
renderWithProviders(<UserEditView {...defaultProps} />);
await waitFor(() => {
expect(screen.getByRole("spinbutton", { name: /max budget/i })).toBeEnabled();
});
await userEvent.click(screen.getByText("Unlimited Budget"));
await waitFor(() => {
expect(screen.getByRole("checkbox", { name: "Unlimited Budget" })).toBeChecked();
});
expect(screen.getByRole("spinbutton", { name: /max budget/i })).toBeDisabled();
});
it("should set unlimited budget checkbox when max_budget is null", async () => {
const userDataWithNullBudget = {
...MOCK_USER_DATA,
@ -247,7 +262,7 @@ describe("UserEditView", () => {
renderWithProviders(<UserEditView {...defaultProps} userData={userDataWithNullBudget} />);
await waitFor(() => {
const checkbox = screen.getByLabelText("Unlimited Budget");
const checkbox = screen.getByRole("checkbox", { name: "Unlimited Budget" });
expect(checkbox).toBeChecked();
});
});
@ -282,10 +297,10 @@ describe("UserEditView", () => {
renderWithProviders(<UserEditView {...defaultProps} />);
await waitFor(() => {
expect(screen.getByLabelText("Unlimited Budget")).toBeInTheDocument();
expect(screen.getByRole("checkbox", { name: "Unlimited Budget" })).toBeInTheDocument();
});
const checkbox = screen.getByLabelText("Unlimited Budget");
const checkbox = screen.getByRole("checkbox", { name: "Unlimited Budget" });
await userEvent.click(checkbox);
await waitFor(() => {
@ -400,7 +415,7 @@ describe("UserEditView", () => {
const budgetInput = screen.getByRole("spinbutton", { name: /max budget/i });
await userEvent.clear(budgetInput);
const checkbox = screen.getByLabelText("Unlimited Budget");
const checkbox = screen.getByRole("checkbox", { name: "Unlimited Budget" });
expect(checkbox).not.toBeChecked();
const submitButton = screen.getByRole("button", { name: /save changes/i });
@ -416,10 +431,10 @@ describe("UserEditView", () => {
renderWithProviders(<UserEditView {...defaultProps} onSubmit={onSubmitMock} />);
await waitFor(() => {
expect(screen.getByLabelText("Unlimited Budget")).toBeInTheDocument();
expect(screen.getByRole("checkbox", { name: "Unlimited Budget" })).toBeInTheDocument();
});
const checkbox = screen.getByLabelText("Unlimited Budget");
const checkbox = screen.getByRole("checkbox", { name: "Unlimited Budget" });
await userEvent.click(checkbox);
await waitFor(() => {
@ -494,7 +509,7 @@ describe("UserEditView", () => {
renderWithProviders(<UserEditView {...defaultProps} userData={userDataWithUndefinedBudget} />);
await waitFor(() => {
const checkbox = screen.getByLabelText("Unlimited Budget");
const checkbox = screen.getByRole("checkbox", { name: "Unlimited Budget" });
expect(checkbox).toBeChecked();
});
});

View file

@ -256,14 +256,10 @@ export function UserEditView({
label={
<>
Max Budget (USD)
<span className="ml-3 inline-flex items-center gap-2 font-normal">
<Checkbox
aria-label="Unlimited Budget"
checked={unlimitedBudget}
onCheckedChange={handleUnlimitedBudgetChange}
/>
<label className="ml-3 inline-flex items-center gap-2 font-normal">
<Checkbox checked={unlimitedBudget} onCheckedChange={handleUnlimitedBudgetChange} />
Unlimited Budget
</span>
</label>
</>
}
>