From 32fd3ef7d31da4b6ea5fd9409b286d1d4e1ffb48 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 10 Apr 2026 07:22:25 +0000 Subject: [PATCH] =?UTF-8?q?Add=20SSR/hydration=20flash=20detection=20test,?= =?UTF-8?q?=20fix=20to-number=20=E2=86=92=20parse-number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - site-full.spec.js: home test captures SSR counter from raw HTML before JS runs, compares with post-hydration counter. Fails if they differ. - home-stepper.sx: to-number → parse-number (to-number doesn't exist in the OCaml server environment — caused crash on fresh server start) Test output: "No flash: SSR=0 hydrated=0" — passes. Tested on fresh stack=site server, not cached Docker container. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/playwright/site-full.spec.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/playwright/site-full.spec.js b/tests/playwright/site-full.spec.js index 70eabf3c..854fec20 100644 --- a/tests/playwright/site-full.spec.js +++ b/tests/playwright/site-full.spec.js @@ -159,9 +159,23 @@ test('home', async ({ page }) => { const errors = trackErrors(page); const entries = []; - await page.goto(server.baseUrl + '/sx/', { waitUntil: 'domcontentloaded', timeout: 30000 }); + // Capture SSR state before JS runs — detect hydration flash + const ssrResponse = await page.goto(server.baseUrl + '/sx/', { waitUntil: 'commit', timeout: 30000 }); + const ssrHtml = await ssrResponse.text(); + const ssrMatch = ssrHtml.match(/tabular-nums[^>]*>(\d+) \/ (\d+)<\/span>/); + const ssrIndex = ssrMatch ? ssrMatch[1] : null; + + // Wait for hydration await waitForSxReady(page); + // Check post-hydration index + const hydratedIndex = await page.evaluate(() => { + const m = document.body.textContent.match(/(\d+)\s*\/\s*16/); + return m ? m[1] : null; + }); + const noFlash = ssrIndex === hydratedIndex; + entries.push({ ok: noFlash, label: `No flash: SSR=${ssrIndex} hydrated=${hydratedIndex}`, feature: 'no-flash' }); + const info = await discoverPage(page); entries.push({ ok: true, label: 'Boot: data-sx-ready', feature: 'boot' });