The CEO dashboard requested /api/tickets?page_size=500, but the API caps page_size at 200 (le=200 in app/routers/tickets.py), so the request returned 422 and every KPI/chart rendered zeros. - ceo.html: fetch all tickets by looping pages of page_size=200 until total items are collected (with a safety bound), keeping KPIs accurate as volume grows past 200. - tests: add test suite anchoring the pagination contract — page_size=500 returns 422, page_size=200 returns items/total/page/page_size, and a page loop collects every ticket without duplicates. - pyproject: enable pytest-asyncio auto mode and tests/ discovery. - .gitignore: un-ignore committed tests/test_*.py.
57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
"""Tests anchoring ticket list pagination behavior.
|
|
|
|
The CEO dashboard (app/templates/dashboard/ceo.html) previously requested
|
|
`page_size=500`; the API caps page_size at 200 (`le=200` in
|
|
app/routers/tickets.py), so that request returned 422 and the dashboard
|
|
rendered empty KPIs. These tests pin the API contract the frontend now
|
|
relies on: page_size=200 + page loops that collect every ticket.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
async def test_page_size_over_cap_returns_422(client):
|
|
"""Requests above the page_size cap must be rejected (the original bug)."""
|
|
resp = await client.get("/api/tickets", params={"page_size": 500})
|
|
assert resp.status_code == 422
|
|
|
|
|
|
async def test_page_size_at_cap_returns_items_and_total(client, seed_tickets):
|
|
"""page_size=200 is the max legal value and returns the full response shape."""
|
|
await seed_tickets(14)
|
|
resp = await client.get("/api/tickets", params={"page": 1, "page_size": 200})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["total"] == 14
|
|
assert len(data["items"]) == 14
|
|
assert data["page"] == 1
|
|
assert data["page_size"] == 200
|
|
|
|
|
|
async def test_paginated_loop_collects_all_tickets(client, seed_tickets):
|
|
"""The frontend's page loop (page_size=200 until total reached) collects every ticket."""
|
|
total_seeded = await seed_tickets(450) # 3 pages of 200
|
|
|
|
collected: list[dict] = []
|
|
total = float("inf")
|
|
page = 1
|
|
page_size = 200
|
|
while len(collected) < total and page <= 1000:
|
|
resp = await client.get("/api/tickets", params={"page": page, "page_size": page_size})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["items"], "expected a non-empty page"
|
|
collected.extend(data["items"])
|
|
total = data["total"] or len(collected)
|
|
page += 1
|
|
|
|
assert total == total_seeded
|
|
assert len(collected) == total_seeded
|
|
# No duplicate tickets across pages
|
|
ids = [t["id"] for t in collected]
|
|
assert len(set(ids)) == len(ids)
|