Initial commit: Canteen Asset Geolocation Tool v2
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user