- Moved app.py, db.py, gateway.py, templates.py, embeddings.py, rns_client.py, and handlers/ into src/tinyweb/ - Created root app.py shim (adds src/ to sys.path, imports main) - Created pyproject.toml with setuptools config (where = ["src"]) - Added src/tinyweb/__init__.py - Updated all internal imports to use tinyweb. prefix (73 occurrences) - Removed sys.path.insert hack from conftest.py - Updated Dockerfile: pip install -e /app before running - Updated gateway.py usage message: python -m tinyweb.gateway - Updated README.md gateway usage instructions
63 lines
2.4 KiB
Python
63 lines
2.4 KiB
Python
"""Tests for `handle_search` — the home page + primary user flow."""
|
|
from tinyweb.handlers import handle_search
|
|
|
|
|
|
def test_empty_index_empty_query_shows_welcome(temp_db, csrf_session):
|
|
resp = handle_search({})
|
|
assert resp["status"] == 200
|
|
body = resp["body"]
|
|
assert "Your index is empty" in body
|
|
# Links the welcome panel offers as equal-weight starting points.
|
|
assert "/add" in body
|
|
assert "/style" in body
|
|
assert "/subscriptions" in body
|
|
|
|
|
|
def test_empty_index_with_query_shows_no_results(temp_db, csrf_session):
|
|
resp = handle_search({"q": ["rust"]})
|
|
assert resp["status"] == 200
|
|
assert "No results in your index" in resp["body"]
|
|
|
|
|
|
def test_populated_index_with_matching_query_returns_results(seeded_db, csrf_session):
|
|
resp = handle_search({"q": ["rust"]})
|
|
assert resp["status"] == 200
|
|
assert "Rust Intro" in resp["body"]
|
|
# Page count shown in meta line.
|
|
assert "4 pages indexed" in resp["body"]
|
|
|
|
|
|
def test_query_only_matches_relevant_pages(seeded_db, csrf_session):
|
|
resp = handle_search({"q": ["ocaml"]})
|
|
body = resp["body"]
|
|
assert "Why OCaml" in body
|
|
assert "Python Tips" not in body
|
|
assert "Rust Intro" not in body
|
|
|
|
|
|
def test_pagination_query_param_respected(seeded_db, csrf_session):
|
|
"""A high page number should still render without crashing."""
|
|
resp = handle_search({"q": ["example"], "p": ["99"]})
|
|
assert resp["status"] == 200
|
|
|
|
|
|
def test_trusted_sites_fallback_surfaces_when_query_matches_link_label(seeded_db, csrf_session):
|
|
"""Links extracted from indexed pages act as a fallback when direct results
|
|
are absent or thin; labels are substring-matched case-insensitively."""
|
|
resp = handle_search({"q": ["advanced"]})
|
|
body = resp["body"]
|
|
# The label "advanced rust guide" is on a link extracted from rust-intro.
|
|
assert "advanced rust guide" in body
|
|
assert "trusted sites" in body
|
|
|
|
|
|
def test_page_count_in_meta_line(seeded_db, csrf_session):
|
|
resp = handle_search({})
|
|
assert "4 pages indexed" in resp["body"]
|
|
|
|
|
|
def test_csp_and_security_headers_not_in_handler_but_via_dispatch(seeded_db, csrf_session):
|
|
"""Handler itself returns no security headers; dispatch_request wraps them.
|
|
This test documents the boundary so future refactors don't break assumptions."""
|
|
resp = handle_search({})
|
|
assert "headers" not in resp or "Content-Security-Policy" not in resp.get("headers", {})
|