import { describe, it, expect, vi } from 'vitest'
import { createRoot } from '../vdom.ts'
import { on } from './on-mixin.ts'
import { invariant } from '../invariant.ts'
import type { Assert, Equal } from '../../test/utils.ts'
import type { Dispatched } from './on-mixin.ts'
describe('on mixin', () => {
it('updates listeners in place without rebinding when capture is unchanged', () => {
let calls: string[] = []
let container = document.createElement('div')
let root = createRoot(container)
root.render(
,
)
root.flush()
let button = container.querySelector('button')
invariant(button)
let addSpy = vi.spyOn(button, 'addEventListener')
let removeSpy = vi.spyOn(button, 'removeEventListener')
root.render(
,
)
root.flush()
button.click()
root.flush()
expect(calls).toEqual(['second'])
expect(addSpy).toHaveBeenCalledTimes(0)
expect(removeSpy).toHaveBeenCalledTimes(0)
})
it('rebinds when capture option changes', () => {
let container = document.createElement('div')
let root = createRoot(container)
root.render()
root.flush()
let button = container.querySelector('button')
invariant(button)
let addSpy = vi.spyOn(button, 'addEventListener')
let removeSpy = vi.spyOn(button, 'removeEventListener')
root.render()
root.flush()
expect(addSpy).toHaveBeenCalledTimes(1)
expect(removeSpy).toHaveBeenCalledTimes(1)
})
it('passes abort signal as the second handler argument', () => {
let receivedSignal = AbortSignal.abort()
let container = document.createElement('div')
let root = createRoot(container)
root.render(
,
)
root.flush()
let button = container.querySelector('button')
invariant(button)
button.click()
root.flush()
expect(receivedSignal).toBeInstanceOf(AbortSignal)
expect(receivedSignal.aborted).toBe(false)
})
it('supports multiple event types on the same element', () => {
let calls: string[] = []
let container = document.createElement('div')
let root = createRoot(container)
root.render(
,
)
root.flush()
let button = container.querySelector('button')
invariant(button)
button.dispatchEvent(new FocusEvent('focus', { bubbles: true }))
button.click()
root.flush()
expect(calls).toEqual(['focus', 'click'])
})
it('removes listeners when on() mixin is removed', () => {
let calls = 0
let container = document.createElement('div')
let root = createRoot(container)
root.render(
,
)
root.flush()
let button = container.querySelector('button')
invariant(button)
button.click()
root.flush()
expect(calls).toBe(1)
root.render()
root.flush()
button.click()
root.flush()
expect(calls).toBe(1)
})
it('aborts previous handler signal on reentry', async () => {
let signals: AbortSignal[] = []
let pendingResolvers: Array<() => void> = []
let container = document.createElement('div')
let root = createRoot(container)
root.render(
,
)
root.flush()
let button = container.querySelector('button')
invariant(button)
button.click()
button.click()
root.flush()
expect(signals).toHaveLength(2)
expect(signals[0]!.aborted).toBe(true)
expect(signals[1]!.aborted).toBe(false)
for (let resolve of pendingResolvers) resolve()
await Promise.resolve()
})
})
const _infersNodeType = (