test(e2e): real-browser pass in Playwright Chromium
Three end-to-end scenarios against a static+SSR test server: the zero-build page (import map + native ESM, no bundler), the SSR page (rendered content in the raw response, live after hydration, no mismatch warnings), and adoption (an expando on the server-rendered node survives a real render). Renders are raf-batched so assertions poll. Real Chromium flushed out three fixes happy-dom couldn't see: - nanoraf called an extracted requestAnimationFrame bare — Illegal invocation under strict-mode ESM (sloppy CJS had masked it); wrapped. - the counter example only routed '/', so serving it from any subpath threw; it now has a wildcard fallback. - hydration mismatch detection is now whitespace-insensitive (the parser reparents whitespace, e.g. text after </body>), and page scripts belong in <head> when a view owns <body> — same convention bankai v9 used. CI gets an e2e job with chromium-headless-shell. 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
13155a3469
commit
63b56144a5
@@ -42,7 +42,10 @@ function firstDifference (a, b, path) {
|
||||
}
|
||||
|
||||
if (a.nodeType === 3 || a.nodeType === 8) { // text, comment
|
||||
if (a.nodeValue !== b.nodeValue) {
|
||||
// whitespace-insensitive: the parser shuffles insignificant
|
||||
// whitespace (e.g. text after </body> reparents into body), and
|
||||
// morph reconciles it silently — only report meaningful text
|
||||
if (a.nodeValue.trim() !== b.nodeValue.trim()) {
|
||||
return {
|
||||
path: pathString(path),
|
||||
reason: 'text',
|
||||
@@ -64,8 +67,8 @@ function firstDifference (a, b, path) {
|
||||
}
|
||||
}
|
||||
|
||||
const aKids = a.childNodes
|
||||
const bKids = b.childNodes
|
||||
const aKids = significant(a.childNodes)
|
||||
const bKids = significant(b.childNodes)
|
||||
if (aKids.length !== bKids.length) {
|
||||
return {
|
||||
path: pathString(path.concat(a.nodeName.toLowerCase())),
|
||||
@@ -83,6 +86,18 @@ function firstDifference (a, b, path) {
|
||||
return null
|
||||
}
|
||||
|
||||
// child nodes that matter for comparison: everything except
|
||||
// whitespace-only text nodes
|
||||
function significant (childNodes) {
|
||||
const out = []
|
||||
for (let i = 0; i < childNodes.length; i++) {
|
||||
const node = childNodes[i]
|
||||
if (node.nodeType === 3 && !node.nodeValue.trim()) continue
|
||||
out.push(node)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function attrDifference (a, b) {
|
||||
const aAttrs = a.attributes
|
||||
const bAttrs = b.attributes
|
||||
|
||||
Reference in New Issue
Block a user