ghost-shopper-api / python /tests /test_pdf_assessments.py
azzaraqi
Deploy FastAPI backend with Supabase pooler support
b84ea83
Raw
History Blame Contribute Delete
5.45 kB
"""
Unit Tests — PDFService with Assessment Data
Tests:
- PDF generation with assessment items
- PDF with GS-specific visit fields (ghost_shopper, visit_type)
- PDF with multiple categories (A-E)
- PDF includes signature section
- PDF binary category D rendering (Ya/Tidak)
"""
import pytest
from sqlalchemy.ext.asyncio import AsyncSession
from models.visit_model import Visit
from models.assessment_model import Assessment
from models.checklist_model import Checklist
from models.photo_model import Photo
from services.pdf_service import PDFService
PDF_MAGIC = b"%PDF"
# Standard 21-item assessment template (categories A-E)
GS_ITEMS = [
("A", 1, "Welcoming Kasir (Senyum, Sapa, Salam)", 4.0, "4"),
("A", 2, "Upselling & Cross-selling Menu", 3.0, "3"),
("A", 3, "Konfirmasi pesanan dan penyebutan total harga", 5.0, "5"),
("A", 4, "Waktu penyajian pesanan sesuai standar", 4.0, "4"),
("A", 5, "Ucapan terima kasih dan salam penutup", 4.0, "4"),
("B", 1, "Suhu minuman sesuai standar", 4.0, "4"),
("B", 2, "Rasa minuman sesuai standar", 3.0, "3"),
("B", 3, "Presentasi / tampilan minuman", 5.0, "5"),
("B", 4, "Suhu makanan sesuai standar", 4.0, "4"),
("B", 5, "Rasa dan tampilan makanan", 4.0, "4"),
("C", 1, "Kebersihan meja dan kursi", 4.0, "4"),
("C", 2, "Kebersihan lantai", 3.0, "3"),
("C", 3, "Kebersihan dan kelengkapan toilet", 2.0, "2"),
("C", 4, "Kebersihan area outdoor/teras", 4.0, "4"),
("D", 1, "Kasir memberikan struk belanja", 1.0, "Ya"),
("D", 2, "Staf menggunakan seragam lengkap", 0.0, "Tidak"),
("E", 1, "Kenyamanan suhu ruangan / AC", 4.0, "4"),
("E", 2, "Background music tidak terlalu keras", 5.0, "5"),
("E", 3, "Pencahayaan ruangan memadai", 4.0, "4"),
("E", 4, "Aroma ruangan nyaman", 3.0, "3"),
("E", 5, "Kesan keseluruhan pengalaman", 4.0, "4"),
]
@pytest.mark.asyncio
class TestPDFWithAssessments:
async def _seed_assessments(self, session: AsyncSession, visit: Visit):
"""Populate a visit with the full 21-item GS assessment."""
for cat, item_no, criteria, score, raw in GS_ITEMS:
session.add(Assessment(
visit_id=visit.id,
category=cat,
item_no=item_no,
criteria=criteria,
score=score,
raw_value=raw,
))
await session.flush()
async def test_pdf_with_assessments_is_valid(
self, async_session: AsyncSession, sample_visit: Visit,
):
"""PDF with assessments should start with PDF magic."""
await self._seed_assessments(async_session, sample_visit)
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
async def test_pdf_with_seeded_assessments(
self, async_session: AsyncSession, sample_visit: Visit,
):
"""PDF after seeding 21 assessment items should still be valid."""
await self._seed_assessments(async_session, sample_visit)
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
assert len(result) > 1024 # Must be at least 1KB
async def test_pdf_with_gs_fields_valid(
self, async_session: AsyncSession, sample_visit: Visit,
):
"""Visit with ghost_shopper and visit_type should produce valid PDF."""
# sample_visit already has ghost_shopper="Auditor Test" and visit_type="dine_in"
await self._seed_assessments(async_session, sample_visit)
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
assert len(result) > 3000 # Rich content
async def test_pdf_full_report_with_all_data(
self, async_session: AsyncSession, sample_visit: Visit,
):
"""Full report: assessments + checklists + photos."""
await self._seed_assessments(async_session, sample_visit)
# Add checklists
for i, checked in enumerate([True, True, False]):
async_session.add(Checklist(
visit_id=sample_visit.id,
item_name=f"SOP Check {i+1}",
is_checked=checked,
))
# Add photos
for j in range(2):
async_session.add(Photo(
visit_id=sample_visit.id,
file_path=f"/uploads/evidence_{j}.jpg",
file_name=f"evidence_{j}.jpg",
file_size=51200,
mime_type="image/jpeg",
))
await async_session.flush()
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
assert len(result) > 5000 # Full report should be substantial
async def test_pdf_single_assessment_item(
self, async_session: AsyncSession, sample_visit: Visit,
sample_assessment: Assessment,
):
"""PDF with just one assessment item should still be valid."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC