import { describe, it, expect } from 'vitest'
import { createRoot } from '../lib/vdom.ts'
import { invariant } from '../lib/invariant.ts'
import type { Handle } from '../lib/component.ts'
describe('vnode rendering', () => {
describe('signals', () => {
it('provides mounted signal on handle.signal', () => {
let container = document.createElement('div')
let root = createRoot(container)
let capturedSignal: AbortSignal | undefined
function App(handle: Handle) {
capturedSignal = handle.signal
return () => null
}
root.render()
invariant(capturedSignal)
expect(capturedSignal).toBeInstanceOf(AbortSignal)
expect(capturedSignal.aborted).toBe(false)
root.render(null)
root.flush()
expect(capturedSignal.aborted).toBe(true)
})
it('provides render signal to tasks and aborts on re-render', () => {
let container = document.createElement('div')
let root = createRoot(container)
let signals: AbortSignal[] = []
function App(handle: Handle) {
handle.queueTask((signal) => {
signals.push(signal)
})
return () => null
}
root.render()
root.flush()
expect(signals.length).toBe(1)
invariant(signals[0])
expect(signals[0]).toBeInstanceOf(AbortSignal)
expect(signals[0].aborted).toBe(false)
root.render()
root.flush()
expect(signals.length).toBe(1)
invariant(signals[0])
expect(signals[0].aborted).toBe(true)
})
it('aborts handle.update() signal on next update', async () => {
let container = document.createElement('div')
let root = createRoot(container)
let capturedSignal: AbortSignal | undefined
let capturedUpdate = () => {}
function App(handle: Handle) {
capturedUpdate = () => {
handle.update().then((signal) => {
capturedSignal = signal
})
}
return () => null
}
root.render()
root.flush()
capturedUpdate()
root.flush()
await Promise.resolve()
invariant(capturedSignal)
let firstSignal = capturedSignal
expect(firstSignal.aborted).toBe(false)
capturedUpdate()
root.flush()
expect(firstSignal.aborted).toBe(true)
})
it('aborts queueTask signal when component is removed', () => {
let container = document.createElement('div')
let root = createRoot(container)
let capturedSignal: AbortSignal | undefined
function App(handle: Handle) {
handle.queueTask((signal) => {
capturedSignal = signal
})
return () => null
}
root.render()
root.flush()
invariant(capturedSignal)
expect(capturedSignal.aborted).toBe(false)
root.render(null)
root.flush()
expect(capturedSignal.aborted).toBe(true)
})
it('aborts handle.update() signal when component is removed', async () => {
let container = document.createElement('div')
let root = createRoot(container)
let capturedSignal: AbortSignal | undefined
let capturedUpdate = () => {}
function App(handle: Handle) {
capturedUpdate = () => {
handle.update().then((signal) => {
capturedSignal = signal
})
}
return () => null
}
root.render()
root.flush()
capturedUpdate()
root.flush()
await Promise.resolve()
invariant(capturedSignal)
expect(capturedSignal.aborted).toBe(false)
root.render(null)
root.flush()
expect(capturedSignal.aborted).toBe(true)
})
})
})