Files
canteen-asset-tracker/tests/frontend/test_assets.py
T

145 lines
5.0 KiB
Python

"""Frontend E2E tests — asset list, search, filter, detail."""
import pytest
import requests
def _login(page):
"""Helper: login as admin."""
page.locator("#loginUsername").fill("admin")
page.locator("#loginPassword").fill("changeme")
page.locator("button:has-text('Sign In')").click()
page.wait_for_selector("#loginOverlay", state="hidden", timeout=5000)
@pytest.mark.frontend
def test_asset_list_shows_created_asset(page, live_server):
"""Assets created via API appear in the Assets tab."""
_login(page)
# Create an asset via API
resp = requests.post(
f"{live_server}/api/assets",
json={
"machine_id": "TEST-001",
"name": "Test Espresso Machine",
"category": "Appliances",
"status": "active",
},
)
assert resp.status_code == 201
# Navigate to Assets tab
page.locator(".tab-btn[data-tab='tabAssets']").click()
page.wait_for_selector("#tabAssets.active", timeout=3000)
# Wait for the asset list to render
page.wait_for_selector(".asset-item", timeout=5000)
assert page.locator(".asset-item").count() >= 1
assert page.locator(".ai-name:has-text('Test Espresso Machine')").is_visible()
@pytest.mark.frontend
def test_asset_list_empty_state(page, live_server):
"""Assets tab shows empty state when no assets exist."""
_login(page)
page.locator(".tab-btn[data-tab='tabAssets']").click()
page.wait_for_selector("#tabAssets.active", timeout=3000)
# Should show empty state (no assets seeded into fresh DB).
# loadAssets() runs async — give it time to fetch and render.
page.wait_for_timeout(2000)
has_empty = page.locator(".empty-state").count() > 0
has_items = page.locator(".asset-item").count() > 0
assert not has_items, f"Fresh DB has {page.locator('.asset-item').count()} assets unexpectedly"
assert has_empty, "Empty state should appear on fresh DB"
@pytest.mark.frontend
def test_asset_search_filters_by_name(page, live_server):
"""Search input filters assets by name."""
_login(page)
# Create two assets via API
for mid, name in [("SRCH-001", "Alpha Blender"), ("SRCH-002", "Beta Oven")]:
requests.post(
f"{live_server}/api/assets",
json={"machine_id": mid, "name": name, "category": "Appliances"},
)
# Navigate to Assets
page.locator(".tab-btn[data-tab='tabAssets']").click()
page.wait_for_selector("#tabAssets.active", timeout=3000)
page.wait_for_selector(".asset-item", timeout=5000)
# Search for "Alpha" — use #assetSearch to avoid ambiguity with
# customer and activity search inputs that share the .input-field class.
page.locator("#assetSearch").fill("Alpha")
page.wait_for_timeout(500) # debounce
items = page.locator(".asset-item")
assert items.count() == 1
assert page.locator(".ai-name:has-text('Alpha Blender')").is_visible()
@pytest.mark.frontend
def test_asset_category_filter(page, live_server):
"""Category filter pills filter assets."""
_login(page)
# Create assets in different categories
requests.post(
f"{live_server}/api/assets",
json={"machine_id": "FILT-001", "name": "Chair", "category": "Furniture"},
)
requests.post(
f"{live_server}/api/assets",
json={"machine_id": "FILT-002", "name": "Fridge", "category": "Appliances"},
)
# Navigate to Assets
page.locator(".tab-btn[data-tab='tabAssets']").click()
page.wait_for_selector("#tabAssets.active", timeout=3000)
page.wait_for_selector(".asset-item", timeout=5000)
# wait_for_selector returns on first match — give the list time to fully render
page.wait_for_timeout(500)
assert page.locator(".asset-item").count() == 2
# Click "Furniture" filter pill
page.locator(".pill:has-text('Furniture')").click()
page.wait_for_timeout(300)
assert page.locator(".asset-item").count() == 1
assert page.locator(".ai-name:has-text('Chair')").is_visible()
@pytest.mark.frontend
def test_asset_detail_view(page, live_server):
"""Clicking an asset opens detail panel with correct info."""
_login(page)
requests.post(
f"{live_server}/api/assets",
json={
"machine_id": "DETAIL-001",
"name": "Detail Test Asset",
"description": "A test asset for detail view",
"category": "Equipment",
"status": "active",
},
)
page.locator(".tab-btn[data-tab='tabAssets']").click()
page.wait_for_selector("#tabAssets.active", timeout=3000)
page.wait_for_selector(".asset-item", timeout=5000)
# Click the asset — viewAsset() calls showDetailView(), which
# makes #assetsDetailView visible (not .scan-result — that's for
# barcode scans).
page.locator(".ai-name:has-text('Detail Test Asset')").click()
page.wait_for_selector("#assetsDetailView", state="visible", timeout=5000)
# Verify detail content
assert page.locator("#detailName:has-text('Detail Test Asset')").is_visible()