import { test, before } from 'node:test' import assert from 'node:assert' import { Window } from 'happy-dom' let choo, html, devtools 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('@uhhm/buuh')) ;({ default: html } = await import('@uhhm/buuh-html/browser')) ;({ default: devtools } = await import('../index.js')) }) test('devtools exposes window.choo with live state, log and emit', async () => { const app = choo() app.use(devtools()) app.use((state, emitter) => { state.count = 0 emitter.on('bump', (n) => { state.count += n }) }) app.route('/', (state) => html`
${state.count}
`) app.start() assert.ok(window.choo, 'window.choo exists') assert.strictEqual(window.choo.state.count, 0, 'live state exposed') window.choo.emit('bump', 2) assert.strictEqual(window.choo.state.count, 2, 'emit from the console handle works') assert.ok(window.choo.log.some((e) => e.name === 'bump'), 'events land in the log') assert.strictEqual(typeof window.choo.help, 'function') const json = JSON.parse(window.choo.copy()) assert.strictEqual(json.count, 2, 'copy() serializes state') assert.strictEqual(json.cache, null, 'state.cache not serialized') }) test('devtools is a no-op on the server', async () => { // fresh import in a windowless world is covered by the guard: calling // the store with no window must not throw or touch globals const store = devtools() const hadWindow = globalThis.window delete globalThis.window try { assert.doesNotThrow(() => store({}, { on () {} }, {})) } finally { globalThis.window = hadWindow } })