import { fireEvent, waitFor } from "@testing-library/dom"; import { beforeEach, describe, expect, it, vi } from "vitest"; import AutocompleteStatic from "../Autocomplete.static"; const renderAutocomplete = (options: any) => { const wrapper = document.createElement("div"); wrapper.className = ["autocomplete__wrapper", options.wrapperClassName] .filter(Boolean) .join(" "); const input = document.createElement("input"); input.className = ["autocomplete__input", options.customInputClassName] .filter(Boolean) .join(" "); input.value = options.defaultValue ?? ""; wrapper.appendChild(input); options.element.appendChild(wrapper); }; const renderAutocompleteAsync = (options: any) => { window.setTimeout(() => renderAutocomplete(options), 0); }; const accessibleAutocompleteMock: any = vi.fn(renderAutocompleteAsync); accessibleAutocompleteMock.enhanceSelectElement = vi.fn((options: any) => { const element = document.createElement("div"); const selectedOption = options.selectElement.options[options.selectElement.selectedIndex]; options.selectElement.parentNode.insertBefore(element, options.selectElement); renderAutocompleteAsync({ ...options, element, defaultValue: selectedOption?.textContent ?? "", }); }); vi.mock("@orangesk/accessible-autocomplete", () => ({ default: accessibleAutocompleteMock, })); describe("Autocomplete.static", () => { beforeEach(() => { document.body.innerHTML = ""; vi.clearAllMocks(); }); it("moves search icon classes from input config to wrapper config", async () => { const select = document.createElement("select"); document.body.appendChild(select); new AutocompleteStatic(select, { customInputClassName: "input--search-icon-with-placeholder custom-class", }); await waitFor(() => { expect( accessibleAutocompleteMock.enhanceSelectElement, ).toHaveBeenCalled(); }); const config = accessibleAutocompleteMock.enhanceSelectElement.mock.calls[0][0]; expect(config.wrapperClassName).toContain( "autocomplete__wrapper--search-icon-with-placeholder", ); expect(config.customInputClassName).toBe("custom-class"); }); it("passes invalid state to generated input", async () => { const select = document.createElement("select"); select.className = "autocomplete is-invalid"; document.body.appendChild(select); new AutocompleteStatic(select, { customInputClassName: "input--search-icon-with-placeholder", }); await waitFor(() => { expect(document.querySelector(".autocomplete__input")).toHaveClass( "is-invalid", ); expect(document.querySelector(".autocomplete__input")).toHaveAttribute( "aria-invalid", "true", ); }); }); it("passes disabled state to generated input and hides clear button", async () => { const select = document.createElement("select"); const appleOption = new Option("apple", "apple", true, true); select.append(appleOption); select.disabled = true; document.body.appendChild(select); new AutocompleteStatic(select, { customInputClassName: "input--search-icon-with-placeholder", }); await waitFor(() => { expect(document.querySelector(".autocomplete__input")).toBeDisabled(); expect(document.querySelector(".autocomplete__clear")).not.toBeVisible(); }); }); it("clears input and select value from search icon autocomplete", async () => { const select = document.createElement("select"); const emptyOption = new Option("", ""); const appleOption = new Option("apple", "apple", true, true); select.append(emptyOption, appleOption); document.body.appendChild(select); const onConfirm = vi.fn(); new AutocompleteStatic(select, { customInputClassName: "input--search-icon-with-placeholder", onConfirm, }); await waitFor(() => { expect(document.querySelector(".autocomplete__clear")).toBeVisible(); }); expect( document .querySelector(".autocomplete__wrapper") ?.contains(document.querySelector(".autocomplete__clear")), ).toBe(true); const input = document.querySelector( ".autocomplete__input", ); const clearButton = document.querySelector( ".autocomplete__clear", ); expect(input?.value).toBe("apple"); fireEvent.click(clearButton as HTMLButtonElement); expect(input?.value).toBe(""); expect(select.value).toBe(""); expect(clearButton).not.toBeVisible(); expect(onConfirm).toHaveBeenCalledWith(""); }); it("keeps clear button keyboard events from reaching autocomplete wrapper", async () => { const select = document.createElement("select"); const emptyOption = new Option("", ""); const appleOption = new Option("apple", "apple", true, true); select.append(emptyOption, appleOption); document.body.appendChild(select); new AutocompleteStatic(select, { customInputClassName: "input--search-icon-with-placeholder", }); await waitFor(() => { expect(document.querySelector(".autocomplete__clear")).toBeVisible(); }); const wrapper = document.querySelector(".autocomplete__wrapper"); const clearButton = document.querySelector( ".autocomplete__clear", ); const onWrapperKeydown = vi.fn(); wrapper?.addEventListener("keydown", onWrapperKeydown); fireEvent.keyDown(clearButton as HTMLButtonElement, { key: " ", code: "Space", keyCode: 32, }); expect(onWrapperKeydown).not.toHaveBeenCalled(); }); });