diff options
Diffstat (limited to 'tests/gallery-probes')
| -rw-r--r-- | tests/gallery-probes/probe-fams.mjs | 4 | ||||
| -rw-r--r-- | tests/gallery-probes/probe.mjs | 108 |
2 files changed, 56 insertions, 56 deletions
diff --git a/tests/gallery-probes/probe-fams.mjs b/tests/gallery-probes/probe-fams.mjs index 7aa2c4b..993d22d 100644 --- a/tests/gallery-probes/probe-fams.mjs +++ b/tests/gallery-probes/probe-fams.mjs @@ -42,7 +42,7 @@ try { 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 + // scope (CSS instrument): 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`); @@ -50,7 +50,7 @@ try { // 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)`); + await evl(`document.getElementById('card-R19').dupre.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); diff --git a/tests/gallery-probes/probe.mjs b/tests/gallery-probes/probe.mjs index e394316..d9ba22f 100644 --- a/tests/gallery-probes/probe.mjs +++ b/tests/gallery-probes/probe.mjs @@ -1,4 +1,4 @@ -// CDP probe for the widget gallery — no playwright, Node global WebSocket/fetch. +// CDP probe for the instrument gallery — no playwright, Node global WebSocket/fetch. // Usage: node probe.mjs [--shot out.png] [--size N] import { spawn } from 'node:child_process'; import { writeFileSync } from 'node:fs'; @@ -65,7 +65,7 @@ try { const errs = events.filter(e => e.method === 'Runtime.exceptionThrown'); ok('no exceptions on load', errs.length === 0, errs.map(e => e.params.exceptionDetails?.exception?.description).join('; ').slice(0, 200)); - // 1. card count (the widgets/row default is checked in 1h) + // 1. card count (the instruments/row default is checked in 1h) const cards = await evl(`document.querySelectorAll('.card').length`); ok('111 cards', cards === 111, `got ${cards}`); @@ -89,7 +89,7 @@ try { const chips = [...document.querySelectorAll('#card-07 .fc')].map(c => c.title); const missing = want.filter(w => !chips.includes(w)); if (missing.length) return 'card 07 missing accents: ' + missing.join(' '); - const built = Object.keys(GW.accentStyles('--x')); + const built = Object.keys(DUPRE.accentStyles('--x')); return JSON.stringify(built) === JSON.stringify(want) ? 'ok' : 'family is ' + JSON.stringify(built); })()`); ok('card 07 offers the shared accent family', accents === 'ok', accents); @@ -107,7 +107,7 @@ try { })()`); ok('card 07 defaults to gold and recolours on click', chipInk === 'ok', chipInk); - // 1e. The colour-policy backbone. Every widget's colour is either free (the + // 1e. The colour-policy backbone. Every instrument's colour is either free (the // consumer picks) or locked for a stated reason, and the colour pass kept // finding cards where "is this one a standard?" was answered from memory and // wrong. So policy is declared on the builder and checked here. The invariant @@ -116,10 +116,10 @@ try { // an accent card can't forget to say so. Coverage grows card by card; this // round classifies the touched set, and the count is reported not gated. const policy = await evl(`(()=>{ - const KINDS = GW.POLICIES; + const KINDS = DUPRE.POLICIES; if (!KINDS) return 'no POLICIES vocabulary'; const valid = new Set(Object.keys(KINDS)); - const fns = Object.entries(GW).filter(([,v]) => typeof v === 'function'); + const fns = Object.entries(DUPRE).filter(([,v]) => typeof v === 'function'); const declared = fns.filter(([,v]) => v.POLICY); // each POLICY record is complete: a valid kind, a why, an authentic range const shape = declared.filter(([,v]) => !valid.has(v.POLICY.kind) || !v.POLICY.why || !v.POLICY.authentic) @@ -177,10 +177,10 @@ try { })()`); ok('colour policy tally sums to the card total', ptally.startsWith('ok'), ptally); - // 1h. widgets/row: the control sets an explicit column count and the cards + // 1h. instruments/row: the control sets an explicit column count and the cards // resize to match. One-per-row cards must be much wider than four-per-row, // and the count actually reaches the grid. - ok('default is 3 widgets/row', await evl(`document.body.dataset.cols`) === '3'); + ok('default is 3 instruments/row', await evl(`document.body.dataset.cols`) === '3'); await evl(`document.querySelector('.szbar .key[data-cols="1"]').click()`); const w1col = await evl(`document.querySelector('.card').getBoundingClientRect().width`); const cols1 = await evl(`getComputedStyle(document.querySelector('.grid')).gridTemplateColumns.split(' ').length`); @@ -189,7 +189,7 @@ try { const cols4 = await evl(`getComputedStyle(document.querySelector('.grid')).gridTemplateColumns.split(' ').length`); ok('1/row is much wider than 4/row', w1col > w4col * 2.5, `w1=${Math.round(w1col)} w4=${Math.round(w4col)}`); ok('the grid renders the chosen column count', cols1 === 1 && cols4 === 4, `1->${cols1} 4->${cols4}`); - ok('widgets/row chip flips state', await evl(`document.body.dataset.cols`) === '4'); + ok('instruments/row chip flips state', await evl(`document.body.dataset.cols`) === '4'); // 3. behavioral, zoomed: fader drag on card 03 changes readout. Run at 2/row, // not 1/row: at one-per-row the card is wide enough that its controls fall @@ -245,7 +245,7 @@ try { // disengaged state instead. dim offText lets an off toggle recede in a dense // panel. Craig's call, 2026-07-16. const atoms = await evl(`(()=>{ - const S = GW.slideToggle.STYLES; + const S = DUPRE.slideToggle.STYLES; const want = { on: ['amber','green','dark','red','warn'], onText: ['panel','cream','green'], off: ['dark','red'], offText: ['white','red','black','dim'], thumb: ['light','dark','chrome','brass'] }; @@ -260,9 +260,9 @@ try { // must resolve in STYLES — a typo here would silently fall through to the // stylesheet default and look "nearly right", which is the worst outcome. const presets = await evl(`(()=>{ - const P = GW.slideToggle.PRESETS, S = GW.slideToggle.STYLES; + const P = DUPRE.slideToggle.PRESETS, S = DUPRE.slideToggle.STYLES; if (!P) return 'no PRESETS'; - const AX = GW.slideToggle.AXIS_ORDER; + const AX = DUPRE.slideToggle.AXIS_ORDER; const bad = []; for (const [name, p] of Object.entries(P)) { for (const ax of AX) { @@ -279,7 +279,7 @@ try { // the only thing carrying state. Both backgrounds must stay dark while the // inks diverge — if either pill lights, the preset has lost its point. const dark = await evl(`(()=>{ - const P = GW.slideToggle.PRESETS.dark, S = GW.slideToggle.STYLES; + const P = DUPRE.slideToggle.PRESETS.dark, S = DUPRE.slideToggle.STYLES; const onBg = S.on[P.on].vars['--sw-on-bg'], offBg = S.off[P.off].vars['--sw-off-bg']; const onInk = S.onText[P.onText].vars['--sw-on-ink'], offInk = S.offText[P.offText].vars['--sw-off-ink']; if (onBg !== offBg) return 'pills differ: on=' + onBg + ' off=' + offBg; @@ -288,7 +288,7 @@ try { })()`); ok('dark preset keeps both pills dark and the inks distinct', dark === 'ok', dark); - // 7b. the card claims the preset it is actually in. The widget defaults to + // 7b. the card claims the preset it is actually in. The instrument defaults to // `panel`, so a preset group with nothing lit would assert "no preset // active" — false, and exactly the kind of quiet mislabel this walk exists // to catch. Nothing above this point touches card 01's chips (checks 2-4 @@ -304,8 +304,8 @@ try { })()`); ok('card 01 defaults to the panel preset', defaultPreset === 'panel', defaultPreset); - // 8. a preset chip drives the widget AND re-syncs the axis chips, so the card - // never shows a combination the widget isn't in. + // 8. a preset chip drives the instrument AND re-syncs the axis chips, so the card + // never shows a combination the instrument isn't in. const applied = await evl(`(()=>{ const card = document.getElementById('card-01'); const groups = [...card.querySelectorAll('.fgroup')]; @@ -319,7 +319,7 @@ try { const brd = card.querySelector('.switch').style.getPropertyValue('--sw-on-brd'); return (lit.length === 1 ? lit[0].title : 'lit=' + lit.length) + '|' + brd; })()`); - ok('armed preset drives widget and syncs the on chip', applied === 'red|var(--fail)', applied); + ok('armed preset drives instrument and syncs the on chip', applied === 'red|var(--fail)', applied); // 8b. axes are not independent: onText overrides the ink `on` sets, so changing // `on` after picking an onText must not silently revert the legend while its @@ -505,10 +505,10 @@ try { // 13. KEYS is a declarative TABLE, not a function over a DOM event. The Emacs // port installs this same table into a keymap — it never sees a keydown — - // so a function here would force it to re-derive the widget's intent and + // so a function here would force it to re-derive the instrument's intent and // the two bindings would drift. (README, keyboard contract.) const keysTable = await evl(`(()=>{ - const K = GW.abcKeypad.KEYS; + const K = DUPRE.abcKeypad.KEYS; if (!K) return 'no KEYS'; if (typeof K !== 'object' || Array.isArray(K)) return 'KEYS is not a plain table: ' + typeof K; const missing = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'].filter(c => K[c] !== c); @@ -519,7 +519,7 @@ try { })()`); ok('R57 KEYS is a declarative table covering the plate', keysTable === 'ok', keysTable); - // 13b. THE contract's first rule: no document-level listener. A widget that + // 13b. THE contract's first rule: no document-level listener. An instrument that // binds globally types into itself from anywhere on a 110-card page. // Typing at the body with the card unfocused must do nothing at all. const unfocused = await evl(`(()=>{ @@ -560,12 +560,12 @@ try { const seq = ['A','B','SPC','7']; key('CLR').dispatchEvent(new MouseEvent('click', {bubbles:true})); seq.forEach(k => key(k).dispatchEvent(new MouseEvent('click', {bubbles:true}))); - const byClick = rd() + '/' + document.getElementById('card-R57').gw.get(); + const byClick = rd() + '/' + document.getElementById('card-R57').dupre.get(); key('CLR').dispatchEvent(new MouseEvent('click', {bubbles:true})); pad.focus(); ['A','B',' ','7'].forEach(k => pad.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, cancelable: true }))); - const byKey = rd() + '/' + document.getElementById('card-R57').gw.get(); + const byKey = rd() + '/' + document.getElementById('card-R57').dupre.get(); return byClick === byKey ? 'ok' : 'drift: click=' + byClick + ' key=' + byKey; })()`); ok('R57 click and key land in the same place', drift === 'ok', drift); @@ -576,7 +576,7 @@ try { // caller is a hole in exactly the target the table exists for. const pressGuard = await evl(`(()=>{ const card = document.getElementById('card-R57'); - const h = card.gw; + const h = card.dupre; if (!h || !h.press) return 'no handle'; const key = k => [...card.querySelectorAll('.kp-key')].find(e => e.dataset.k === k); key('CLR').dispatchEvent(new MouseEvent('click', {bubbles:true})); @@ -590,7 +590,7 @@ try { // 13c-4. Every key the table maps must be a real plate action, or the Emacs // port installs a binding that silently does nothing. const keysSubset = await evl(`(()=>{ - const bad = Object.entries(GW.abcKeypad.KEYS).filter(([,v]) => !GW.abcKeypad.ACTIONS.has(v)); + const bad = Object.entries(DUPRE.abcKeypad.KEYS).filter(([,v]) => !DUPRE.abcKeypad.ACTIONS.has(v)); return bad.length ? 'KEYS maps to non-actions: ' + JSON.stringify(bad) : 'ok'; })()`); ok('R57 every KEYS value is a real plate action', keysSubset === 'ok', keysSubset); @@ -598,7 +598,7 @@ try { // 13d. preventDefault is spent only where there is a default worth killing. // Space scrolls and Backspace navigates back, so those are claimed; Tab is // how the page is navigable and Escape belongs to the audit stepper, so a - // widget that swallows either breaks something it cannot see. + // instrument that swallows either breaks something it cannot see. const defaults = await evl(`(()=>{ const pad = document.querySelector('#card-R57 .kp-pad'); pad.focus(); @@ -637,11 +637,11 @@ try { // click ever prints, the card has silently become a keypad with extra steps. // Reads the BUFFER, not the card readout: the readout is supposed to change // while hunting ("stylus over g"), and asserting on it would fail a correct - // widget for showing the operator where the pointer is. + // instrument for showing the operator where the pointer is. const grammar = await evl(`(()=>{ const cell = c => document.querySelector('#card-R58 .ix-cell[data-c="' + c + '"]'); const lever = document.querySelector('#card-R58 .ix-lever'); - const buf = () => document.getElementById('card-R58').gw.get(); + const buf = () => document.getElementById('card-R58').dupre.get(); document.querySelector('#card-R58 .ix-clear').dispatchEvent(new MouseEvent('click', {bubbles:true})); const empty = buf(); ['M','i','g'].forEach(c => cell(c).dispatchEvent(new MouseEvent('click', {bubbles:true}))); @@ -674,7 +674,7 @@ try { cell('s').dispatchEvent(new MouseEvent('click', {bubbles:true})); lever.dispatchEvent(new MouseEvent('click', {bubbles:true})); lever.dispatchEvent(new MouseEvent('click', {bubbles:true})); - return document.getElementById('card-R58').gw.get(); + return document.getElementById('card-R58').dupre.get(); })()`); /* Exact, on the buffer. /ss$/ on the readout also matched 'sss', so it passed even if selecting printed — unable to fail on the one bug this card is about. */ @@ -722,7 +722,7 @@ try { // redraw. Craig has already said the keys will change; a layout welded into // the drawing is one that never does. const layoutData = await evl(`(()=>{ - const L = GW.indexPlate && GW.indexPlate.LAYOUT; + const L = DUPRE.indexPlate && DUPRE.indexPlate.LAYOUT; if (!L) return 'no LAYOUT'; if (!Array.isArray(L) || !L.every(Array.isArray)) return 'LAYOUT is not a grid'; const cells = document.querySelectorAll('#card-R58 .ix-cell').length; @@ -778,7 +778,7 @@ try { // jump the stylus across the plate to the second. 14e can't see it — a // duplicate inflates the drawn count and the declared count equally. const dupes = await evl(`(()=>{ - const flat = GW.indexPlate.LAYOUT.flat().filter(Boolean); + const flat = DUPRE.indexPlate.LAYOUT.flat().filter(Boolean); const seen = new Set(), dup = new Set(); for (const c of flat) (seen.has(c) ? dup : seen).add(c); return dup.size ? 'duplicated on the plate: ' + [...dup].join(' ') : 'ok'; @@ -788,7 +788,7 @@ try { // 14i. press() is the allowlist for R58 too. R57 has this check; without it, // press('F1') reaching select() unfiltered would ship green. const ixPress = await evl(`(()=>{ - const h = document.getElementById('card-R58').gw; + const h = document.getElementById('card-R58').dupre; h.press('CLR'); ['F1', 'PRINT ', '', 'constructor', 'ZZ'].forEach(k => h.press(k)); return JSON.stringify([h.get(), h.selected()]); @@ -799,7 +799,7 @@ try { // relaying the plate can't leave a keybinding pointing at a character the // plate no longer carries. Enter is the lever. const ixKeys = await evl(`(()=>{ - const K = GW.indexPlate.KEYS, L = GW.indexPlate.LAYOUT; + const K = DUPRE.indexPlate.KEYS, L = DUPRE.indexPlate.LAYOUT; if (!K) return 'no KEYS'; const chars = L.flat().filter(Boolean); const missing = chars.filter(c => K[c] !== c); @@ -816,7 +816,7 @@ try { // demonstrate is gone. const ixType = await evl(`(()=>{ const pad = document.querySelector('#card-R58 .ix-pad'); - const h = document.getElementById('card-R58').gw; + const h = document.getElementById('card-R58').dupre; const send = k => pad.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, cancelable: true })); document.querySelector('#card-R58 .ix-clear').dispatchEvent(new MouseEvent('click', {bubbles:true})); pad.focus(); @@ -834,7 +834,7 @@ try { // argument for having no shift key. const ixCase = await evl(`(()=>{ const pad = document.querySelector('#card-R58 .ix-pad'); - const h = document.getElementById('card-R58').gw; + const h = document.getElementById('card-R58').dupre; const send = k => pad.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, cancelable: true })); document.querySelector('#card-R58 .ix-clear').dispatchEvent(new MouseEvent('click', {bubbles:true})); pad.focus(); @@ -857,12 +857,12 @@ try { ok('R58 leaves Space alone (not on the plate)', ixSpace === 'ok', ixSpace); // 15e. Unfocused, it hears nothing — the contract's first rule, on the second - // widget to take keys. + // instrument to take keys. // Asserts nothing CHANGED, rather than expecting a cleared selection: CLR // is fresh paper, and fresh paper doesn't move the operator's hand, so the // stylus legitimately stays where the previous check left it. const ixBlur = await evl(`(()=>{ - const h = document.getElementById('card-R58').gw; + const h = document.getElementById('card-R58').dupre; document.querySelector('#card-R58 .ix-clear').dispatchEvent(new MouseEvent('click', {bubbles:true})); document.activeElement.blur(); const before = JSON.stringify([h.get(), h.selected()]); @@ -877,7 +877,7 @@ try { // through the declared charset one flap at a time, retarget cleanly, and // animate:false jumps straight to the target. const flapApi = await evl(`(() => { - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; return { reading: typeof h.reading, chars: typeof h.chars, set: typeof h.set }; })()`); ok('N20 handle exposes reading() and chars', flapApi.reading === 'function' && flapApi.chars === 'string', @@ -889,12 +889,12 @@ try { // Let the board settle on a known grid first — the demo ticker left it // anywhere, and every command cascades (there is deliberately no teleport // path). setText is the deterministic seam; next() is random by design. - await evl(`document.querySelector('#card-N20').gw.setText('SYSTEM\\nVOLUME\\nSIGNAL')`); + await evl(`document.querySelector('#card-N20').dupre.setText('SYSTEM\\nVOLUME\\nSIGNAL')`); await sleep(6500); // Start a cascade and sample the displayed reading every 15ms until stable. await evl(`(() => { - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; window.__n20 = { samples: [], anims: 0 }; h.setText('VOLUME\\nSIGNAL\\nRECORD'); // multi-step distances on several cells window.__n20.n = 0; @@ -911,7 +911,7 @@ try { await sleep(6500); const n20 = await evl(`(() => { clearInterval(window.__n20.timer); - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; return { samples: [...new Set(window.__n20.samples)], final: h.reading(), anims: window.__n20.anims, chars: h.chars }; })()`); @@ -933,7 +933,7 @@ try { // Retarget mid-cascade: aim at word 2, then word 3 while still spinning; must land on 3. await evl(`(() => { - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; window.__n20r = { samples: [] }; window.__n20r.timer = setInterval(() => window.__n20r.samples.push(h.reading()), 15); h.setText('SIGNAL\\nRECORD\\nONLINE'); setTimeout(() => h.setText('RECORD\\nONLINE\\nSTEREO'), 180); @@ -941,7 +941,7 @@ try { await sleep(7000); const n20b = await evl(`(() => { clearInterval(window.__n20r.timer); - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; return { final: h.reading().split('\\n')[0], target: 'RECORD', sawSync: window.__n20r.samples.some(s => s.split('\\n')[0] === 'SIGNAL'), anims: document.querySelector('#card-N20').getAnimations({ subtree: true }).length }; @@ -955,7 +955,7 @@ try { const n20s = await evl(`(() => { const el = document.createElement('div'); document.body.appendChild(el); const pool = ['SYSTEM','VOLUME','SIGNAL','RECORD','ONLINE','STEREO','FILTER','OUTPUT']; - const h = GW.splitFlap(el, { rows: 3, cells: 6, words: pool, animate: false }); + const h = DUPRE.splitFlap(el, { rows: 3, cells: 6, words: pool, animate: false }); const grids = [h.reading().split('\\n')]; h.next(); grids.push(h.reading().split('\\n')); h.next(); grids.push(h.reading().split('\\n')); @@ -975,7 +975,7 @@ try { const n20c = await evl(`(() => { const el = document.createElement('div'); document.body.appendChild(el); const settles = []; - const h = GW.splitFlap(el, { animate: false, onSettle: r => settles.push(r) }); + const h = DUPRE.splitFlap(el, { animate: false, onSettle: r => settles.push(r) }); h.set(1); const r = h.reading(); el.remove(); return { r, settles }; @@ -986,7 +986,7 @@ try { // The card is a three-row six-letter board; the demo draws random pool words. const n20d = await evl(`(() => { - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; return { cells: document.querySelectorAll('#card-N20 .flapd').length, lines: document.querySelectorAll('#card-N20 .flapline').length, readLines: h.reading().split('\\n').length }; @@ -997,9 +997,9 @@ try { // Skin axis: dark (cream on black) and the inverse light (black on cream), // switched by the chip rig via setStyle, computed ink actually inverting. const n20e = await evl(`(() => { - const h = document.querySelector('#card-N20').gw; - if (typeof h.setStyle !== 'function' || !GW.splitFlap.STYLES || !GW.splitFlap.STYLES.skin) return 'no skin axis'; - const skins = Object.keys(GW.splitFlap.STYLES.skin); + const h = document.querySelector('#card-N20').dupre; + if (typeof h.setStyle !== 'function' || !DUPRE.splitFlap.STYLES || !DUPRE.splitFlap.STYLES.skin) return 'no skin axis'; + const skins = Object.keys(DUPRE.splitFlap.STYLES.skin); if (skins[0] !== 'paper') return 'paper must list first, got: ' + skins.join(','); if (!['dark','white','light','paper'].every(k => skins.includes(k))) return 'skins are: ' + skins.join(','); const ink = () => getComputedStyle(document.querySelector('#card-N20 .fh')).color; @@ -1025,8 +1025,8 @@ try { ok('N20 skins: paper default first, white ink, cream, ivory — all switch and restore', n20e === 'ok', n20e); const n20fnt = await evl(`(() => { - const h = document.querySelector('#card-N20').gw; - if (!GW.splitFlap.STYLES.font) return 'no font axis'; + const h = document.querySelector('#card-N20').dupre; + if (!DUPRE.splitFlap.STYLES.font) return 'no font axis'; const fam = () => getComputedStyle(document.querySelector('#card-N20 .fh')).fontFamily; const helv = fam(); // the card's default face is Helvetica if (!/helvetica/i.test(helv)) return 'default face is not helvetica: ' + helv; @@ -1056,7 +1056,7 @@ try { // Flap speed: the handle takes setFlapMs and the card's slider drives it. const n20v = await evl(`(() => { - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; if (typeof h.setFlapMs !== 'function' || typeof h.flapMs !== 'function') return 'no speed api'; const before = h.flapMs(); if (before !== 100) return 'default flap rate is ' + before + ', want 100'; @@ -1075,7 +1075,7 @@ try { // board must settle, hold the reading ~2s, and only then take the next update. await evl(`(() => { IH.flap = window.__realFlap; - const h = document.querySelector('#card-N20').gw; + const h = document.querySelector('#card-N20').dupre; window.__n20dwell = { settleAt: 0, changeAt: 0, settled: '' }; h.onSettle(r => { if (!window.__n20dwell.settleAt) { window.__n20dwell.settleAt = performance.now(); window.__n20dwell.settled = r; } }); window.__n20dwell.timer = setInterval(() => { @@ -1114,9 +1114,9 @@ try { await send('Emulation.setEmulatedMedia', { features: [{ name: 'prefers-reduced-motion', value: 'reduce' }] }); await send('Page.reload'); await sleep(2500); - const rm1 = await evl(`document.querySelector('#card-N20').gw.reading()`); + const rm1 = await evl(`document.querySelector('#card-N20').dupre.reading()`); await sleep(5200); - const rm2 = await evl(`(() => ({ r: document.querySelector('#card-N20').gw.reading(), anims: document.getAnimations().length }))()`); + const rm2 = await evl(`(() => ({ r: document.querySelector('#card-N20').dupre.reading(), anims: document.getAnimations().length }))()`); ok('N20 rests under reduced motion (no self-advancing dwell chain)', rm1 === rm2.r && rm2.anims === 0, JSON.stringify({ before: rm1, after: rm2.r, anims: rm2.anims })); |
