diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_sidebar_legal_measured.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_sidebar_legal_measured.py | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_sidebar_legal_measured.py b/packages/meshbay-hub/tests/test_sidebar_legal_measured.py new file mode 100644 index 0000000..faaaec7 --- /dev/null +++ b/packages/meshbay-hub/tests/test_sidebar_legal_measured.py @@ -0,0 +1,101 @@ +""" +The legal link at the foot of the sidebar, measured in a browser. + +It is pinned to the bottom of the window, not of the page: the sidebar sticks +under the navigation bar at the window's height, so on a long file list the +link is still on screen. And the music bar, pinned to the bottom of the window +as well, must not cover it — the bar publishes its height as `--music-bar-h` +(sticky.js, as the toolbars do), and the sidebar stops above it. That value +is set by hand here; what is under test is the stylesheet's arithmetic. + +On a phone the sidebar is the slide-out panel, measured open. +""" + +import json +import shutil +import subprocess +import textwrap +from pathlib import Path + +import pytest + +HARNESS = Path(__file__).parent / "harness" / "layout_probe.py" +STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" + +pytestmark = pytest.mark.skipif( + shutil.which("google-chrome") is None or not (STATIC / "style.css").exists(), + reason="Chrome or the SPA stylesheet is not available") + +# The probe's frames are this tall. +WINDOW_H = 740 +MUSIC_BAR_H = 64 +WIDTHS = [390, 1024, 1440] + + +def _page(music: bool) -> str: + groups = "".join( + f'<a class="sidebar-item sidebar-group" href="#/"><span class="si-head">' + f'<span class="sidebar-item-name">Some group {i}</span></span></a>' for i in range(4)) + bar = (f'<div class="music-player-bar" style="height:{MUSIC_BAR_H}px;' + f'box-sizing:border-box">a track</div>') if music else "" + style = f' style="--music-bar-h:{MUSIC_BAR_H}px"' if music else "" + return textwrap.dedent(f""" + <div id="app"{style}> + <nav class="nav"><div class="nav-left"><a class="nav-brand" href="#/">MeshBay</a></div> + <div class="nav-right"><button class="nav-btn">someone</button></div></nav> + <div class="layout"> + <aside class="sidebar open"> + <div class="sidebar-section"><div class="sidebar-heading">My groups</div>{groups}</div> + <a class="sidebar-legal" href="/legal/">Legal information</a> + </aside> + <main class="main"><h2>A long list</h2><div style="height:3000px"></div></main> + </div> + {bar} + </div> + """) + + +def _measure(tmp_path_factory, music: bool) -> dict: + fragment = tmp_path_factory.mktemp("sidebar") / "fragment.html" + fragment.write_text(_page(music), encoding="utf-8") + proc = subprocess.run( + ["python3", str(HARNESS), ",".join(str(w) for w in WIDTHS), + str(fragment), ".sidebar-legal", ".sidebar", ".music-player-bar"], + 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.fixture(scope="module") +def plain(tmp_path_factory): + return _measure(tmp_path_factory, music=False) + + +@pytest.fixture(scope="module") +def playing(tmp_path_factory): + return _measure(tmp_path_factory, music=True) + + +@pytest.mark.parametrize("width", WIDTHS) +def test_the_link_is_at_the_bottom_of_the_window(plain, width): + """Not at the bottom of a 3000px page, where nobody would find it.""" + link = plain[str(width)]["boxes"][".sidebar-legal"] + assert link is not None, "no legal link" + bottom = link["top"] + link["height"] + assert WINDOW_H - 8 <= bottom <= WINDOW_H, ( + f"at {width} px the link ends at {bottom}, the window at {WINDOW_H}") + assert link["offLeft"] == 0 and link["offRight"] == 0 + + +@pytest.mark.parametrize("width", WIDTHS) +def test_the_music_bar_does_not_cover_it(playing, width): + link = playing[str(width)]["boxes"][".sidebar-legal"] + bar = playing[str(width)]["boxes"][".music-player-bar"] + assert link is not None and bar is not None + bottom = link["top"] + link["height"] + assert bottom <= bar["top"] + 1, ( + f"at {width} px the link ends at {bottom} and the music bar starts at {bar['top']}") + assert bottom >= bar["top"] - 8, ( + f"at {width} px the link floats {bar['top'] - bottom} px above the music bar") |