"""Tests for the public survey submission endpoint.""" import pytest @pytest.mark.asyncio async def test_submit_survey_success(client): """POST valid survey data returns 200 with id.""" payload = { "respondent_name": "Test Engineer", "responses": { "prereqs": ["Who's affected", "What changed recently"], "verify_fix": "Have the user confirm it's working", "steps_at_a_time": "5 steps", }, } response = await client.post("/api/v1/survey/submit", json=payload) assert response.status_code == 200 data = response.json() assert "id" in data assert data["message"] == "Thank you for your response!" @pytest.mark.asyncio async def test_submit_survey_anonymous(client): """Survey works without respondent_name.""" payload = { "responses": { "first_step": "Check if it's one user or many", }, } response = await client.post("/api/v1/survey/submit", json=payload) assert response.status_code == 200 assert "id" in response.json() @pytest.mark.asyncio async def test_submit_survey_missing_responses(client): """Missing responses field returns 422.""" payload = {"respondent_name": "Test"} response = await client.post("/api/v1/survey/submit", json=payload) assert response.status_code == 422 @pytest.mark.asyncio async def test_submit_survey_empty_body(client): """Empty body returns 422.""" response = await client.post("/api/v1/survey/submit", json={}) assert response.status_code == 422 @pytest.mark.asyncio async def test_check_invite_status_not_found(client): """Invalid token returns 404.""" response = await client.get("/api/v1/survey/invite/nonexistent") assert response.status_code == 404 @pytest.mark.asyncio async def test_submit_with_completed_token_returns_409(client, admin_auth_headers): """Submitting with an already-used token returns 409.""" # Create invite create_res = await client.post( "/api/v1/admin/survey-invites", json={"recipient_name": "Test User"}, headers=admin_auth_headers, ) assert create_res.status_code == 200 token = create_res.json()["token"] # First submit succeeds submit_res = await client.post( "/api/v1/survey/submit", json={"responses": {"q1": "answer"}, "token": token}, ) assert submit_res.status_code == 200 # Second submit with same token returns 409 submit_res2 = await client.post( "/api/v1/survey/submit", json={"responses": {"q1": "answer"}, "token": token}, ) assert submit_res2.status_code == 409 @pytest.mark.asyncio async def test_create_invite_requires_admin(client, auth_headers): """Non-admin users cannot create invites.""" response = await client.post( "/api/v1/admin/survey-invites", json={"recipient_name": "Test"}, headers=auth_headers, ) assert response.status_code == 403 @pytest.mark.asyncio async def test_create_and_list_invites(client, admin_auth_headers): """Admin can create and list invites.""" # Create create_res = await client.post( "/api/v1/admin/survey-invites", json={"recipient_name": "John Smith", "recipient_email": "john@msp.example.com"}, headers=admin_auth_headers, ) assert create_res.status_code == 200 data = create_res.json() assert data["recipient_name"] == "John Smith" assert data["status"] == "pending" assert "survey_url" in data # List list_res = await client.get("/api/v1/admin/survey-invites", headers=admin_auth_headers) assert list_res.status_code == 200 invites = list_res.json() assert len(invites) >= 1 @pytest.mark.asyncio async def test_list_survey_responses_admin(client, admin_auth_headers): """Admin can list survey responses.""" await client.post( "/api/v1/survey/submit", json={"respondent_name": "Tester", "responses": {"q1": "answer"}}, ) res = await client.get("/api/v1/admin/survey-responses", headers=admin_auth_headers) assert res.status_code == 200 data = res.json() assert "responses" in data assert "total" in data assert "this_week" in data assert data["total"] >= 1 assert data["responses"][0]["respondent_name"] == "Tester" assert data["responses"][0]["source"] == "direct" @pytest.mark.asyncio async def test_list_survey_responses_requires_admin(client, auth_headers): """Non-admin cannot list survey responses.""" res = await client.get("/api/v1/admin/survey-responses", headers=auth_headers) assert res.status_code == 403 @pytest.mark.asyncio async def test_export_survey_responses_csv(client, admin_auth_headers): """Admin can export survey responses as CSV.""" await client.post( "/api/v1/survey/submit", json={ "respondent_name": "CSV Tester", "responses": { "prereqs": ["Who's affected", "What changed recently"], "verify_fix": "Have the user confirm", "steps_at_a_time": "5 steps", "prioritization": ["Likelihood", "Speed", "Blast radius"], }, }, ) res = await client.get("/api/v1/admin/survey-responses/export", headers=admin_auth_headers) assert res.status_code == 200 assert "text/csv" in res.headers["content-type"] assert "attachment" in res.headers.get("content-disposition", "") body = res.text assert "CSV Tester" in body assert "Respondent" in body @pytest.mark.asyncio async def test_export_survey_responses_requires_admin(client, auth_headers): """Non-admin cannot export survey responses.""" res = await client.get("/api/v1/admin/survey-responses/export", headers=auth_headers) assert res.status_code == 403