Files
beanflows/web/tests/test_dashboard.py
Deeman d09ba91023 Remove password admin login, seed dev accounts, add regression tests
Admin flow:
- Remove /admin/login (password-based) and /admin/dev-login routes entirely
- admin_required now checks only the 'admin' role; redirects to auth.login
- auth/dev-login with an ADMIN_EMAILS address redirects directly to /admin/
- .env.example: replace ADMIN_PASSWORD with ADMIN_EMAILS=admin@beanflows.coffee

Dev seeding:
- Add dev_seed.py: idempotent upsert of 4 fixed accounts (admin, free,
  starter, pro) so every access tier is testable after dev_run.sh
- dev_run.sh: seed after migrations, show all 4 login shortcuts

Regression tests (37 passing):
- test_analytics.py: concurrent fetch_analytics calls return correct row
  counts (cursor thread-safety regression), column names are lowercase
- test_roles.py TestAdminAuthFlow: password login routes return 404,
  admin_required redirects to auth.login, dev-login grants admin role
  and redirects to admin panel when email is in ADMIN_EMAILS
- conftest.py: add mock_analytics fixture (fixes 7 pre-existing dashboard
  test errors); fix assertion text and lowercase metric param in tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 20:10:45 +01:00

80 lines
2.6 KiB
Python

"""
Tests for the coffee analytics dashboard.
"""
import pytest
@pytest.mark.asyncio
async def test_dashboard_requires_login(client):
"""Dashboard redirects unauthenticated users."""
response = await client.get("/dashboard/")
assert response.status_code == 302
@pytest.mark.asyncio
async def test_dashboard_loads(auth_client, mock_analytics):
"""Dashboard renders with chart data for authenticated user."""
response = await auth_client.get("/dashboard/")
assert response.status_code == 200
body = (await response.get_data(as_text=True))
assert "Coffee Dashboard" in body
assert "Global Supply" in body
assert "Stock-to-Use" in body
assert "Top Producing Countries" in body
@pytest.mark.asyncio
async def test_dashboard_shows_metric_cards(auth_client, mock_analytics):
"""Dashboard shows key metric values from latest data."""
response = await auth_client.get("/dashboard/")
body = (await response.get_data(as_text=True))
# Latest production from mock: 172,000
assert "172,000" in body
@pytest.mark.asyncio
async def test_dashboard_yoy_table(auth_client, mock_analytics):
"""Dashboard renders YoY production change table."""
response = await auth_client.get("/dashboard/")
body = (await response.get_data(as_text=True))
assert "Brazil" in body
assert "Vietnam" in body
@pytest.mark.asyncio
async def test_dashboard_free_plan_limits_history(auth_client, mock_analytics):
"""Free plan should show limited history notice."""
response = await auth_client.get("/dashboard/")
body = (await response.get_data(as_text=True))
assert "Upgrade" in body
@pytest.mark.asyncio
async def test_dashboard_free_plan_no_csv_export(auth_client, mock_analytics):
"""Free plan should not show CSV export button."""
response = await auth_client.get("/dashboard/")
body = (await response.get_data(as_text=True))
assert "CSV export available on Trader" in body
@pytest.mark.asyncio
async def test_countries_page_loads(auth_client, mock_analytics):
"""Country comparison page loads."""
response = await auth_client.get("/dashboard/countries")
assert response.status_code == 200
body = (await response.get_data(as_text=True))
assert "Country Comparison" in body
@pytest.mark.asyncio
async def test_countries_page_with_selection(auth_client, mock_analytics):
"""Country comparison with country params."""
response = await auth_client.get("/dashboard/countries?country=BR&country=VN&metric=production")
assert response.status_code == 200