Skip to content

Commit 0401f25

Browse files
authored
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
1 parent 7c2bc4a commit 0401f25

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

.changeset/ninety-lobsters-deliver.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/autocomplete": patch
3+
---
4+
5+
fixed autocomplete validate prop not working after hovering when validation behavior is native

packages/components/autocomplete/__tests__/autocomplete.test.tsx

+54
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,60 @@ describe("Autocomplete", () => {
782782
expect(input).not.toHaveAttribute("aria-describedby");
783783
expect(input.validity.valid).toBe(true);
784784
});
785+
786+
// 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
787+
// this causes the first form submit after initial render to always succeed even if the validate function returns an error
788+
it("should work with validate after hovering", async () => {
789+
const onSubmit = jest.fn((e) => {
790+
e.preventDefault();
791+
});
792+
793+
const {getByTestId, findByRole} = render(
794+
<Form validationBehavior="native" onSubmit={onSubmit}>
795+
<AutocompleteExample
796+
data-testid="combobox"
797+
name="animal"
798+
validate={(value) => {
799+
if (!value?.selectedKey) {
800+
return "Please select an animal";
801+
}
802+
}}
803+
validationBehavior="native"
804+
/>
805+
<button data-testid="submit" type="submit">
806+
Submit
807+
</button>
808+
</Form>,
809+
);
810+
811+
const combobox = getByTestId("combobox") as HTMLInputElement;
812+
const submit = getByTestId("submit");
813+
814+
expect(combobox).not.toHaveAttribute("aria-describedby");
815+
expect(combobox.validity.valid).toBe(false);
816+
817+
await user.hover(combobox);
818+
await user.click(submit);
819+
820+
expect(onSubmit).toHaveBeenCalledTimes(0);
821+
expect(combobox).toHaveAttribute("aria-describedby");
822+
expect(
823+
document.getElementById(combobox.getAttribute("aria-describedby")!),
824+
).toHaveTextContent("Please select an animal");
825+
826+
await user.click(combobox);
827+
await user.keyboard("pe");
828+
829+
const listbox = await findByRole("listbox");
830+
const items = within(listbox).getAllByRole("option");
831+
832+
await user.click(items[0]);
833+
expect(combobox).toHaveAttribute("aria-describedby");
834+
835+
await user.click(submit);
836+
expect(onSubmit).toHaveBeenCalledTimes(1);
837+
expect(combobox).not.toHaveAttribute("aria-describedby");
838+
});
785839
});
786840

787841
describe("validationBehavior=aria", () => {

packages/components/autocomplete/src/use-autocomplete.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -429,12 +429,19 @@ export function useAutocomplete<T extends object>(originalProps: UseAutocomplete
429429
}),
430430
} as ButtonProps);
431431

432+
// prevent use-input's useFormValidation hook from overwriting use-autocomplete's useFormValidation hook when there are uncommitted validation errors
433+
// see https://github.com/nextui-org/nextui/pull/4452
434+
const hasUncommittedValidation =
435+
validationBehavior === "native" &&
436+
state.displayValidation.isInvalid === false &&
437+
state.realtimeValidation.isInvalid === true;
438+
432439
const getInputProps = () =>
433440
({
434441
...otherProps,
435442
...inputProps,
436443
...slotsProps.inputProps,
437-
isInvalid,
444+
isInvalid: hasUncommittedValidation ? undefined : isInvalid,
438445
validationBehavior,
439446
errorMessage:
440447
typeof errorMessage === "function"

0 commit comments

Comments
 (0)