import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { createRoot } from '../lib/vdom.ts' import { renderToString } from '../lib/stream.ts' import { invariant } from '../lib/invariant.ts' describe('hydration', () => { let container: HTMLDivElement beforeEach(() => { container = document.createElement('div') document.body.appendChild(container) }) afterEach(() => { document.body.innerHTML = '' }) describe('text node handling', () => { it('adopts single server text node when client has multiple text children', async () => { // Server renders "Hello world" as single text node let html = await renderToString(Hello world) container.innerHTML = html let existingSpan = container.querySelector('span') invariant(existingSpan) let originalTextNode = existingSpan.firstChild invariant(originalTextNode instanceof Text) // Client has two text children: ["Hello ", "world"] let root = createRoot(container) root.render( {'Hello '} {'world'} , ) root.flush() // Span should be adopted expect(container.querySelector('span')).toBe(existingSpan) // Text content should match (even if internal structure differs) expect(existingSpan.textContent).toBe('Hello world') }) it('subsequent update patches consolidated text content', async () => { let html = await renderToString(Hello world) container.innerHTML = html let existingSpan = container.querySelector('span') invariant(existingSpan) let name = 'world' function render() { root.render( {'Hello '} {name} , ) root.flush() } let root = createRoot(container) render() expect(existingSpan.textContent).toBe('Hello world') // Update the dynamic part name = 'Ryan' render() expect(existingSpan.textContent).toBe('Hello Ryan') }) it('handles null children as empty text', async () => { let html = await renderToString(