diff --git a/tests/playwright/site-full.spec.js b/tests/playwright/site-full.spec.js index 8eb5ebf6..fa642caa 100644 --- a/tests/playwright/site-full.spec.js +++ b/tests/playwright/site-full.spec.js @@ -166,19 +166,22 @@ test('home', async ({ page }) => { }]); // Inject observer before page JS boots to detect hydration flash. - // A flash = the island content goes empty (0 children) between SSR and hydration. - // An atomic replaceChildren swap is fine — content is never visibly empty. + // A flash = the island's visible text content changes during hydration. + // True hydration should preserve SSR DOM — no visible change at all. await page.addInitScript(() => { window.__flashDetected = false; + window.__flashDetail = null; const check = () => { const stepper = document.querySelector('[data-sx-island="home/stepper"]'); if (!stepper || !stepper.parentNode) return; - const ssrChildCount = stepper.childNodes.length; + const ssrText = stepper.textContent; new MutationObserver(() => { - if (stepper.childNodes.length === 0 && ssrChildCount > 0) { + const newText = stepper.textContent; + if (newText !== ssrText && !window.__flashDetected) { window.__flashDetected = true; + window.__flashDetail = { ssr: ssrText.substring(0, 80), hydrated: newText.substring(0, 80) }; } - }).observe(stepper, { childList: true }); + }).observe(stepper, { childList: true, subtree: true, characterData: true }); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', check); @@ -204,9 +207,12 @@ test('home', async ({ page }) => { const noFlash = ssrIndex === hydratedIndex; entries.push({ ok: noFlash, label: `No flash: SSR=${ssrIndex} hydrated=${hydratedIndex} (cookie=7)`, feature: 'no-flash' }); - // Check for hydration flash — island content going empty during hydration - const flashDetected = await page.evaluate(() => window.__flashDetected || false); - entries.push({ ok: !flashDetected, label: `No clobber: ${flashDetected ? 'island went empty during hydration' : 'clean'}`, feature: 'no-clobber' }); + // Check for hydration flash — island text content changed during hydration + const flash = await page.evaluate(() => ({ + detected: window.__flashDetected || false, + detail: window.__flashDetail, + })); + entries.push({ ok: !flash.detected, label: `No clobber: ${flash.detected ? 'text changed — ssr:"' + (flash.detail?.ssr || '').substring(0, 40) + '" → hydrated:"' + (flash.detail?.hydrated || '').substring(0, 40) + '"' : 'clean'}`, feature: 'no-clobber' }); const info = await discoverPage(page); entries.push({ ok: true, label: 'Boot: data-sx-ready', feature: 'boot' });