diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_site_basics.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_site_basics.py | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_site_basics.py b/packages/meshbay-hub/tests/test_site_basics.py new file mode 100644 index 0000000..a3da39a --- /dev/null +++ b/packages/meshbay-hub/tests/test_site_basics.py @@ -0,0 +1,81 @@ +""" +The files every website is expected to have at the root of its origin. + +They live in the hub's static directory, which is mounted at "/", so every hub +serves them — meshbay.org included, because its Caddyfile hands the hub every +path the public site does not name. +""" + +import re +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient +from meshbay_hub.app import create_app + +CADDYFILE = Path(__file__).resolve().parents[3] / "packaging" / "caddy" / "meshbay.org.Caddyfile" + + +@pytest.fixture(scope="module") +def client(): + return TestClient(create_app()) + + +def test_robots_keeps_crawlers_out_of_the_signed_in_views(client): + r = client.get("/robots.txt") + assert r.status_code == 200 + assert r.headers["content-type"].startswith("text/plain") + rules = re.findall(r"^Disallow:\s*(\S+)", r.text, re.M) + assert "/app/" in rules and "/v1/" in rules + # A crawler rendering the sign-in page needs its scripts and stylesheet. + assert not any(rule in ("/", "/a/", "/app") for rule in rules), rules + + +@pytest.mark.parametrize("path, magic", [ + ("/favicon.ico", b"\x00\x00\x01\x00"), + ("/apple-touch-icon.png", b"\x89PNG"), +]) +def test_the_icons_are_served_from_the_root(client, path, magic): + """Browsers ask for both at the root whether or not a page links them.""" + r = client.get(path) + assert r.status_code == 200 + assert r.content.startswith(magic), f"{path} is not the image it claims to be" + + +@pytest.mark.skipif(not CADDYFILE.exists(), reason="no Caddyfile in this tree") +@pytest.mark.parametrize("path", ["/robots.txt", "/favicon.ico", "/apple-touch-icon.png"]) +def test_meshbay_org_sends_them_to_the_hub(path): + """The public site owns only the paths its matcher names; a file claimed + there would be looked for in /srv/meshbay/site and 404.""" + m = re.search(r"^\s*@site path (.+)$", CADDYFILE.read_text(), re.M) + assert m, "the @site matcher is gone" + assert path not in m.group(1).split() + + +def _og(html: str, prop: str) -> str | None: + m = re.search(rf'<meta property="og:{prop}" content="([^"]*)">', html) + return m and m.group(1) + + +def test_a_link_to_the_hub_previews_with_the_logo(): + """Messengers draw a link from og:title and og:image, and resolve only an + absolute image URL — so it names the hub's public name, and the file is + one the hub serves.""" + from meshbay_hub.config import load_config + cfg = load_config() + cfg.identity.id = "hub.example.org" + client = TestClient(create_app(cfg)) + for path in ("/", "/app"): + html = client.get(path).text + assert _og(html, "title") == "MeshBay" + assert _og(html, "image") == "https://hub.example.org/og-image.jpg", path + image = client.get("/og-image.jpg") + assert image.status_code == 200 and image.content.startswith(b"\xff\xd8") + assert len(image.content) < 300_000, "too heavy for some messengers to fetch" + + +def test_the_preview_description_fits_in_a_preview(): + """A preview shows a line or two and cuts the rest; a cut sentence says + nothing.""" + from meshbay_hub.api.webapp import PREVIEW_DESCRIPTION + assert len(PREVIEW_DESCRIPTION) <= 60 |