""" 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/) and the phase39 per-area page (/f/area/). """ 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/ and /f/area/ 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