aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_media_pager.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_media_pager.py')
-rw-r--r--packages/meshbay-hub/tests/test_media_pager.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_media_pager.py b/packages/meshbay-hub/tests/test_media_pager.py
new file mode 100644
index 0000000..a8a0569
--- /dev/null
+++ b/packages/meshbay-hub/tests/test_media_pager.py
@@ -0,0 +1,71 @@
+"""
+Videos and Music show their cards a page at a time (`pager.js`).
+
+The page size is a hub preference, so two things can go wrong without any
+error on screen: a stored value the client misreads, and a key the hub refuses
+— the Settings select would snap back and nothing would say why. The functions
+are read out of `pager.js` rather than copied, and the key out of both files.
+"""
+
+import json
+import re
+import shutil
+import subprocess
+from pathlib import Path
+
+import pytest
+
+ROOT = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub"
+PAGER = ROOT / "static" / "pager.js"
+USERS = ROOT / "api" / "users.py"
+
+pytestmark = pytest.mark.skipif(
+ shutil.which("node") is None or not PAGER.exists(),
+ reason="node or the SPA sources are not available")
+
+
+@pytest.fixture(scope="module")
+def source():
+ text = PAGER.read_text(encoding="utf-8")
+ consts = re.findall(r"^export const PAGE_SIZE_\w+ = [^;]+;", text, re.M)
+ funcs = [re.search(rf"^export function {name}\(.*?^\}}", text, re.M | re.S)
+ for name in ("pageSizeFrom", "pageBounds")]
+ assert len(consts) == 4 and all(funcs), "pager.js no longer has what this test reads"
+ return "\n".join(consts + [m.group(0) for m in funcs]).replace("export ", "")
+
+
+def _run(tmp_path, source, expr):
+ script = tmp_path / "case.js"
+ script.write_text(f"{source}\nconsole.log(JSON.stringify({expr}));")
+ out = subprocess.run(["node", str(script)], capture_output=True, text=True, check=True)
+ return json.loads(out.stdout)
+
+
+@pytest.mark.parametrize("stored, expected", [
+ (None, 50), ("", 50), ("30", 30), ("10", 10), ("200", 200),
+ ("0", 50), ("210", 50), ("35", 50), ("abc", 50), ("-10", 50),
+])
+def test_page_size_from_preference(tmp_path, source, stored, expected):
+ prefs = {} if stored is None else {"media_page_size": stored}
+ assert _run(tmp_path, source, f"pageSizeFrom({json.dumps(prefs)})") == expected
+
+
+@pytest.mark.parametrize("total, size, page, expected", [
+ (0, 50, 0, {"page": 0, "last": 0, "start": 0, "end": 0}),
+ (120, 50, 0, {"page": 0, "last": 2, "start": 0, "end": 50}),
+ (120, 50, 2, {"page": 2, "last": 2, "start": 100, "end": 120}),
+ (100, 50, 1, {"page": 1, "last": 1, "start": 50, "end": 100}),
+ # The list shrank under the reader: the last page that exists, not an empty one.
+ (60, 50, 4, {"page": 1, "last": 1, "start": 50, "end": 60}),
+ (60, 50, -1, {"page": 0, "last": 1, "start": 0, "end": 50}),
+])
+def test_page_bounds(tmp_path, source, total, size, page, expected):
+ assert _run(tmp_path, source, f"pageBounds({total}, {size}, {page})") == expected
+
+
+def test_hub_accepts_the_key_the_client_writes():
+ key = re.search(r"^export const PAGE_SIZE_PREF = '([^']+)';",
+ PAGER.read_text(encoding="utf-8"), re.M).group(1)
+ allowed = re.search(r"ALLOWED_PREF_KEYS = frozenset\(\[(.*?)\]\)",
+ USERS.read_text(encoding="utf-8"), re.S).group(1)
+ assert f'"{key}"' in allowed