Files
DashBoard/tests/e2e/test_global_connection.py

174 lines
6.5 KiB
Python

# -*- coding: utf-8 -*-
"""E2E tests for SPA shell navigation/runtime contracts."""
import pytest
import re
from playwright.sync_api import Page, expect
def _sidebar_links(page: Page):
"""Support both legacy and current shell nav selectors."""
return page.locator("a.drawer-link[href], a.sidebar-item[data-route]")
def _fetch_json_status(page: Page, url: str):
"""Run fetch in browser context and return status/payload metadata."""
return page.evaluate(
"""
async (targetUrl) => {
const response = await fetch(targetUrl, { cache: 'no-store' });
let payload = null;
try {
payload = await response.json();
} catch (_) {
payload = null;
}
return { ok: response.ok, status: response.status, payload };
}
""",
url,
)
@pytest.mark.e2e
class TestPortalPage:
"""E2E tests for portal shell routing and drawer navigation."""
def test_portal_loads_successfully(self, page: Page, app_server: str):
page.goto(app_server)
expect(page.locator("h1")).to_contain_text("MES 報表入口")
def test_portal_has_sidebar_routes(self, page: Page, app_server: str):
page.goto(app_server)
expect(_sidebar_links(page).first).to_be_visible()
expect(page.locator(".drawer-link:has-text('WIP 即時概況')")).to_be_visible()
expect(page.locator(".drawer-link:has-text('設備即時概況')")).to_be_visible()
expect(page.locator(".drawer-link:has-text('設備歷史績效')")).to_be_visible()
expect(page.locator(".drawer-link:has-text('設備維修查詢')")).to_be_visible()
def test_portal_sidebar_navigation_uses_direct_routes(self, page: Page, app_server: str):
page.goto(app_server)
first_route = _sidebar_links(page).first
expect(first_route).to_be_visible()
target_href = first_route.get_attribute("href")
assert target_href, "sidebar route href missing"
first_route.click()
expect(page).to_have_url(re.compile(f".*{re.escape(target_href)}$"))
assert page.locator("iframe").count() == 0, "Shell content must not use iframe"
def test_portal_health_popup_clickable(self, page: Page, app_server: str):
page.goto(app_server)
trigger = page.locator(".health-trigger")
expect(trigger).to_be_visible()
expect(page.locator("#shellHealthPopup")).to_have_count(0)
trigger.click()
expect(page.locator("#shellHealthPopup")).to_be_visible()
page.keyboard.press("Escape")
expect(page.locator("#shellHealthPopup")).to_have_count(0)
@pytest.mark.e2e
class TestFrontendApiRuntime:
"""E2E tests for runtime API availability in browser context."""
def test_wip_overview_can_call_summary_api_via_fetch(self, page: Page, app_server: str):
page.goto(f"{app_server}/wip-overview")
result = _fetch_json_status(page, "/api/wip/overview/summary")
assert result["ok"] is True
assert result["status"] == 200
assert isinstance(result.get("payload"), dict)
def test_wip_detail_can_call_workcenter_api_via_fetch(self, page: Page, app_server: str):
page.goto(f"{app_server}/wip-detail")
result = _fetch_json_status(page, "/api/wip/meta/workcenters")
assert result["ok"] is True
assert result["status"] == 200
assert isinstance(result.get("payload"), dict)
def test_global_mesapi_bridge_is_optional(self, page: Page, app_server: str):
page.goto(f"{app_server}/wip-overview")
runtime = page.evaluate(
"""
() => ({
hasFetch: typeof window.fetch === 'function',
hasMesApi: typeof window.MesApi !== 'undefined',
hasMesApiGet: Boolean(window.MesApi && typeof window.MesApi.get === 'function'),
})
"""
)
assert runtime["hasFetch"] is True
if runtime["hasMesApi"]:
assert runtime["hasMesApiGet"] is True
@pytest.mark.e2e
class TestRoutePagesSmoke:
"""Basic smoke checks for key route pages."""
def test_wip_overview_loads(self, page: Page, app_server: str):
response = page.goto(f"{app_server}/wip-overview")
assert response is not None and response.ok
expect(page.locator("body")).to_be_visible()
def test_wip_detail_loads(self, page: Page, app_server: str):
response = page.goto(f"{app_server}/wip-detail")
assert response is not None and response.ok
expect(page.locator("body")).to_be_visible()
def test_resource_page_loads(self, page: Page, app_server: str):
response = page.goto(f"{app_server}/resource")
assert response is not None and response.ok
expect(page.locator("body")).to_be_visible()
def test_tables_page_loads(self, page: Page, app_server: str):
response = page.goto(f"{app_server}/tables")
assert response is not None
assert response.status in {200, 403}
expect(page.locator("body")).to_be_visible()
if response.status == 200:
header = page.locator("h1")
expect(header).to_be_visible()
text = header.inner_text()
assert "MES 數據表查詢工具" in text or "頁面開發中" in text
def test_excel_query_page_loads(self, page: Page, app_server: str):
response = page.goto(f"{app_server}/excel-query")
assert response is not None
assert response.status in {200, 403}
expect(page.locator("body")).to_be_visible()
@pytest.mark.e2e
class TestConsoleAndErrorSignals:
"""Console/pageerror checks for SPA runtime stability."""
def test_wip_overview_has_no_uncaught_page_errors(self, page: Page, app_server: str):
errors = []
page.on("pageerror", lambda error: errors.append(str(error)))
page.goto(f"{app_server}/wip-overview")
page.wait_for_timeout(2000)
assert errors == [], f"Unexpected page errors: {errors[:3]}"
def test_wip_overview_triggers_expected_api_requests(self, page: Page, app_server: str):
observed = set()
def on_response(resp):
if "/api/wip/overview/summary" in resp.url:
observed.add("summary")
if "/api/wip/overview/matrix" in resp.url:
observed.add("matrix")
page.on("response", on_response)
page.goto(f"{app_server}/wip-overview", wait_until="domcontentloaded")
page.wait_for_timeout(5000)
assert "summary" in observed
assert "matrix" in observed