fix(autocomplete): validate prop not working after hovering (#4452)

* 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
This commit is contained in:
Peterl561 2025-01-03 03:17:42 +08:00 committed by GitHub
parent 7c2bc4a18e
commit 0401f2548f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 67 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
"@nextui-org/autocomplete": patch
---
fixed autocomplete validate prop not working after hovering when validation behavior is native

View File

@ -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", () => {

View File

@ -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"