diff options
Diffstat (limited to 'packages/meshbay-hub/tests/harness/menu_scroll_probe.py')
| -rwxr-xr-x | packages/meshbay-hub/tests/harness/menu_scroll_probe.py | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/packages/meshbay-hub/tests/harness/menu_scroll_probe.py b/packages/meshbay-hub/tests/harness/menu_scroll_probe.py index 809d1b1..5fb9579 100755 --- a/packages/meshbay-hub/tests/harness/menu_scroll_probe.py +++ b/packages/meshbay-hub/tests/harness/menu_scroll_probe.py @@ -119,7 +119,81 @@ let closed = false; } cases.push({ case: 'pressed outside the menu', closed }); - // 4. And so does a scroll of the page. Not optional: the menu is fixed, so + // 4. Opened partway down the window, the panel must end *inside* it. + // Scrolling a panel whose own bottom is off-screen moves its last rows + // into a region of itself that no scroll can bring back, which is what + // "the last track cannot be reached" was. + closed = false; + render(html`<${Menu} x=${300} y=${300} items=${ITEMS} onClose=${onClose} />`, + document.getElementById('root')); + await frame(); + const low = document.querySelector('.ctx-menu'); + low.scrollTop = low.scrollHeight; + await frame(); + const lowRows = low.querySelectorAll('.ctx-menu-item'); + const lowLast = lowRows[lowRows.length - 1]; + cases.push({ case: 'a long menu opened partway down the window', + openedAt: 300, viewport: window.innerHeight, + panelTop: Math.round(low.getBoundingClientRect().top), + panelBottom: Math.round(low.getBoundingClientRect().bottom), + lastRowBottom: Math.round(lowLast.getBoundingClientRect().bottom), + lastRowLabel: lowLast.textContent.trim(), + overflows: low.scrollHeight > low.clientHeight + 1 }); + + // 5. And it must still end inside it after a submenu has expanded, which + // is a size change happening in `MenuItems`' own state — the placement + // effect's dependencies cannot see it. + // + // Opened low on purpose. A two-row menu 600px down has 192px of room + // beneath it, and that is the height the panel is given; expanding a + // sixty-track list into it must re-place the panel rather than thread + // the list through the porthole the collapsed one was measured for. + const NESTED = [ + { key: 'load', label: 'Load a playlist', items: ITEMS.slice(0, 3) }, + { key: 'remove', label: 'Remove a track', items: ITEMS }, + ]; + render(html`<${Menu} x=${300} y=${600} items=${NESTED} onClose=${onClose} />`, + document.getElementById('root')); + await frame(); + const nested = document.querySelector('.ctx-menu'); + const collapsedBottom = Math.round(nested.getBoundingClientRect().bottom); + const toggle = Array.from(nested.querySelectorAll('.ctx-menu-item')) + .find((b) => b.textContent.indexOf('Remove a track') >= 0); + if (!toggle) return fail('no submenu row to expand'); + toggle.click(); + await frame(); + await sleep(60); + await frame(); + const open = document.querySelector('.ctx-menu'); + open.scrollTop = open.scrollHeight; + await frame(); + const openRows = open.querySelectorAll('.ctx-menu-item'); + const openLast = openRows[openRows.length - 1]; + cases.push({ case: 'a submenu expanded inside it', + openedAt: 600, viewport: window.innerHeight, + collapsedBottom, + panelHeight: Math.round(open.getBoundingClientRect().height), + panelTop: Math.round(open.getBoundingClientRect().top), + panelBottom: Math.round(open.getBoundingClientRect().bottom), + lastRowBottom: Math.round(openLast.getBoundingClientRect().bottom), + lastRowLabel: openLast.textContent.trim(), + overflows: open.scrollHeight > open.clientHeight + 1 }); + + // 6. A short menu opened at the very bottom still flips above the pointer + // rather than being pinned there and scrolled — the condition deciding + // that was rewritten, so it is measured rather than assumed. + const SHORT = ITEMS.slice(0, 4); + render(html`<${Menu} x=${300} y=${780} items=${SHORT} onClose=${onClose} />`, + document.getElementById('root')); + await frame(); + const short = document.querySelector('.ctx-menu'); + cases.push({ case: 'a short menu opened at the bottom edge', + openedAt: 780, viewport: window.innerHeight, + panelTop: Math.round(short.getBoundingClientRect().top), + panelBottom: Math.round(short.getBoundingClientRect().bottom), + overflows: short.scrollHeight > short.clientHeight + 1 }); + + // 7. And so does a scroll of the page. Not optional: the menu is fixed, so // a grid scrolling under it leaves it pointing at the wrong album. render(html`<${Menu} x=${300} y=${40} items=${ITEMS} onClose=${onClose} />`, document.getElementById('root')); |