import { describe, it, expect, vi } from 'vitest' import { createRoot, on, pressEvents } from '../../index.ts' describe('press mixin', () => { it('dispatches down, up, and press for Enter key', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) button.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', bubbles: true })) root.flush() expect(events).toEqual(['down', 'up', 'press']) }) it('suppresses up and press when long press is prevented', () => { vi.useFakeTimers() try { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement button.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true })) vi.advanceTimersByTime(501) button.dispatchEvent(new KeyboardEvent('keyup', { key: ' ', bubbles: true })) root.flush() expect(events).toEqual(['long']) } finally { vi.useRealTimers() } }) it('dispatches cancel when pointer ends outside target', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown', { isPrimary: true }) dispatchPointer(button.ownerDocument, 'pointerup') root.flush() expect(events).toEqual(['cancel']) }) it('dispatches down, up, and press for primary pointer interactions', () => { let events: string[] = [] let points: Array<{ type: string; x: number; y: number }> = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown', { clientX: 11, clientY: 22, isPrimary: true }) dispatchPointer(button, 'pointerup', { clientX: 33, clientY: 44, isPrimary: true }) root.flush() expect(events).toEqual(['down', 'up', 'press']) expect(points).toEqual([ { type: 'down', x: 11, y: 22 }, { type: 'up', x: 33, y: 44 }, { type: 'press', x: 33, y: 44 }, ]) }) it('ignores non-primary pointerdown events', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown', { isPrimary: false }) dispatchPointer(button, 'pointerup', { isPrimary: false }) root.flush() expect(events).toEqual([]) }) it('clears long-press timer on pointerleave while pressed', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown') dispatchPointer(button, 'pointerleave') dispatchPointer(button, 'pointerup') root.flush() expect(events).toEqual(['up', 'press']) }) it('suppresses pointer up/press after prevented long press', () => { vi.useFakeTimers() try { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown') vi.advanceTimersByTime(501) dispatchPointer(button, 'pointerup') root.flush() expect(events).toEqual(['long']) } finally { vi.useRealTimers() } }) it('dispatches cancel and suppresses up/press when Escape cancels keyboard press', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })) button.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', bubbles: true })) root.flush() expect(events).toEqual(['down', 'cancel']) }) it('ignores keyup when no keyboard press is active', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement button.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', bubbles: true })) root.flush() expect(events).toEqual([]) }) it('ignores duplicate keydown while a key press is already active', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) button.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) button.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter', bubbles: true })) root.flush() expect(events).toEqual(['down', 'up', 'press']) }) it('ignores document pointerup when no pointer press is active', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button.ownerDocument, 'pointerup') root.flush() expect(events).toEqual([]) }) it('cleans up listeners when root is removed', () => { let events: string[] = [] let container = document.createElement('div') let root = createRoot(container) root.render( , ) root.flush() let button = container.querySelector('button') as HTMLButtonElement dispatchPointer(button, 'pointerdown') root.render(null) root.flush() dispatchPointer(button, 'pointerup') dispatchPointer(button.ownerDocument, 'pointerup') expect(events).toEqual([]) }) }) function dispatchPointer( target: EventTarget, type: 'pointerdown' | 'pointerup' | 'pointerleave', init: { clientX?: number; clientY?: number; isPrimary?: boolean } = {}, ) { let event = new Event(type, { bubbles: true, cancelable: true }) as PointerEvent ;(event as { clientX: number }).clientX = init.clientX ?? 0 ;(event as { clientY: number }).clientY = init.clientY ?? 0 ;(event as { isPrimary: boolean }).isPrimary = init.isPrimary ?? true target.dispatchEvent(event) }