UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

644 lines 35.8 kB
import { createInjector } from '@furystack/inject'; import { createComponent, initializeShadeRoot } from '@furystack/shades'; import { usingAsync } from '@furystack/utils'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { Suggest } from './index.js'; describe('Suggest', () => { let originalAnimate; let animateCalls; beforeEach(() => { vi.useFakeTimers(); document.body.innerHTML = '<div id="root"></div>'; animateCalls = []; originalAnimate = Element.prototype.animate; Element.prototype.animate = vi.fn((keyframes, options) => { animateCalls.push({ keyframes, options }); const mockAnimation = { onfinish: null, oncancel: null, cancel: vi.fn(), play: vi.fn(), pause: vi.fn(), finish: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), }; return mockAnimation; }); }); afterEach(async () => { await vi.runAllTimersAsync(); const suggest = document.querySelector('shade-suggest'); suggest?.remove(); document.body.innerHTML = ''; Element.prototype.animate = originalAnimate; vi.useRealTimers(); vi.restoreAllMocks(); }); const advanceTimers = async (ms) => { await vi.advanceTimersByTimeAsync(ms); }; const createTestEntries = () => [ { id: 1, name: 'First' }, { id: 2, name: 'Second' }, { id: 3, name: 'Third' }, ]; const getTestEntries = async (term) => { const entries = createTestEntries(); if (!term) return entries; return entries.filter((e) => e.name.toLowerCase().includes(term.toLowerCase())); }; const getSuggestionEntry = (entry) => ({ element: createComponent("span", { "data-testid": `suggestion-${entry.id}` }, entry.name), score: entry.id, }); describe('rendering', () => { it('should render as custom element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); expect(suggest).not.toBeNull(); }); }); it('should render the default prefix', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "Search:", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const termIcon = suggest?.querySelector('.term-icon'); expect(termIcon?.textContent).toBe('Search:'); }); }); it('should render the input container', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const inputContainer = suggest?.querySelector('.input-container'); expect(inputContainer).not.toBeNull(); }); }); it('should apply custom styles', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion, style: { backgroundColor: 'red' } })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const inputContainer = suggest?.querySelector('.input-container'); expect(inputContainer?.style.backgroundColor).toBe('red'); }); }); }); describe('keyboard navigation', () => { it('should handle ArrowDown to move selection down', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'test'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }); Object.defineProperty(arrowDownEvent, 'target', { value: input }); wrapper?.dispatchEvent(arrowDownEvent); await advanceTimers(50); const selectedItems = suggest?.querySelectorAll('.suggestion-item.selected'); expect(selectedItems?.length).toBeGreaterThanOrEqual(0); }); }); it('should handle ArrowUp to move selection up', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'test'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }); Object.defineProperty(arrowDownEvent, 'target', { value: input }); wrapper?.dispatchEvent(arrowDownEvent); wrapper?.dispatchEvent(arrowDownEvent); const arrowUpEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }); Object.defineProperty(arrowUpEvent, 'target', { value: input }); wrapper?.dispatchEvent(arrowUpEvent); await advanceTimers(50); expect(suggest).not.toBeNull(); }); }); it('should handle Enter to select current suggestion', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }); Object.defineProperty(enterEvent, 'target', { value: input }); wrapper?.dispatchEvent(enterEvent); await advanceTimers(50); expect(onSelectSuggestion).toHaveBeenCalled(); }); }); it('should prevent default on Enter key', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }); Object.defineProperty(enterEvent, 'target', { value: input }); const preventDefaultSpy = vi.spyOn(enterEvent, 'preventDefault'); wrapper?.dispatchEvent(enterEvent); expect(preventDefaultSpy).toHaveBeenCalled(); }); }); it('should prevent default on ArrowUp key when suggestions are open', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const arrowUpEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true, cancelable: true }); Object.defineProperty(arrowUpEvent, 'target', { value: input }); const preventDefaultSpy = vi.spyOn(arrowUpEvent, 'preventDefault'); wrapper?.dispatchEvent(arrowUpEvent); expect(preventDefaultSpy).toHaveBeenCalled(); }); }); it('should prevent default on ArrowDown key when suggestions are open', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true, cancelable: true }); Object.defineProperty(arrowDownEvent, 'target', { value: input }); const preventDefaultSpy = vi.spyOn(arrowDownEvent, 'preventDefault'); wrapper?.dispatchEvent(arrowDownEvent); expect(preventDefaultSpy).toHaveBeenCalled(); }); }); it('should not prevent default on arrow keys when dropdown is closed', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); const arrowDownEvent = new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true, cancelable: true }); Object.defineProperty(arrowDownEvent, 'target', { value: input }); const preventDefaultSpy = vi.spyOn(arrowDownEvent, 'preventDefault'); wrapper?.dispatchEvent(arrowDownEvent); expect(preventDefaultSpy).not.toHaveBeenCalled(); }); }); it('should not move selection below 0', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'test'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); for (let i = 0; i < 5; i++) { const arrowUpEvent = new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }); Object.defineProperty(arrowUpEvent, 'target', { value: input }); wrapper?.dispatchEvent(arrowUpEvent); } await advanceTimers(50); expect(suggest).not.toBeNull(); }); }); }); describe('open/close behavior', () => { it('should open when clicking term icon', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const termIcon = suggest?.querySelector('.term-icon'); termIcon?.click(); await advanceTimers(50); expect(suggest?.hasAttribute('data-opened')).toBe(true); }); }); it('should close when clicking close button', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const termIcon = suggest?.querySelector('.term-icon'); termIcon?.click(); await advanceTimers(50); const closeButton = suggest?.querySelector('.close-suggestions'); closeButton?.click(); await advanceTimers(50); expect(suggest?.hasAttribute('data-opened')).toBe(false); }); }); it('should trigger animation when opening', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const initialAnimationCount = animateCalls.length; const suggest = document.querySelector('shade-suggest'); const termIcon = suggest?.querySelector('.term-icon'); termIcon?.click(); await advanceTimers(50); expect(animateCalls.length).toBeGreaterThan(initialAnimationCount); }); }); it('should trigger animation when closing', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const termIcon = suggest?.querySelector('.term-icon'); termIcon?.click(); await advanceTimers(50); const animationCountAfterOpen = animateCalls.length; const closeButton = suggest?.querySelector('.close-suggestions'); closeButton?.click(); await advanceTimers(50); expect(animateCalls.length).toBeGreaterThan(animationCountAfterOpen); }); }); }); describe('suggestions loading', () => { it('should fetch suggestions when typing', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); const getEntriesSpy = vi.fn(getTestEntries); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getEntriesSpy, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); expect(getEntriesSpy).toHaveBeenCalledWith('First'); }); }); it('should show loader animation while loading', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); const resolveHolder = { resolve: null }; const slowGetEntries = () => new Promise((resolve) => { resolveHolder.resolve = resolve; }); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: slowGetEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest?.querySelector('input'); input.value = 'test'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const loader = suggest?.querySelector('shade-loader'); expect(loader).not.toBeNull(); resolveHolder.resolve?.(createTestEntries()); await advanceTimers(50); }); }); it('should render suggestions after loading', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest?.querySelector('input'); input.value = 'test'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const suggestionList = suggest?.querySelector('shade-suggest-suggestion-list'); expect(suggestionList).not.toBeNull(); }); }); }); describe('suggestion selection', () => { it('should call onSelectSuggestion when selecting via Enter', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }); Object.defineProperty(enterEvent, 'target', { value: input }); wrapper?.dispatchEvent(enterEvent); await advanceTimers(50); expect(onSelectSuggestion).toHaveBeenCalledWith(expect.objectContaining({ name: 'First' })); }); }); it('should close after selecting a suggestion', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const wrapper = suggest?.querySelector('.suggest-wrapper'); const input = suggest?.querySelector('input'); input.value = 'First'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); expect(suggest?.hasAttribute('data-opened')).toBe(true); const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }); Object.defineProperty(enterEvent, 'target', { value: input }); wrapper?.dispatchEvent(enterEvent); await advanceTimers(50); expect(suggest?.hasAttribute('data-opened')).toBe(false); }); }); }); describe('sub-components', () => { it('should render SuggestInput component', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const suggestInput = suggest?.querySelector('shades-suggest-input'); expect(suggestInput).not.toBeNull(); }); }); it('should render SuggestionList component', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const suggestionList = suggest?.querySelector('shade-suggest-suggestion-list'); expect(suggestionList).not.toBeNull(); }); }); it('should render Loader component', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const loader = suggest?.querySelector('shade-loader'); expect(loader).not.toBeNull(); }); }); }); describe('spatial navigation attributes', () => { it('should have data-spatial-nav-target on the host element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); expect(suggest.hasAttribute('data-spatial-nav-target')).toBe(true); }); }); it('should have tabIndex of -1 on the host element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); expect(suggest.tabIndex).toBe(-1); }); }); it('should delegate focus to the inner input when the host is focused', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", getEntries: getTestEntries, getSuggestionEntry: getSuggestionEntry, onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest.querySelector('input'); suggest.dispatchEvent(new FocusEvent('focus', { bubbles: false })); await advanceTimers(10); expect(document.activeElement).toBe(input); }); }); }); describe('synchronous suggestions mode', () => { it('should render with string[] suggestions', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", suggestions: ['Apple', 'Banana', 'Cherry'], onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); expect(suggest).not.toBeNull(); }); }); it('should render input in sync mode', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", suggestions: ['Apple', 'Banana', 'Cherry'], onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest?.querySelector('input'); expect(input).not.toBeNull(); }); }); it('should show filtered suggestions in sync mode', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onSelectSuggestion = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(Suggest, { defaultPrefix: "\uD83D\uDD0D", suggestions: ['Apple', 'Apricot', 'Banana'], onSelectSuggestion: onSelectSuggestion })), }); await advanceTimers(50); const suggest = document.querySelector('shade-suggest'); const input = suggest?.querySelector('input'); input.value = 'ap'; input.dispatchEvent(new Event('input', { bubbles: true })); await advanceTimers(300); const suggestionItems = suggest?.querySelectorAll('.suggestion-item'); expect(suggestionItems?.length).toBe(2); }); }); }); }); //# sourceMappingURL=index.spec.js.map