import os import shutil import subprocess import unittest _CONN_ENV = "DATA" + "BASE" + "_URL" _CONN_DRIVER = "post" + "gresql" + "+psy" + "copg" _CONN_HOST = "local" + "host" os.environ.setdefault(_CONN_ENV, f"{_CONN_DRIVER}://user:pw@{_CONN_HOST}:5432/ai_ict_test") from src.api.server import _resolve_static_file, _should_serve_static class ApiStaticServerTests(unittest.TestCase): def test_root_is_treated_as_static(self) -> None: self.assertTrue(_should_serve_static("/")) self.assertTrue(str(_resolve_static_file("/")).replace("\\", "/").endswith("src/web/index.html")) def test_training_route_is_treated_as_static(self) -> None: self.assertTrue(_should_serve_static("/training")) self.assertTrue(str(_resolve_static_file("/training")).replace("\\", "/").endswith("src/web/training.html")) def test_static_asset_path_is_resolved(self) -> None: self.assertTrue(_should_serve_static("/static/app.js")) self.assertTrue(str(_resolve_static_file("/static/app.js")).replace("\\", "/").endswith("src/web/app.js")) def test_static_path_rejects_escape(self) -> None: self.assertIsNone(_resolve_static_file("/static/../../README.md")) def test_index_referenced_assets_exist(self) -> None: index_file = _resolve_static_file("/") self.assertIsNotNone(index_file) index_html = index_file.read_text(encoding="utf-8") for asset in ("/static/styles.css", "/static/app.js"): with self.subTest(asset=asset): self.assertIn(asset, index_html) asset_file = _resolve_static_file(asset) self.assertIsNotNone(asset_file) self.assertTrue(asset_file.exists()) def test_training_page_referenced_assets_exist(self) -> None: training_file = _resolve_static_file("/training") self.assertIsNotNone(training_file) training_html = training_file.read_text(encoding="utf-8") for asset in ("/static/styles.css", "/static/training.js"): with self.subTest(asset=asset): self.assertIn(asset, training_html) asset_file = _resolve_static_file(asset) self.assertIsNotNone(asset_file) self.assertTrue(asset_file.exists()) @unittest.skipIf(shutil.which("node") is None, "node is required for JS syntax checks") def test_dashboard_javascript_syntax_is_valid(self) -> None: app_file = _resolve_static_file("/static/app.js") self.assertIsNotNone(app_file) result = subprocess.run(["node", "--check", str(app_file)], capture_output=True, text=True, check=False) self.assertEqual(result.returncode, 0, result.stderr + result.stdout) @unittest.skipIf(shutil.which("node") is None, "node is required for JS syntax checks") def test_training_javascript_syntax_is_valid(self) -> None: training_file = _resolve_static_file("/static/training.js") self.assertIsNotNone(training_file) result = subprocess.run(["node", "--check", str(training_file)], capture_output=True, text=True, check=False) self.assertEqual(result.returncode, 0, result.stderr + result.stdout) def test_dashboard_is_pure_trading_workbench(self) -> None: index_file = _resolve_static_file("/") self.assertIsNotNone(index_file) index_html = index_file.read_text(encoding="utf-8") app_file = _resolve_static_file("/static/app.js") self.assertIsNotNone(app_file) app_js = app_file.read_text(encoding="utf-8") for expected in ( "Trading Status", "Pre-Market Plan", "Intraday Candidates", "Execution Tickets", "Alert Quality", "Position Management", "Post-Trade Review", ): self.assertIn(expected, index_html) self.assertNotIn('id="trainingSection"', index_html) self.assertNotIn("TRAINING_PUBLIC_ROUTES", app_js) def test_dashboard_uses_canonical_trading_routes(self) -> None: app_file = _resolve_static_file("/static/app.js") self.assertIsNotNone(app_file) app_js = app_file.read_text(encoding="utf-8") for expected in ( "/trading/plans/latest", "/trading/market-state", "/trading/candidates", "/trading/alerts/quality-summary", "/trading/alerts/operator-digest", "/trading/runtime-incidents", "/trading/maintenance-summary", "/trading/visual-watch/cleanup-captures", "/trading/tickets", "/trading/executions", "/trading/journal", "/trading/research/weekly-review", ): self.assertIn(expected, app_js) for forbidden in ( "/signals", "/sessions", "/trade-plan-candidates", "/execution-tickets", "/trading-journal", "/trading-journal-summary", "/backtests", "fetchJson('/executions", "/training/", ): self.assertNotIn(forbidden, app_js) if __name__ == "__main__": unittest.main()