aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-16 15:56:54 -0500
committerCraig Jennings <c@cjennings.net>2026-07-16 15:56:54 -0500
commitd3180917944bcedc21e77dff2e3967eb4db142c0 (patch)
treea5ffdae8977487df38e6cf84f7a461cb8310854f
parenta6e5161dd98987043c4112e3f26d33a3aed11f97 (diff)
downloadarchsetup-d3180917944bcedc21e77dff2e3967eb4db142c0.tar.gz
archsetup-d3180917944bcedc21e77dff2e3967eb4db142c0.zip
fix(test): stop a failing screen-family check orphaning its browser
probe-fams.mjs had no try/finally, so a throw skipped chrome.kill() and left the headless browser alive on its port. The next run connected to that survivor and reported results from a stale page: old widgets.js, chips already clicked. It cost me a debug loop today, insisting a card's default ink was green and another's chips were missing, neither of which was true of the page on disk. A probe that answers from the previous run is worse than one that crashes. Its two siblings already had the guard.
-rw-r--r--tests/gallery-probes/probe-fams.mjs113
1 files changed, 75 insertions, 38 deletions
diff --git a/tests/gallery-probes/probe-fams.mjs b/tests/gallery-probes/probe-fams.mjs
index 99b4e92..7aa2c4b 100644
--- a/tests/gallery-probes/probe-fams.mjs
+++ b/tests/gallery-probes/probe-fams.mjs
@@ -15,50 +15,87 @@ const fails = [];
const ok = (n, c, d = '') => { console.log(`${c ? 'PASS' : 'FAIL'} ${n}${d ? ' — ' + d : ''}`); if (!c) fails.push(n); };
await send('Runtime.enable'); await sleep(1500);
-ok('no exceptions on load', events.filter(e => e.method === 'Runtime.exceptionThrown').length === 0);
-// count screen-family rows only — card option groups (e.g. card 01) reuse .famchips
-ok('5 screen chip rows', await evl(`[...document.querySelectorAll('.famchips .lab')].filter(l=>l.textContent==='screen').length`) === 5);
+/* Everything below runs inside try/finally so a failing check cannot orphan the
+ browser. It could before, and the consequence was worse than a leak: the next
+ run connected to the survivor on this same port and reported results from a
+ STALE page — old widgets.js, chips already clicked. A probe that answers from
+ the previous run is worse than one that crashes. */
+try {
+ ok('no exceptions on load', events.filter(e => e.method === 'Runtime.exceptionThrown').length === 0);
+ // count screen-family rows only — card option groups (e.g. card 01) reuse .famchips
+ const famRows = await evl(`[...document.querySelectorAll('.famchips .lab')].filter(l=>l.textContent==='screen').length`);
+ ok('6 screen chip rows', famRows === 6, `got ${famRows}`);
-// default fallback: dmx ink computes to gold-hi rgb(255,190,84)
-const dmxFill0 = await evl(`getComputedStyle(document.querySelector('#card-R10 svg text')).fill`);
-ok('R10 default ink = gold-hi', dmxFill0 === 'rgb(255, 190, 84)', dmxFill0);
+ // default fallback: dmx ink computes to gold-hi rgb(255,190,84)
+ const dmxFill0 = await evl(`getComputedStyle(document.querySelector('#card-R10 svg text')).fill`);
+ ok('R10 default ink = gold-hi', dmxFill0 === 'rgb(255, 190, 84)', dmxFill0);
-// click green chip on R10 -> ink becomes phos rgb(127,224,160)
-await evl(`document.querySelector('#card-R10').querySelector('.fc[title="green"]').click()`);
-const dmxFill1 = await evl(`getComputedStyle(document.querySelector('#card-R10 svg text')).fill`);
-ok('R10 green chip recolors ink', dmxFill1 === 'rgb(127, 224, 160)', dmxFill1);
+ // click green chip on R10 -> ink becomes phos rgb(127,224,160)
+ await evl(`document.querySelector('#card-R10').querySelector('.fc[title="green"]').click()`);
+ const dmxFill1 = await evl(`getComputedStyle(document.querySelector('#card-R10 svg text')).fill`);
+ ok('R10 green chip recolors ink', dmxFill1 === 'rgb(127, 224, 160)', dmxFill1);
-// radar: default sweep line = gold-hi; click green -> phos
-const swSel = `document.querySelector('#card-R31')`;
-const line0 = await evl(`getComputedStyle(document.querySelectorAll('#card-R31 svg line')[0]).stroke`);
-await evl(`${swSel}.querySelector('.fc[title="green"]').click()`);
-const line1 = await evl(`getComputedStyle(document.querySelectorAll('#card-R31 svg line')[0]).stroke`);
-ok('R31 green chip recolors furniture', line0 !== line1 && line1 === 'rgb(88, 184, 126)', `${line0} -> ${line1}`);
+ // radar: default sweep line = gold-hi; click green -> phos
+ const swSel = `document.querySelector('#card-R31')`;
+ const line0 = await evl(`getComputedStyle(document.querySelectorAll('#card-R31 svg line')[0]).stroke`);
+ await evl(`${swSel}.querySelector('.fc[title="green"]').click()`);
+ const line1 = await evl(`getComputedStyle(document.querySelectorAll('#card-R31 svg line')[0]).stroke`);
+ ok('R31 green chip recolors furniture', line0 !== line1 && line1 === 'rgb(88, 184, 126)', `${line0} -> ${line1}`);
-// scope (CSS widget): trace stroke changes on amber chip
-const tr0 = await evl(`getComputedStyle(document.querySelector('.scope polyline')).stroke`);
-await evl(`document.querySelector('.scope').closest('.card').querySelector('.fc[title="amber"]').click()`);
-const tr1 = await evl(`getComputedStyle(document.querySelector('.scope polyline')).stroke`);
-ok('N11 amber chip recolors trace', tr0 !== tr1 && tr1 === 'rgb(255, 190, 84)', `${tr0} -> ${tr1}`);
+ // scope (CSS widget): trace stroke changes on amber chip
+ const tr0 = await evl(`getComputedStyle(document.querySelector('.scope polyline')).stroke`);
+ await evl(`document.querySelector('.scope').closest('.card').querySelector('.fc[title="amber"]').click()`);
+ const tr1 = await evl(`getComputedStyle(document.querySelector('.scope polyline')).stroke`);
+ ok('N11 amber chip recolors trace', tr0 !== tr1 && tr1 === 'rgb(255, 190, 84)', `${tr0} -> ${tr1}`);
-// R19: drag still works after family switch (click vfd, then check the handle's set() writes var-based fills)
-await evl(`document.querySelector('#card-R19 .fc[title="vfd"]').click()`);
-await evl(`document.getElementById('card-R19').gw.set(30,70)`);
-const barFill = await evl(`(()=>{const b=document.querySelectorAll('#card-R19 svg rect')[10];return b.getAttribute('fill');})()`);
-ok('R19 dynamic fills use vars', barFill.startsWith('var(--scr-'), barFill);
+ // R19: drag still works after family switch (click vfd, then check the handle's set() writes var-based fills)
+ await evl(`document.querySelector('#card-R19 .fc[title="vfd"]').click()`);
+ await evl(`document.getElementById('card-R19').gw.set(30,70)`);
+ const barFill = await evl(`(()=>{const b=document.querySelectorAll('#card-R19 svg rect')[10];return b.getAttribute('fill');})()`);
+ ok('R19 dynamic fills use vars', barFill.startsWith('var(--scr-'), barFill);
-// R17: face gradient stop resolves to amber face after chip
-await evl(`document.querySelector('#card-R17 .fc[title="amber"]').click()`);
-const face = await evl(`getComputedStyle(document.querySelector('#card-R17 svg radialGradient stop')).stopColor`);
-ok('R17 amber chip retints face', face === 'rgb(216, 203, 166)', face);
+ // R17: face gradient stop resolves to amber face after chip
+ await evl(`document.querySelector('#card-R17 .fc[title="amber"]').click()`);
+ const face = await evl(`getComputedStyle(document.querySelector('#card-R17 svg radialGradient stop')).stopColor`);
+ ok('R17 amber chip retints face', face === 'rgb(216, 203, 166)', face);
-ok('no exceptions after chip clicks', events.filter(e => e.method === 'Runtime.exceptionThrown').length === 0);
+ // R57's window is a screen like any other, and it offers ALL six families
+ // rather than the five its siblings carry — including vfd, the marquee cyan.
+ const kpFams = await evl(`(()=>{
+ const chips = [...document.querySelectorAll('#card-R57 .fc')].map(c => c.title);
+ const want = ['amber','green','red','blue','vfd','white'];
+ return want.every(f => chips.includes(f)) ? 'ok' : 'got ' + JSON.stringify(chips);
+ })()`);
+ ok('R57 offers all six screen families', kpFams === 'ok', kpFams);
-// screenshot the recolored screens region (scroll R31 into view)
-await evl(`document.querySelector('#card-R31 svg').scrollIntoView({block:'center'})`);
-await sleep(400);
-const shot = await send('Page.captureScreenshot', { format: 'png' });
-writeFileSync('fams.png', Buffer.from(shot.result.data, 'base64'));
-console.log('shot: fams.png');
-chrome.kill();
+ // Default is the shipped gold, unchanged until a chip is clicked. It reads the
+ // same as the amber family's --scr-hi because --gold-hi IS #ffbe54 — which is
+ // what makes the amber default pixel-identical rather than a near-miss.
+ const kpInk0 = await evl(`getComputedStyle(document.querySelector('#card-R57 .kp-pad text')).fill`);
+ ok('R57 default ink = gold-hi', kpInk0 === 'rgb(255, 190, 84)', kpInk0);
+
+ // vfd recolors both the ink and the window behind it — a screen is not just its text
+ await evl(`document.querySelector('#card-R57 .fc[title="vfd"]').click()`);
+ const kpInk1 = await evl(`getComputedStyle(document.querySelector('#card-R57 .kp-pad text')).fill`);
+ ok('R57 vfd chip recolors the ink to marquee cyan', kpInk1 === 'rgb(99, 230, 200)', kpInk1);
+ /* .kp-win, not the first rect on the pad — that one is the faceplate, and
+ reading it made this check report the plate's colour and fail for the wrong
+ reason. */
+ const kpBg = await evl(`getComputedStyle(document.querySelector('#card-R57 .kp-win')).fill`);
+ ok('R57 vfd chip recolors the window too', kpBg === 'rgb(6, 16, 13)', kpBg);
+
+ ok('no exceptions after chip clicks', events.filter(e => e.method === 'Runtime.exceptionThrown').length === 0);
+
+ // screenshot the recolored screens region (scroll R31 into view)
+ await evl(`document.querySelector('#card-R31 svg').scrollIntoView({block:'center'})`);
+ await sleep(400);
+ const shot = await send('Page.captureScreenshot', { format: 'png' });
+ writeFileSync('fams.png', Buffer.from(shot.result.data, 'base64'));
+ console.log('shot: fams.png');
+} catch (e) {
+ console.error('PROBE ERROR: ' + e.message);
+ fails.push('probe-error');
+} finally {
+ chrome.kill();
+}
process.exit(fails.length ? 1 : 0);