diff --git a/internal/verify-map-paint.mjs b/internal/verify-map-paint.mjs index a124870c5..7c3047935 100644 --- a/internal/verify-map-paint.mjs +++ b/internal/verify-map-paint.mjs @@ -89,10 +89,26 @@ for (const url of urls) { await page.waitForTimeout(15000) const r = await page.evaluate(() => { - const host = [...document.querySelectorAll('*')].find((e) => e.tagName.includes('-')) + // ★ SHADOW DOM DOES NOT PIERCE — walk NESTED roots recursively (fixed 2026-09-20). + // A cap-4/cap-5 COMPOSITE mounts child custom elements, each with its OWN shadow root, + // so the map canvas lives one (or more) levels DOWN. A single-level + // `shadowRoot.querySelector('canvas')` can never see it and reports a perfectly working + // map as "no canvas". That false negative cost three wrong diagnoses of upg-100-mfe: + // "the Map tab is unwired", then "the pane has zero height" — while live measurement + // through nested roots showed a 1280x800 canvas with a live GL context the whole time. + // Flat leaves were unaffected, which is exactly why the blind spot survived: the gate + // passed the four single-level leaves and only lied about composites. + const deep = (root, sel, out = []) => { + out.push(...root.querySelectorAll(sel)) + for (const el of root.querySelectorAll('*')) if (el.shadowRoot) deep(el.shadowRoot, sel, out) + return out + } + const host = [...document.querySelectorAll('*')].find((e) => e.tagName.includes('-') && e.shadowRoot) const sr = host && host.shadowRoot if (!sr) return { shadow: false } - const cv = sr.querySelector('canvas') + // Prefer a canvas that actually HAS a GL context, at any depth. + const canvases = deep(sr, 'canvas') + const cv = canvases.find((c) => c.getContext('webgl2') || c.getContext('webgl')) || canvases[0] || null // Read ONLY user-visible copy: shadowRoot.textContent includes the injected