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
This commit is contained in:
co-authored by
Claude Fable 5
parent
7e08b585ac
commit
8b684a17d2
@@ -0,0 +1,72 @@
|
||||
// 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()
|
||||
})
|
||||
Reference in New Issue
Block a user