""" A page whose content fits the window must not offer a scrollbar. Twice now. First the sign-in card: `.layout` and `.page-center` each reserved `100vh - 52px` and the second sat inside the first's 24px padding, so the document was 48px too tall at every window size. Then the chat tab: the panel is sized from JS to `viewport - top - 16`, which puts its bottom 16px above the fold — but `.main` adds 24px of padding below it, so the document came out **exactly 8px too tall, at every window size**, which is what "there is always a scrollbar" means. Neither is visible in the stylesheet. Both are one subtraction against another, in different files, and the only way to see them is to measure the document against the window — which is what this does, running the real `fit()` lifted out of `app.js` rather than a copy of it. """ import json import shutil import subprocess import textwrap from pathlib import Path import pytest HARNESS = Path(__file__).parent / "harness" / "scroll_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") HEIGHTS = [700, 900, 1200] NAV_AND_SIDEBAR = """ """ CHAT_TAB = NAV_AND_SIDEBAR + """

a group

hello

""" SHORT_PAGE = NAV_AND_SIDEBAR + """

a group

not much here

""" def _measure(fragment: str, tmp_path: Path) -> dict: path = tmp_path / "fragment.html" path.write_text(fragment, encoding="utf-8") proc = subprocess.run( ["python3", str(HARNESS), str(path), ",".join(str(h) for h in HEIGHTS)], 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 chat(tmp_path_factory): return _measure(CHAT_TAB, tmp_path_factory.mktemp("chat")) @pytest.fixture(scope="module") def short(tmp_path_factory): return _measure(SHORT_PAGE, tmp_path_factory.mktemp("short")) @pytest.mark.parametrize("height", HEIGHTS) def test_the_chat_tab_fits_its_window(chat, height): r = chat[str(height)] assert r["overflow"] <= 0, ( f"the document is {r['overflow']}px taller than the {height}px window — " f"a scrollbar on the chat tab. Past the fold: {r['past']}") @pytest.mark.parametrize("height", HEIGHTS) def test_nothing_on_the_chat_tab_hangs_below_the_fold(chat, height): """The composer is the one that matters: a chat you cannot type in.""" assert chat[str(height)]["past"] == [] @pytest.mark.parametrize("height", HEIGHTS) def test_the_chat_panel_uses_the_room_it_has(chat, height): """The correction must not overshoot. The panel should end just above the fold, not halfway up the page — a 240px chat in a 1200px window would pass every assertion above and be useless.""" panel = chat[str(height)]["panel"] assert panel, "no chat panel in the measurement" gap = height - panel["bottom"] assert 0 <= gap <= 40, ( f"the panel ends {gap}px above the fold at {height}px") @pytest.mark.parametrize("height", HEIGHTS) def test_a_short_page_does_not_scroll_either(short, height): """The control: without this, a chat panel shrunk to nothing would pass.""" r = short[str(height)] assert r["overflow"] <= 0, f"{r['overflow']}px of overflow with no content"