// End-to-end in happy-dom: the counter app running the real browser path — // start(), store, emit, nanoraf-batched re-render, nanomorph in place. import { test, before } from 'node:test' import assert from 'node:assert' import { Window } from 'happy-dom' let choo, html before(async () => { const win = new Window({ url: 'http://localhost/' }) globalThis.window = win globalThis.document = win.document globalThis.requestAnimationFrame = win.requestAnimationFrame.bind(win) ;({ default: choo } = await import('@choojs/core')) ;({ default: html } = await import('@choojs/html/browser')) }) const tick = (ms = 30) => new Promise((resolve) => setTimeout(resolve, ms)) test('a full app renders, emits, and morphs in the browser', async () => { const app = choo() app.use((state, emitter) => { state.count = 0 emitter.on('increment', (n) => { state.count += n emitter.emit('render') }) }) app.route('/', (state, emit) => { return html`

count is ${state.count}

` }) const tree = app.start() assert.strictEqual(tree.querySelector('h1').textContent, 'count is 0') // state event → render event → raf-batched morph of the same tree app.emit('increment', 1) await tick() assert.strictEqual(tree.querySelector('h1').textContent, 'count is 1', 'emit re-rendered in place') // and through an actual DOM click on the interpolated handler tree.querySelector('button').click() await tick() assert.strictEqual(tree.querySelector('h1').textContent, 'count is 2', 'click handler emitted') // raf batching: two synchronous emits, one render app.emit('increment', 1) app.emit('increment', 1) await tick() assert.strictEqual(tree.querySelector('h1').textContent, 'count is 4', 'batched emits coalesced') })