diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-16 16:42:00 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-16 16:42:00 +0200 |
| commit | e2fedc92a789db4c1fe5d6575108cc43265a10a4 (patch) | |
| tree | f3b41d258efa609faec0187e7c77832ef601f4b8 /packages/meshbay-hub/tests/test_menu_scroll.py | |
| parent | 17ddd4de9087a98c87bec28a6b773572b1c58b50 (diff) | |
| download | meshbay-e2fedc92a789db4c1fe5d6575108cc43265a10a4.tar.gz | |
menu: give the panel the room that is actually below it
`max-height: calc(100vh - 16px)` says how tall the menu may be and nothing
about where its bottom lands, so one opened partway down the window ran
past it and its last rows scrolled out of reach. Measure from where the
panel was placed, and re-measure when a submenu opens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/tests/test_menu_scroll.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_menu_scroll.py | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/packages/meshbay-hub/tests/test_menu_scroll.py b/packages/meshbay-hub/tests/test_menu_scroll.py index 5b680a4..b56a053 100644 --- a/packages/meshbay-hub/tests/test_menu_scroll.py +++ b/packages/meshbay-hub/tests/test_menu_scroll.py @@ -1,5 +1,8 @@ """ -A pop-up menu taller than the window can be scrolled without dismissing itself. +A pop-up menu taller than the window can be scrolled, and scrolled all the way. + +Two defects, one symptom — "the last track cannot be reached" — and they had to +be fixed in that order, because the first hides the second. `.ctx-menu` is `overflow-y: auto` under a `max-height`, and a playlist's tracklist expands *inside* it — sixty tracks is three times the panel's height, @@ -16,6 +19,14 @@ this: it reaches every row with `.click()`, which scrolls nothing at all. The last two cases are the ones that must keep closing the menu, and they are why the fix is a filter on the event's origin rather than a removed listener. + +The second defect is where the panel ends. `max-height: calc(100vh - 16px)` +says how tall it may be and nothing about where its bottom lands, so a panel +opened 300px down the window ran 300px past the bottom of it. It scrolled — but +its last rows scrolled into a part of itself that is off the screen, which no +further scrolling brings back. `menu.js` measures the room left below where it +put the panel. The flip case is measured too, because the condition deciding it +was rewritten in the same breath. """ import json @@ -74,3 +85,58 @@ def test_scrolling_the_page_still_closes_it(cases): # under a sticky toolbar, so a menu that survives leaves itself pointing at # an album that has moved. assert cases["scrolled the page underneath"]["closed"] + + +def test_a_long_menu_ends_inside_the_window(cases): + c = cases["a long menu opened partway down the window"] + assert c["overflows"], f"the fixture measures nothing: {c}" + assert c["panelBottom"] <= c["viewport"], ( + f"the panel runs {c['panelBottom'] - c['viewport']}px past the bottom " + f"of the window: {c}") + + +def test_the_last_row_of_a_long_menu_can_be_reached(cases): + # Scrolled to the end, the last row has to be *visible*. This is the + # user-facing sentence, and the one that fails while the panel overruns the + # window: the rows are there, scrolled into a region nothing can show. + c = cases["a long menu opened partway down the window"] + assert c["lastRowLabel"].startswith("Track 60"), c + assert c["lastRowBottom"] <= c["viewport"], ( + f"the last row sits {c['lastRowBottom'] - c['viewport']}px below the " + f"window after scrolling to the end: {c}") + + +def test_it_still_opens_at_the_pointer_when_the_room_is_below(cases): + # The cure must not be a menu that jumps somewhere else: a list too tall + # for any placement stays where it was asked for and scrolls. + c = cases["a long menu opened partway down the window"] + assert c["panelTop"] == c["openedAt"], c + + +def test_an_expanded_submenu_stays_inside_the_window(cases): + c = cases["a submenu expanded inside it"] + assert c["panelBottom"] > c["collapsedBottom"], ( + f"the submenu did not actually expand: {c}") + assert c["panelBottom"] <= c["viewport"], c + assert c["lastRowLabel"].startswith("Track 60"), c + assert c["lastRowBottom"] <= c["viewport"], c + + +def test_an_expanded_submenu_is_re_placed_rather_than_left_in_its_slot(cases): + # The size change happens in `MenuItems`' own state, which the placement + # effect cannot see on its own — this is what the report upward is for. + # Without it the panel keeps the height measured for its collapsed self: + # the menu stays inside the window, and a sixty-track list is threaded + # through the 192px that were free below where it was opened. + c = cases["a submenu expanded inside it"] + assert c["panelHeight"] > c["viewport"] - c["openedAt"], ( + f"the panel is still the size the collapsed menu was given: {c}") + + +def test_a_short_menu_at_the_bottom_edge_still_flips(cases): + # No regression on the placement that already worked: a menu that fits + # above the pointer is drawn there whole, not pinned to the edge and + # squeezed into the few pixels left below it. + c = cases["a short menu opened at the bottom edge"] + assert c["panelBottom"] <= c["openedAt"], c + assert not c["overflows"], f"a four-item menu should not need scrolling: {c}" |