Skip to content

Commit

Permalink
fix(autocomplete): validate prop not working after hovering (#4452)
Browse files Browse the repository at this point in the history
* fix(autocomplete): validate prop not working after hovering

* test(autocomplete): validate prop function should work after hover

* chore(changeset): fixed autocomplete validate not working after hover

* chore(autocomplete): minor comment change
  • Loading branch information
Peterl561 authored Jan 2, 2025
1 parent 7c2bc4a commit 0401f25
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/ninety-lobsters-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nextui-org/autocomplete": patch
---

fixed autocomplete validate prop not working after hovering when validation behavior is native
54 changes: 54 additions & 0 deletions packages/components/autocomplete/__tests__/autocomplete.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,60 @@ describe("Autocomplete", () => {
expect(input).not.toHaveAttribute("aria-describedby");
expect(input.validity.valid).toBe(true);
});

// this test is to cover a case where hovering over the combobox causes the validation from use-input to overwrite the validation from use-autocomplete if not handled properly
// this causes the first form submit after initial render to always succeed even if the validate function returns an error
it("should work with validate after hovering", async () => {
const onSubmit = jest.fn((e) => {
e.preventDefault();
});

const {getByTestId, findByRole} = render(
<Form validationBehavior="native" onSubmit={onSubmit}>
<AutocompleteExample
data-testid="combobox"
name="animal"
validate={(value) => {
if (!value?.selectedKey) {
return "Please select an animal";
}
}}
validationBehavior="native"
/>
<button data-testid="submit" type="submit">
Submit
</button>
</Form>,
);

const combobox = getByTestId("combobox") as HTMLInputElement;
const submit = getByTestId("submit");

expect(combobox).not.toHaveAttribute("aria-describedby");
expect(combobox.validity.valid).toBe(false);

await user.hover(combobox);
await user.click(submit);

expect(onSubmit).toHaveBeenCalledTimes(0);
expect(combobox).toHaveAttribute("aria-describedby");
expect(
document.getElementById(combobox.getAttribute("aria-describedby")!),
).toHaveTextContent("Please select an animal");

await user.click(combobox);
await user.keyboard("pe");

const listbox = await findByRole("listbox");
const items = within(listbox).getAllByRole("option");

await user.click(items[0]);
expect(combobox).toHaveAttribute("aria-describedby");

await user.click(submit);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(combobox).not.toHaveAttribute("aria-describedby");
});
});

describe("validationBehavior=aria", () => {
Expand Down
9 changes: 8 additions & 1 deletion packages/components/autocomplete/src/use-autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,12 +429,19 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
}),
} as ButtonProps);

// prevent use-input's useFormValidation hook from overwriting use-autocomplete's useFormValidation hook when there are uncommitted validation errors
// see https://github.com/nextui-org/nextui/pull/4452
const hasUncommittedValidation =
validationBehavior === "native" &&
state.displayValidation.isInvalid === false &&
state.realtimeValidation.isInvalid === true;

const getInputProps = () =>
({
...otherProps,
...inputProps,
...slotsProps.inputProps,
isInvalid,
isInvalid: hasUncommittedValidation ? undefined : isInvalid,
validationBehavior,
errorMessage:
typeof errorMessage === "function"
Expand Down

0 comments on commit 0401f25

Please sign in to comment.