test+docs: full-app browser integration test and the isomorphic counter example

The integration test runs the counter through the real browser path in
happy-dom: start(), store events, raf-batched morph, DOM click handlers,
emit coalescing. examples/counter is the Phase 2 exit criterion: one app
module mounted zero-build in a browser via import map and string-rendered
by node examples/counter/render.js.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-08 16:56:54 +02:00
co-authored by Claude Fable 5
parent c696e00d4f
commit 870aa79668
5 changed files with 152 additions and 5 deletions
+35
View File
@@ -0,0 +1,35 @@
// The classic choo counter. This one module is the whole app, and both
// sides consume it: the browser mounts it (import map resolves
// @choojs/html to the DOM renderer), Node stringifies it (same specifier
// resolves to the string renderer). That's the isomorphic contract.
import choo from '@choojs/core'
import html from '@choojs/html'
export default function createApp () {
const app = choo()
app.use(countStore)
app.route('/', mainView)
return app
}
function mainView (state, emit) {
return html`
<body>
<h1>count is ${state.count}</h1>
<button onclick=${onclick}>Increment</button>
</body>
`
function onclick () {
emit('increment', 1)
}
}
function countStore (state, emitter) {
state.count = state.count || 0
emitter.on('increment', function (count) {
state.count += count
emitter.emit('render')
})
}