diff --git a/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.spec.ts b/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.spec.ts new file mode 100644 index 000000000..b1ebd3471 --- /dev/null +++ b/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.spec.ts @@ -0,0 +1,66 @@ +import { AbstractCombobox } from "./abstract-combobox"; + +// A popup stands in for AbstractPopup: the combobox only needs the three +// members its constructor and event wiring touch. +function popupStub() { + const cell = { + node: { id: "cell-1" }, + addToTabOrder: () => {}, + removeFromTabOrder: () => {}, + }; + return { + node: { id: "popup-1" }, + focused: cell, + getSelected: () => cell, + onClick: (_callback: Function, _context: Object) => {}, + onKeydown: (_callback: Function, _context: Object) => {}, + }; +} + +describe("The AbstractCombobox", () => { + let input: HTMLInputElement; + let combobox: AbstractCombobox; + + beforeEach(() => { + input = document.createElement("input"); + input.id = "combobox-input"; + document.body.appendChild(input); + combobox = new AbstractCombobox(input, popupStub() as any); + }); + + afterEach(() => { + input.remove(); + }); + + it("should call an onInput callback when the input changes", () => { + // onInput() is public and "input" is a registered event, but nothing used + // to dispatch it, so callbacks registered here were never invoked. + let calls = 0; + combobox.onInput(() => calls++, {}); + + input.value = "abc"; + input.dispatchEvent(new Event("input")); + + expect(calls).toBe(1); + }); + + it("should still call an onSearch callback when the input changes", () => { + let calls = 0; + combobox.onSearch(() => calls++, {}); + + input.value = "abc"; + input.dispatchEvent(new Event("input")); + + expect(calls).toBe(1); + }); + + it("should pass the input event through to both callbacks", () => { + const seen: string[] = []; + combobox.onInput((e: Event) => seen.push(`input:${e.type}`), {}); + combobox.onSearch((e: Event) => seen.push(`search:${e.type}`), {}); + + input.dispatchEvent(new Event("input")); + + expect(seen).toEqual(["input:input", "search:input"]); + }); +}); diff --git a/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.ts b/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.ts index a50af1429..d1b77e288 100755 --- a/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.ts +++ b/src/ui-kit/experimental/aria/abstract-combobox/abstract-combobox.ts @@ -65,6 +65,10 @@ export class AbstractCombobox { private _setupInputEvents(): void { this._input.addEventListener("input", (e) => { + // "input" is declared in _initEventDispatcher and exposed by onInput(), + // so it has to be dispatched here as well; only "search" used to be, which + // left onInput() registering callbacks that were never called. + this._dispatcher.dispatch("input", e); this._dispatcher.dispatch("search", e); });