"""Tests for reports router (/api/reports). Note: Report generation requires WeasyPrint/Kaleido and Jinja2 templates. These tests mock the PDF generation to test endpoint plumbing and auth. """ from unittest.mock import AsyncMock, patch import pytest from httpx import AsyncClient from sqlalchemy.ext.asyncio import AsyncSession from models.user import User from tests.conftest import auth_headers, create_test_recipe class TestMeasurementReport: """GET /api/reports/measurements tests.""" async def test_generate_measurement_report( self, client: AsyncClient, metrologist_user: User, db_session: AsyncSession, ): """Metrologist can generate a measurement report (mocked PDF).""" recipe = await create_test_recipe( db_session, metrologist_user.id ) fake_pdf = b"%PDF-1.4 fake content" with patch( "routers.reports.generate_measurement_report", new_callable=AsyncMock, return_value=fake_pdf, ): resp = await client.get( "/api/reports/measurements", headers=auth_headers(metrologist_user), params={"recipe_id": recipe.id}, ) assert resp.status_code == 200 assert resp.headers["content-type"] == "application/pdf" assert b"%PDF" in resp.content async def test_report_requires_auth(self, client: AsyncClient): """Report endpoints require authentication.""" resp = await client.get( "/api/reports/measurements", params={"recipe_id": 1}, ) assert resp.status_code == 401 class TestSPCReport: """GET /api/reports/spc tests.""" async def test_generate_spc_report( self, client: AsyncClient, metrologist_user: User, db_session: AsyncSession, ): """Metrologist can generate an SPC report (mocked PDF).""" recipe = await create_test_recipe( db_session, metrologist_user.id ) # Get subtask_id tasks_resp = await client.get( f"/api/recipes/{recipe.id}/tasks", headers=auth_headers(metrologist_user), ) subtask_id = tasks_resp.json()[0]["subtasks"][0]["id"] fake_pdf = b"%PDF-1.4 spc report content" with patch( "routers.reports.generate_spc_report", new_callable=AsyncMock, return_value=fake_pdf, ): resp = await client.get( "/api/reports/spc", headers=auth_headers(metrologist_user), params={ "recipe_id": recipe.id, "subtask_id": subtask_id, }, ) assert resp.status_code == 200 assert resp.headers["content-type"] == "application/pdf" async def test_spc_report_requires_metrologist( self, client: AsyncClient, maker_user: User, db_session: AsyncSession, ): """Non-Metrologist cannot generate SPC reports.""" recipe = await create_test_recipe(db_session, maker_user.id) resp = await client.get( "/api/reports/spc", headers=auth_headers(maker_user), params={"recipe_id": recipe.id, "subtask_id": 1}, ) assert resp.status_code == 403