// Async holes and streaming in the server tag. import { test } from 'node:test' import assert from 'node:assert' import html from '@uhhm/buuh-html' import raw from '@uhhm/buuh-html/raw' async function collect (chunks) { const out = [] for await (const chunk of chunks) out.push(chunk) return out } const wait = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms)) test('sync templates stream as a single chunk equal to toString()', async () => { const res = html`

hello ${'world'}

` const chunks = await collect(res) assert.deepStrictEqual(chunks, ['

hello world

']) assert.strictEqual(chunks.join(''), res.toString()) }) test('a promise child splits the stream at the hole', async () => { const res = html`

shell

${wait(10, 'late')}
` const chunks = await collect(res) assert.strictEqual(chunks[0], '

shell

', 'everything before the hole flushes first') assert.strictEqual(chunks.join(''), '

shell

late
end
') }) test('toString() on async content throws with streaming guidance', () => { const res = html`

${Promise.resolve('x')}

` assert.throws(() => res.toString(), /toStream/) }) test('resolved promises can carry templates, arrays, and raw', async () => { const res = html`` const chunks = await collect(res) assert.strictEqual(chunks.join(''), '') }) test('nested templates with async holes stream through their parents', async () => { const inner = html`
${wait(5, 'inner-late')}
` const res = html`

early

${inner}
` const chunks = await collect(res) assert.strictEqual(chunks[0], '

early

', 'parent flushes up to the nested hole') assert.strictEqual(chunks.join(''), '

early

inner-late
') }) test('async iterable children stream chunk by chunk', async () => { async function * rows () { for (let i = 0; i < 3; i++) yield html`
  • ${i}
  • ` } const res = html`
      ${rows()}
    ` const chunks = await collect(res) assert.strictEqual(chunks.join(''), '
    • 0
    • 1
    • 2
    ') assert.ok(chunks.length >= 4, 'each yielded row is its own chunk') }) test('multiple async holes resolve in document order', async () => { // the second promise resolves first; output order must follow the document const res = html`
    ${wait(20, 'A')}|${wait(5, 'B')}
    ` const chunks = await collect(res) assert.strictEqual(chunks.join(''), '
    A|B
    ') }) test('async values in attribute position throw immediately', () => { assert.throws( () => html`
    `, /child position/ ) }) test('resolved async strings are escaped like any child', async () => { const res = html`

    ${wait(5, '