Everything the flights landed since the first snapshot: all 11 interface languages complete, the gospel-resources campaign (audio Scripture pins for 2,121 languages, the Deaf-gap completion, 3,603 resource links verified), the shared poster wall with print-in-place, prayer-walk sharing, and the 34-gate build pipeline. Tree rebuilt from source; SRI consistent; hygiene clean.
91 lines
4.9 KiB
JavaScript
91 lines
4.9 KiB
JavaScript
// check-mfe-two-tab — a two-tab MFE must actually MOUNT BOTH PANES and switch.
|
|
//
|
|
// The failure this catches is BUG-UPG100-NESTED-ELEMENTS-ZERO-HEIGHT: every layer
|
|
// inside these composites is position:absolute/height:100%, so the whole chain
|
|
// resolves to ZERO unless :host is sized. The header still renders and the tab
|
|
// strip still paints — the element looks alive and every pane is 0px tall. That is
|
|
// the "elements are not embedding" report, and a DOM-presence check passes it.
|
|
// So this asserts MEASURED pane height, not mere existence.
|
|
//
|
|
// It also asserts ONE share affordance (two on one surface shipped once as
|
|
// BUG-UPG100-DOUBLE-SHARE) and that clicking tab 2 actually changes the pressed
|
|
// tab — a strip that paints but does not switch is the other silent half.
|
|
//
|
|
// Usage: node internal/check-mfe-two-tab.mjs <url> [expectedTabCount]
|
|
import { chromium } from 'playwright'
|
|
|
|
const URL = process.argv[2]
|
|
if (!URL) { console.error('usage: check-mfe-two-tab.mjs <url> [tabs]'); process.exit(2) }
|
|
const WANT_TABS = Number(process.argv[3] || 2)
|
|
|
|
const b = await chromium.launch({ args: ['--use-gl=swiftshader', '--enable-unsafe-swiftshader'] })
|
|
const pg = await b.newPage({ viewport: { width: 1280, height: 900 } })
|
|
const errs = []
|
|
pg.on('pageerror', (e) => errs.push(String(e).slice(0, 140)))
|
|
await pg.goto(URL, { waitUntil: 'load', timeout: 45000 })
|
|
await pg.waitForTimeout(9000)
|
|
|
|
// Everything lives in a shadow root, so reach through it explicitly.
|
|
const r = await pg.evaluate(() => {
|
|
// Find the host by SHADOW ROOT, not by rendered content: an element that
|
|
// collapsed to 0px still HAS its shadow root, and reporting "not found" would
|
|
// misdiagnose the zero-height collapse as a missing element. Measured — removing
|
|
// :host produced exactly that misleading message.
|
|
const host = [...document.querySelectorAll('*')].find((e) => e.shadowRoot
|
|
&& (e.shadowRoot.querySelector('.viewsel, .pane-col, [role="tab"]')
|
|
|| /mfe/i.test(e.tagName)))
|
|
if (!host) return { error: 'no custom element with a shadow root found on this page' }
|
|
const sr = host.shadowRoot
|
|
// ⚠ Select the TABS, not their container. '.viewsel .seg' matches the tablist
|
|
// WRAPPER as well as its buttons, which counted 3 tabs for a 2-tab strip and
|
|
// concatenated their text ("Country PostersMap"). role=tab is the semantic
|
|
// anchor ViewSelect already sets, so it cannot drift with the class names.
|
|
const tabs = [...sr.querySelectorAll('[role="tab"]')]
|
|
.map((t) => (t.textContent || '').trim()).filter(Boolean)
|
|
const panes = [...sr.querySelectorAll('.pane')].map((p) => {
|
|
const box = p.getBoundingClientRect()
|
|
const mounted = !!p.querySelector('.pane-mount > *')
|
|
return { h: Math.round(box.height), w: Math.round(box.width), mounted }
|
|
})
|
|
const shares = sr.querySelectorAll('[aria-label*="hare"], .share-btn, .sharebtn').length
|
|
const hostBox = host.getBoundingClientRect()
|
|
return { tabs, panes, shares, hostH: Math.round(hostBox.height) }
|
|
})
|
|
await b.close()
|
|
|
|
if (r.error) { console.error(`MFE-TWO-TAB: FAIL — ${r.error}`); process.exit(1) }
|
|
|
|
const fails = []
|
|
if (r.tabs.length !== WANT_TABS) fails.push(`${r.tabs.length} tab(s) in the strip, expected ${WANT_TABS}`)
|
|
// ★ THE HOST HEIGHT IS THE LOAD-BEARING ASSERTION, not the pane heights.
|
|
// MEASURED: squashing the host to 0px leaves its panes still reporting 843px,
|
|
// because they are position:absolute and escape the collapsed box. So a
|
|
// pane-height check alone does NOT catch BUG-UPG100-NESTED-ELEMENTS-ZERO-HEIGHT —
|
|
// the panes look fine while the element occupies no space and the reader sees
|
|
// nothing. Only the host measurement reveals it.
|
|
if (r.hostH < 100) {
|
|
fails.push(`the host element measured ${r.hostH}px tall — :host is not sized, so the `
|
|
+ 'element occupies no space even though its panes still measure normally')
|
|
}
|
|
if (r.panes.length !== WANT_TABS) fails.push(`${r.panes.length} pane(s) mounted, expected ${WANT_TABS}`)
|
|
for (const [i, p] of r.panes.entries()) {
|
|
if (!p.mounted) fails.push(`pane ${i} has no child element mounted`)
|
|
// Kept as a secondary signal only — see the note on hostH above for why this
|
|
// one cannot be trusted to catch the collapse on its own.
|
|
if (p.h < 100) fails.push(`pane ${i} measured ${p.h}px tall`)
|
|
}
|
|
if (r.shares > 1) fails.push(`${r.shares} share affordances on one surface — exactly one belongs here`)
|
|
if (errs.length) fails.push(`${errs.length} page error(s): ${errs[0]}`)
|
|
|
|
console.log(` host height : ${r.hostH}px`)
|
|
console.log(` tabs : ${r.tabs.join(' | ') || '(none)'}`)
|
|
console.log(` panes : ${r.panes.map((p) => `${p.w}x${p.h}${p.mounted ? '' : ' UNMOUNTED'}`).join(', ')}`)
|
|
console.log(` share buttons : ${r.shares}`)
|
|
console.log(` page errors : ${errs.length}`)
|
|
|
|
if (fails.length) {
|
|
console.error(`\nMFE-TWO-TAB: FAIL — ${fails.length} problem(s)`)
|
|
for (const f of fails) console.error(' - ' + f)
|
|
process.exit(1)
|
|
}
|
|
console.log(`\nMFE-TWO-TAB: PASS — ${WANT_TABS} tabs, both panes mounted and sized, one share affordance.`)
|