Files
2026-07-10 15:49:55 -04:00

139 lines
5.3 KiB
Python

"""
Integration tests for the login-free public QR pages (app/routes/public.py).
These lock in CLAUDE.md rule 74 (occupant-safe): the pages are token-addressed,
404 on inactive/unknown facilities, and must never leak checklist/template
names, per-inspection scores, or issue descriptions. Covers both the facility
page (/f/<token>) and the phase39 per-area page (/f/area/<token>).
"""
from app.models.issue import Issue
# ── Facility page ─────────────────────────────────────────────────────────────
def test_facility_page_renders_and_shows_counts(
client, make_facility, make_user, make_template, make_inspection, make_issue):
fac = make_facility()
inspector = make_user(role='inspector')
tpl = make_template(name='SECRET-CHECKLIST-NAME')
make_inspection(fac, inspector, tpl, overall_score=93.8, days_ago=5)
make_inspection(fac, inspector, tpl, overall_score=88.0, days_ago=10)
make_issue(facility=fac, status='open')
resp = client.get(f'/f/{fac.public_token}')
assert resp.status_code == 200
body = resp.get_data(as_text=True)
assert fac.name in body
# Aggregate rating is shown...
assert 'Avg Score' in body
assert 'Report a Problem' in body
def test_facility_page_does_not_leak_internal_detail(
client, make_facility, make_user, make_template, make_inspection, make_issue):
fac = make_facility()
inspector = make_user(role='inspector')
tpl = make_template(name='SECRET-CHECKLIST-NAME')
make_inspection(fac, inspector, tpl, overall_score=77.0, days_ago=3)
make_issue(facility=fac, status='open',
description='CONFIDENTIAL broken toilet in stall 3')
body = client.get(f'/f/{fac.public_token}').get_data(as_text=True)
# Rule 74: no checklist/template names, no issue descriptions.
assert 'SECRET-CHECKLIST-NAME' not in body
assert 'CONFIDENTIAL' not in body
assert 'stall 3' not in body
def test_inactive_facility_404(client, make_facility):
fac = make_facility(active=False)
assert client.get(f'/f/{fac.public_token}').status_code == 404
def test_unknown_token_404(client):
assert client.get('/f/does-not-exist').status_code == 404
def test_facility_report_creates_open_issue(client, db, make_facility):
fac = make_facility()
resp = client.post(
f'/f/{fac.public_token}/report',
data={'description': 'The lobby floor is very slippery today.'},
follow_redirects=True,
)
assert resp.status_code == 200
issues = Issue.query.filter_by(facility_id=fac.id).all()
assert len(issues) == 1
iss = issues[0]
assert iss.status == 'open'
assert iss.severity == 'medium'
assert iss.reported_by is None # public reporter is not a User
assert 'slippery' in iss.description
def test_report_honeypot_silently_drops(client, make_facility):
fac = make_facility()
resp = client.post(
f'/f/{fac.public_token}/report',
data={'description': 'spam spam spam', 'website': 'http://bot.example'},
follow_redirects=True,
)
assert resp.status_code == 200
assert Issue.query.filter_by(facility_id=fac.id).count() == 0
def test_report_rejects_too_short_description(client, make_facility):
fac = make_facility()
resp = client.post(
f'/f/{fac.public_token}/report',
data={'description': 'x'}, # under the 5-char minimum
)
assert resp.status_code == 400
assert Issue.query.filter_by(facility_id=fac.id).count() == 0
# ── Area page (phase39) ───────────────────────────────────────────────────────
def test_area_page_renders(client, make_facility, make_area):
fac = make_facility()
area = make_area(fac)
resp = client.get(f'/f/area/{area.public_token}')
assert resp.status_code == 200
body = resp.get_data(as_text=True)
assert area.name in body
assert fac.name in body
assert 'Report a Problem' in body
def test_area_page_404_when_facility_inactive(client, make_facility, make_area):
fac = make_facility(active=False)
area = make_area(fac)
# Area token is valid, but its parent facility is inactive -> 404.
assert client.get(f'/f/area/{area.public_token}').status_code == 404
def test_area_report_sets_area_id(client, make_facility, make_area):
fac = make_facility()
area = make_area(fac)
resp = client.post(
f'/f/area/{area.public_token}/report',
data={'description': 'Paper towel dispenser is empty in this restroom.'},
follow_redirects=True,
)
assert resp.status_code == 200
iss = Issue.query.filter_by(area_id=area.id).one()
assert iss.facility_id == fac.id
assert iss.area_id == area.id
assert iss.status == 'open'
assert iss.reported_by is None
def test_area_and_facility_tokens_do_not_collide(
client, make_facility, make_area):
"""A facility token hitting the area route (and vice-versa) must 404,
proving the /f/<token> and /f/area/<token> routes stay distinct."""
fac = make_facility()
area = make_area(fac)
# Facility token on the area route -> no area with that token -> 404
assert client.get(f'/f/area/{fac.public_token}').status_code == 404