Files
Bendik Aagaard LynghaugandClaude Fable 5 8b684a17d2 feat(examples)+test(e2e): counter service worker; bankai dev+prod in Chromium
The counter example gains a sw.js exercising bankai's injected-precache
build. e2e proves both bankai paths in real Chromium: the built app
serves, hydrates and runs with zero console errors and zero mismatch
warnings (and choo consumed window.initialState), and the dev server's
Vite-transformed virtual entry hydrates the same way.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
2026-09-08 19:32:37 +02:00

73 lines
2.6 KiB
JavaScript

// bankai v10 end-to-end in real Chromium: the production pipeline
// (build → serve → SSR page hydrates and runs) and the dev server
// (Vite middleware + virtual entry + streaming SSR).
import { test, before, after } from 'node:test'
import assert from 'node:assert'
import { mkdtemp, rm } from 'node:fs/promises'
import { join, dirname } from 'node:path'
import { tmpdir } from 'node:os'
import { fileURLToPath } from 'node:url'
import { chromium } from 'playwright'
import build from '../../packages/bankai/lib/build.js'
import serve from '../../packages/bankai/lib/serve.js'
import dev from '../../packages/bankai/lib/dev.js'
const repo = join(dirname(fileURLToPath(import.meta.url)), '..', '..')
const entry = join(repo, 'examples', 'counter', 'app.js')
let browser, outDir, prod, devSrv
before(async () => {
browser = await chromium.launch()
outDir = await mkdtemp(join(tmpdir(), 'bankai-e2e-'))
await build({ entry, outDir, title: 'counter' })
prod = await serve({ outDir, port: 0 })
devSrv = await dev({ entry, port: 0, title: 'counter dev' })
})
after(async () => {
await browser?.close()
await prod?.close()
await devSrv?.close()
if (outDir) await rm(outDir, { recursive: true, force: true })
})
async function openAndCount (origin) {
const page = await browser.newPage()
const errors = []
const warnings = []
page.on('console', (msg) => {
if (msg.type() === 'error') errors.push(msg.text())
if (msg.type() === 'warning') warnings.push(msg.text())
})
page.on('pageerror', (err) => errors.push(String(err)))
await page.goto(origin + '/')
await page.waitForFunction(() => document.querySelector('h1')?.textContent === 'count is 0')
await page.click('button')
await page.waitForFunction(() => document.querySelector('h1')?.textContent === 'count is 1')
return { page, errors, warnings }
}
test('production: built app serves, hydrates and runs with no errors', async () => {
const { page, errors, warnings } = await openAndCount(prod.origin)
assert.deepStrictEqual(errors, [], 'no console errors')
const mismatches = warnings.filter((w) => w.includes('markup differ'))
assert.deepStrictEqual(mismatches, [], 'no hydration mismatch warnings')
const state = await page.evaluate(() => window.choo ? 'devtools' : typeof window.initialState)
assert.strictEqual(state, 'undefined', 'choo consumed initialState (deleted after merge)')
await page.close()
})
test('dev server: Vite-transformed entry hydrates and runs', async () => {
const { page, errors } = await openAndCount(devSrv.origin)
assert.deepStrictEqual(errors, [], 'no console errors')
await page.close()
})