diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_layout_measured.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_layout_measured.py | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/packages/meshbay-hub/tests/test_layout_measured.py b/packages/meshbay-hub/tests/test_layout_measured.py index 57d325a..298a754 100644 --- a/packages/meshbay-hub/tests/test_layout_measured.py +++ b/packages/meshbay-hub/tests/test_layout_measured.py @@ -62,8 +62,12 @@ NAV = textwrap.dedent(""" </div> </div> </div> + <a class="nav-notif nav-search" href="#/search"> + <svg class="icon" viewBox="0 0 24 24"></svg></a> <a class="nav-notif" href="#/">🔔</a> - <div class="user-menu"><button class="nav-btn">someone</button></div> + <div class="user-menu-wrap"><button class="user-menu-trigger"> + <span class="user-menu-avatar">S</span><span class="user-menu-name">someone</span> + </button></div> </div> </nav> """) @@ -206,8 +210,12 @@ GROUPED = textwrap.dedent(""" </div> </div> </div> + <a class="nav-notif nav-search" href="#/search"> + <svg class="icon" viewBox="0 0 24 24"></svg></a> <a class="nav-notif" href="#/">🔔</a> - <div class="user-menu"><button class="nav-btn">someone</button></div> + <div class="user-menu-wrap"><button class="user-menu-trigger"> + <span class="user-menu-avatar">S</span><span class="user-menu-name">someone</span> + </button></div> </div> </nav> """) @@ -283,3 +291,74 @@ def test_the_waiting_bar_is_as_wide_as_a_progress_bar(grouped): assert bar["width"] > 100, ( f"at {width} px the waiting bar is {bar['width']} px wide") assert bar["height"] >= 3, "the waiting bar has no height" + + +# ── The whole nav on a phone ──────────────────────────────────────────────── +# +# Search moved from the sidebar to the nav, beside the bell. With the user's +# name in the menu trigger, a 20-character handle already put the trigger 79 px +# off a 320 px screen, and 159 px once search and a transfer were there too. +# The fixture is the real markup of `Nav()` and `UserMenu()`, with the icons as +# the 1em boxes `Icon()` draws. + +_ICON = '<svg class="icon" viewBox="0 0 24 24"></svg>' +FULL_NAV = textwrap.dedent(f""" + <nav class="nav"> + <div class="nav-left"> + <button class="nav-hamburger">{_ICON}</button> + <a class="nav-brand" href="#/"><img class="nav-brand-m" alt="M">eshBay</a> + </div> + <div class="nav-right"> + <div class="transfer-wrap"> + <button class="nav-notif transfer-btn">{_ICON}<span class="notif-badge">2</span></button> + </div> + <a class="nav-notif nav-search" href="#/search">{_ICON}</a> + <a class="nav-notif" href="#/">{_ICON}<span class="notif-badge">3</span></a> + <div class="user-menu-wrap"> + <button class="user-menu-trigger"> + <span class="user-menu-avatar">A</span> + <span class="user-menu-name">a_rather_long_handle</span> + <svg class="icon user-menu-caret" viewBox="0 0 24 24"></svg> + </button> + </div> + </div> + </nav> +""") +FULL_NAV_WIDTHS = [320, 360, 412, 521, 768, 1024] + + +@pytest.fixture(scope="module") +def full_nav(tmp_path_factory): + fragment = tmp_path_factory.mktemp("fullnav") / "fragment.html" + fragment.write_text(FULL_NAV, encoding="utf-8") + proc = subprocess.run( + ["python3", str(HARNESS), ",".join(str(w) for w in FULL_NAV_WIDTHS), + str(fragment), ".nav-brand", ".nav-right", ".user-menu-trigger", + ".user-menu-name"], + capture_output=True, text=True, timeout=180) + assert proc.returncode == 0, f"probe failed: {proc.stdout}{proc.stderr}" + out = json.loads(proc.stdout) + assert "error" not in out, f"no measurement: {out}" + return out + + +@pytest.mark.parametrize("width", FULL_NAV_WIDTHS) +def test_the_user_menu_stays_inside_the_nav(full_nav, width): + """Off the right edge is where nobody can open it — and it holds sign-out.""" + boxes = full_nav[str(width)]["boxes"] + trigger = boxes[".user-menu-trigger"] + assert trigger["right"] <= width - 16, ( + f"at {width} px the user menu ends at {trigger['right']} px, past the " + "nav's own padding") + assert boxes[".nav-right"]["left"] >= boxes[".nav-brand"]["right"], ( + f"at {width} px the nav's icons slide under the wordmark") + + +@pytest.mark.parametrize("width", FULL_NAV_WIDTHS) +def test_the_name_leaves_the_trigger_on_mobile_only(full_nav, width): + """Avatar alone up to the mobile breakpoint; the name beside it on a desktop.""" + name = full_nav[str(width)]["boxes"][".user-menu-name"] + shown = bool(name and name["width"] > 0) + assert shown == (width > 768), ( + f"at {width} px the name in the user menu is " + f"{'shown' if shown else 'hidden'}") |