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
73 lines
2.6 KiB
JavaScript
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()
|
|
})
|