# -*- coding: utf-8 -*- """Unit tests for template integration with _base.html. Verifies that all templates properly extend _base.html and include required core JavaScript resources. """ import unittest import os from unittest.mock import patch from mes_dashboard.app import create_app import mes_dashboard.core.database as db def _login_as_admin(client): with client.session_transaction() as sess: sess['admin'] = {'displayName': 'Test Admin', 'employeeNo': 'A001'} def _get_response_and_html(client, endpoint): response = client.get(endpoint, follow_redirects=False) if response.status_code in {301, 302, 307, 308}: follow = client.get(response.location) return response, follow, follow.data.decode('utf-8') return response, response, response.data.decode('utf-8') class TestTemplateIntegration(unittest.TestCase): """Test that all templates properly extend _base.html.""" def setUp(self): self._old_portal_spa = os.environ.get("PORTAL_SPA_ENABLED") os.environ["PORTAL_SPA_ENABLED"] = "false" db._ENGINE = None self.app = create_app('testing') self.app.config['TESTING'] = True self.client = self.app.test_client() _login_as_admin(self.client) def tearDown(self): if self._old_portal_spa is None: os.environ.pop("PORTAL_SPA_ENABLED", None) else: os.environ["PORTAL_SPA_ENABLED"] = self._old_portal_spa def test_portal_includes_base_scripts(self): response = self.client.get('/') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('toast.js', html) self.assertIn('mes-api.js', html) self.assertIn('mes-toast-container', html) def test_wip_overview_serves_pure_vite_module(self): response = self.client.get('/wip-overview') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('/static/dist/wip-overview.js', html) self.assertIn('type="module"', html) self.assertNotIn('mes-toast-container', html) def test_wip_detail_serves_pure_vite_module(self): response = self.client.get('/wip-detail') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('/static/dist/wip-detail.js', html) self.assertIn('type="module"', html) self.assertNotIn('mes-toast-container', html) def test_hold_overview_serves_pure_vite_module(self): response = self.client.get('/hold-overview') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('/static/dist/hold-overview.js', html) self.assertIn('type="module"', html) self.assertNotIn('mes-toast-container', html) def test_tables_page_serves_pure_vite_module(self): response = self.client.get('/tables') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('/static/dist/tables.js', html) self.assertIn('type="module"', html) self.assertNotIn('mes-toast-container', html) def test_resource_page_serves_pure_vite_module(self): response = self.client.get('/resource') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('/static/dist/resource-status.js', html) self.assertIn('type="module"', html) self.assertNotIn('mes-toast-container', html) def test_excel_query_page_includes_base_scripts(self): response = self.client.get('/excel-query') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('toast.js', html) self.assertIn('mes-api.js', html) self.assertIn('mes-toast-container', html) def test_query_tool_page_includes_base_scripts(self): response = self.client.get('/query-tool') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('toast.js', html) self.assertIn('mes-api.js', html) self.assertIn('mes-toast-container', html) def test_tmtt_defect_page_includes_base_scripts(self): response = self.client.get('/tmtt-defect') self.assertEqual(response.status_code, 200) html = response.data.decode('utf-8') self.assertIn('toast.js', html) self.assertIn('mes-api.js', html) self.assertIn('mes-toast-container', html) class TestPortalDynamicDrawerRendering(unittest.TestCase): """Test dynamic portal drawer rendering.""" def setUp(self): self._old_portal_spa = os.environ.get("PORTAL_SPA_ENABLED") os.environ["PORTAL_SPA_ENABLED"] = "false" db._ENGINE = None self.app = create_app('testing') self.app.config['TESTING'] = True self.client = self.app.test_client() _login_as_admin(self.client) def tearDown(self): if self._old_portal_spa is None: os.environ.pop("PORTAL_SPA_ENABLED", None) else: os.environ["PORTAL_SPA_ENABLED"] = self._old_portal_spa def test_portal_uses_navigation_config_for_sidebar_links_without_iframe(self): drawers = [ { "id": "custom", "name": "自訂分類", "order": 1, "admin_only": False, "pages": [ { "route": "/wip-overview", "name": "自訂首頁", "status": "released", "order": 1, } ], }, { "id": "dev-tools", "name": "開發工具", "order": 2, "admin_only": True, "pages": [ { "route": "/admin/pages", "name": "頁面管理", "status": "dev", "order": 1, } ], }, ] with patch("mes_dashboard.app.get_navigation_config", return_value=drawers): response = self.client.get("/") self.assertEqual(response.status_code, 200) html = response.data.decode("utf-8") self.assertIn("自訂分類", html) self.assertIn('href="/wip-overview"', html) self.assertIn('data-route="/wip-overview"', html) self.assertIn('href="/admin/pages"', html) self.assertIn('data-route="/admin/pages"', html) self.assertNotIn("