feat(modernization): promote deferred routes to in-scope and unify page header styles
Promote /tables, /excel-query, /query-tool, /mid-section-defect from deferred to full shell-governed in-scope routes with canonical redirects, content contracts, governance artifacts, and updated CI gates. Unify all page header gradients to #667eea → #764ba2 and h1 font-size to 24px for visual consistency across all dashboard pages. Remove Native Route-View dev annotations from job-query, excel-query, and query-tool headers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,12 +89,17 @@ class TestFullLoginLogoutFlow:
|
||||
def test_complete_admin_login_workflow(self, mock_auth, _mock_is_admin, client):
|
||||
"""Test complete admin login workflow."""
|
||||
mock_auth.return_value = _mock_admin_user()
|
||||
|
||||
# 1. Access portal - should see login link
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode("utf-8")
|
||||
assert "管理員登入" in content
|
||||
spa_enabled = bool(client.application.config.get("PORTAL_SPA_ENABLED", False))
|
||||
|
||||
# 1. Access portal entry.
|
||||
response = client.get("/", follow_redirects=False)
|
||||
if spa_enabled:
|
||||
assert response.status_code == 302
|
||||
assert response.location.rstrip("/").endswith("/portal-shell")
|
||||
else:
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode("utf-8")
|
||||
assert "管理員登入" in content
|
||||
|
||||
# 2. Go to login page
|
||||
response = client.get("/admin/login")
|
||||
@@ -106,15 +111,21 @@ class TestFullLoginLogoutFlow:
|
||||
"password": "password123"
|
||||
}, follow_redirects=True)
|
||||
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode("utf-8")
|
||||
# Should see admin name and logout option
|
||||
assert "Test Admin" in content or "登出" in content
|
||||
|
||||
# 4. Verify session has admin
|
||||
with client.session_transaction() as sess:
|
||||
assert "admin" in sess
|
||||
assert sess["admin"]["mail"] == "ymirliu@panjit.com.tw"
|
||||
assert response.status_code == 200
|
||||
if not spa_enabled:
|
||||
content = response.data.decode("utf-8")
|
||||
# Portal template should show admin identity in non-SPA mode.
|
||||
assert "Test Admin" in content or "登出" in content
|
||||
|
||||
# 4. Verify session has admin
|
||||
with client.session_transaction() as sess:
|
||||
assert "admin" in sess
|
||||
assert sess["admin"]["mail"] == "ymirliu@panjit.com.tw"
|
||||
|
||||
if spa_enabled:
|
||||
nav = client.get("/api/portal/navigation")
|
||||
assert nav.status_code == 200
|
||||
assert nav.get_json()["is_admin"] is True
|
||||
|
||||
# 5. Access admin pages
|
||||
response = client.get("/admin/pages")
|
||||
@@ -244,20 +255,22 @@ class TestPageManagementFlow:
|
||||
|
||||
|
||||
class TestPortalDynamicTabs:
|
||||
"""E2E tests for dynamic portal tabs based on page status."""
|
||||
|
||||
def test_portal_hides_dev_tabs_for_non_admin(self, client, temp_page_status):
|
||||
"""Test portal hides dev page tabs for non-admin users."""
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode("utf-8")
|
||||
|
||||
# Released pages should show
|
||||
assert "WIP 即時概況" in content
|
||||
|
||||
# Dev pages should NOT show (tables and resource are dev)
|
||||
# Note: This depends on the can_view_page implementation in portal.html
|
||||
|
||||
"""E2E tests for dynamic portal tabs based on page status."""
|
||||
|
||||
def test_portal_hides_dev_tabs_for_non_admin(self, client, temp_page_status):
|
||||
"""Test portal hides dev page tabs for non-admin users."""
|
||||
response = client.get("/api/portal/navigation")
|
||||
assert response.status_code == 200
|
||||
payload = response.get_json()
|
||||
routes = {
|
||||
page["route"]
|
||||
for drawer in payload.get("drawers", [])
|
||||
for page in drawer.get("pages", [])
|
||||
}
|
||||
assert "/wip-overview" in routes
|
||||
assert "/tables" not in routes
|
||||
assert payload.get("is_admin") is False
|
||||
|
||||
@patch('mes_dashboard.routes.auth_routes.is_admin', return_value=True)
|
||||
@patch('mes_dashboard.routes.auth_routes.authenticate')
|
||||
def test_portal_shows_all_tabs_for_admin(self, mock_auth, _mock_is_admin, client, temp_page_status):
|
||||
@@ -270,12 +283,17 @@ class TestPortalDynamicTabs:
|
||||
"password": "password123"
|
||||
})
|
||||
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode("utf-8")
|
||||
|
||||
# Admin should see all pages
|
||||
assert "WIP 即時概況" in content
|
||||
response = client.get("/api/portal/navigation")
|
||||
assert response.status_code == 200
|
||||
payload = response.get_json()
|
||||
routes = {
|
||||
page["route"]
|
||||
for drawer in payload.get("drawers", [])
|
||||
for page in drawer.get("pages", [])
|
||||
}
|
||||
assert "/wip-overview" in routes
|
||||
assert "/tables" in routes
|
||||
assert payload.get("is_admin") is True
|
||||
|
||||
|
||||
class TestSessionPersistence:
|
||||
|
||||
@@ -37,27 +37,44 @@ def client(app):
|
||||
class TestResourceHistoryPageAccess:
|
||||
"""E2E tests for page access and navigation."""
|
||||
|
||||
@staticmethod
|
||||
def _load_resource_history_entry(client):
|
||||
spa_enabled = bool(client.application.config.get("PORTAL_SPA_ENABLED", False))
|
||||
response = client.get('/resource-history', follow_redirects=False)
|
||||
if spa_enabled:
|
||||
assert response.status_code == 302
|
||||
assert response.location.endswith('/portal-shell/resource-history')
|
||||
shell_response = client.get('/portal-shell/resource-history')
|
||||
assert shell_response.status_code == 200
|
||||
return shell_response, True
|
||||
return response, False
|
||||
|
||||
def test_page_loads_successfully(self, client):
|
||||
"""Resource history page should load without errors."""
|
||||
response = client.get('/resource-history')
|
||||
|
||||
response, spa_enabled = self._load_resource_history_entry(client)
|
||||
assert response.status_code == 200
|
||||
content = response.data.decode('utf-8')
|
||||
assert '設備歷史績效' in content
|
||||
if spa_enabled:
|
||||
assert '/static/dist/portal-shell.js' in content
|
||||
else:
|
||||
assert '設備歷史績效' in content
|
||||
|
||||
def test_page_bootstrap_container_exists(self, client):
|
||||
"""Resource history page should expose the Vue mount container."""
|
||||
response = client.get('/resource-history')
|
||||
response, _spa_enabled = self._load_resource_history_entry(client)
|
||||
content = response.data.decode('utf-8')
|
||||
|
||||
assert "id='app'" in content or 'id="app"' in content
|
||||
|
||||
def test_page_references_vite_module(self, client):
|
||||
"""Resource history page should load the Vite module bundle."""
|
||||
response = client.get('/resource-history')
|
||||
response, spa_enabled = self._load_resource_history_entry(client)
|
||||
content = response.data.decode('utf-8')
|
||||
|
||||
assert '/static/dist/resource-history.js' in content
|
||||
if spa_enabled:
|
||||
assert '/static/dist/portal-shell.js' in content
|
||||
else:
|
||||
assert '/static/dist/resource-history.js' in content
|
||||
assert 'type="module"' in content
|
||||
|
||||
|
||||
@@ -329,16 +346,28 @@ class TestResourceHistoryValidation:
|
||||
assert response.status_code == 200, f"Failed for granularity={granularity}"
|
||||
|
||||
|
||||
class TestResourceHistoryNavigation:
|
||||
"""E2E tests for navigation integration."""
|
||||
|
||||
def test_portal_includes_history_tab(self, client):
|
||||
"""Portal should include resource history tab."""
|
||||
response = client.get('/')
|
||||
content = response.data.decode('utf-8')
|
||||
|
||||
assert '設備歷史績效' in content
|
||||
assert 'resourceHistoryFrame' in content
|
||||
class TestResourceHistoryNavigation:
|
||||
"""E2E tests for navigation integration."""
|
||||
|
||||
def test_portal_includes_history_tab(self, client):
|
||||
"""Portal should include resource history tab."""
|
||||
if bool(client.application.config.get("PORTAL_SPA_ENABLED", False)):
|
||||
response = client.get('/api/portal/navigation')
|
||||
assert response.status_code == 200
|
||||
payload = response.get_json()
|
||||
pages = [
|
||||
page
|
||||
for drawer in payload.get("drawers", [])
|
||||
for page in drawer.get("pages", [])
|
||||
]
|
||||
history_pages = [page for page in pages if page.get("route") == "/resource-history"]
|
||||
assert history_pages, "resource-history route missing from portal navigation contract"
|
||||
assert history_pages[0].get("name") == "設備歷史績效"
|
||||
else:
|
||||
response = client.get('/')
|
||||
content = response.data.decode('utf-8')
|
||||
assert '設備歷史績效' in content
|
||||
assert 'resourceHistoryFrame' in content
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user