import { describe, it, expect } from 'vitest'
import { createRoot } from './vdom.ts'
import { invariant } from './invariant.ts'
import { renderToString } from './stream.ts'
import { dom } from '@remix-run/events'
describe('hydration', () => {
it('adopts text nodes', async () => {
let container = document.createElement('div')
container.innerHTML = 'Hello, world!'
let node = container.firstChild
let root = createRoot(container)
root.render('Hello, world!')
expect(container.innerHTML).toBe('Hello, world!')
expect(container.firstChild).toBe(node)
})
it('adopts host nodes', async () => {
let container = document.createElement('div')
container.innerHTML = '
'
let node = container.firstChild
let root = createRoot(container)
root.render()
expect(container.innerHTML).toBe('')
expect(container.firstChild).toBe(node)
})
it('adopts dom nodes with children', async () => {
let container = document.createElement('div')
container.innerHTML = '
Hello, world!
'
let node = container.firstChild
let span = container.querySelector('span')
invariant(span)
let root = createRoot(container)
root.render(
Hello, world!
,
)
expect(container.innerHTML).toBe('
Hello, world!
')
expect(container.firstChild).toBe(node)
expect(container.querySelector('span')).toBe(span)
})
it('adopts dom nodes with children text', async () => {
let container = document.createElement('div')
container.innerHTML = '
Hello, world!
'
let node = container.firstChild
invariant(node)
let text = node.firstChild
let root = createRoot(container)
root.render(
Hello, world!
)
expect(container.innerHTML).toBe('
Hello, world!
')
expect(container.firstChild).toBe(node)
let newText = container.firstChild?.firstChild
invariant(newText)
expect(newText).toBe(text)
})
it('adopts dom nodes with children text and elements', async () => {
let container = document.createElement('div')
container.innerHTML = '
Hello, world!
'
let div = container.firstChild
invariant(div)
let text = div.firstChild
invariant(text instanceof Text)
let span = container.querySelector('span')
invariant(span)
let root = createRoot(container)
root.render(
'
let ps = container.querySelectorAll('p')
expect(ps).toHaveLength(2)
let root = createRoot(container)
root.render(
<>
Hello
world!
>,
)
expect(container.innerHTML).toBe('
Hello
world!
')
let newPs = container.querySelectorAll('p')
invariant(newPs.length === 2)
expect(newPs[0]).toEqual(ps[0])
expect(newPs[1]).toEqual(ps[1])
})
it('adopts nodes within components', () => {
let container = document.createElement('div')
container.innerHTML = '
Hello, world!
'
let div = container.firstChild
invariant(div)
let text = div.firstChild
invariant(text instanceof Text)
function App() {
return
Hello, world!
}
let root = createRoot(container)
root.render()
expect(container.innerHTML).toBe('
Hello, world!
')
expect(container.firstChild).toBe(div)
expect(container.firstChild?.firstChild).toBe(text)
})
it('adopts mixed nodes within components', () => {
let container = document.createElement('div')
container.innerHTML = '
Hello, world!
'
let div = container.firstChild
invariant(div)
let text = div.firstChild
invariant(text instanceof Text)
let span = container.querySelector('span')
invariant(span)
function App() {
return (
Hello, world!
)
}
let root = createRoot(container)
root.render()
expect(container.innerHTML).toBe('
'
let div = container.firstChild
invariant(div)
let span = container.querySelector('span')
invariant(span)
let text = span.firstChild
invariant(text)
let root = createRoot(container)
root.render(
Hello
,
)
expect(container.innerHTML).toBe('
Hello
')
expect(container.querySelector('div')).toBe(div)
expect(container.querySelector('span')).toBe(span)
expect(span.firstChild).toBe(text)
})
it('corrects text mismatches', () => {
let container = document.createElement('div')
container.innerHTML = 'Hello'
let text = container.firstChild
let root = createRoot(container)
root.render('Hello, world!')
expect(container.innerHTML).toBe('Hello, world!')
expect(container.firstChild).toBe(text)
})
it.todo('corrects sequential text node mismatches')
it('corrects attribute mismatches', () => {
let container = document.createElement('div')
container.innerHTML = ''
let div = container.firstChild
invariant(div)
let root = createRoot(container)
root.render()
expect(container.innerHTML).toBe('')
expect(container.firstChild).toBe(div)
})
it('attaches events', () => {
let container = document.createElement('div')
container.innerHTML = ''
let button = container.firstChild
invariant(button instanceof HTMLButtonElement)
let root = createRoot(container)
let clicked = false
root.render(
,
)
root.flush()
expect(container.querySelector('button')).toBe(button)
button.click()
expect(clicked).toBe(true)
})
it('ignores excess nodes', () => {
let container = document.createElement('div')
container.innerHTML = '
Who do you think you are?
'
let root = createRoot(container)
root.render(
Who do you think you are?
,
)
expect(container.innerHTML).toBe(
'
Who do you think you are?
',
)
root.render(
Leave it be
,
)
expect(container.innerHTML).toBe('
Leave it be
')
})
it('patches up mismatched elements', () => {
let container = document.createElement('div')
container.innerHTML = '
Who do you think you are?
'
let root = createRoot(container)
root.render(I am!)
expect(container.innerHTML).toBe('I am!')
})
it('works with renderToString', async () => {
function App() {
return (
Content
)
}
let html = await renderToString()
let container = document.createElement('div')
container.innerHTML = html
let main = container.querySelector('main')
invariant(main)
let root = createRoot(container)
root.render()
expect(container.innerHTML).toBe(html)
expect(container.querySelector('main')).toBe(main)
})
it.skip('collapses text nodes', () => {
let container = document.createElement('div')
container.innerHTML = 'All Text'
let root = createRoot(container)
let value = 'Text'
root.render(Some {value})
expect(container.innerHTML).toBe('All Text')
})
})