"""Exercise real pointer/click dispatch on the complete console in Chromium.""" from __future__ import annotations import os import shutil import subprocess import threading from http import HTTPStatus from http.server import ThreadingHTTPServer from pathlib import Path from unittest.mock import patch from urllib.parse import urlparse import pytest from cognitive_agent.application.seat_service import SeatDemoService from cognitive_agent.auth import AuthConfig, AuthRuntime from cognitive_agent.server import REPOSITORY_ROOT, SeatDemoHandler def test_mode_rail_real_browser_interactions(tmp_path: Path) -> None: node = shutil.which("node") if not node: pytest.skip("Node.js is required for the browser interaction regression") env = dict(os.environ) bundled_modules = Path(node).resolve().parent.parent / "node_modules" if bundled_modules.is_dir(): env["NODE_PATH"] = os.pathsep.join( item for item in (str(bundled_modules), env.get("NODE_PATH")) if item ) available = subprocess.run( [node, "-e", "require.resolve('playwright')"], env=env, capture_output=True, encoding="utf-8", check=False, ) if available.returncode: pytest.skip("Playwright is required for the real browser regression") with patch.dict( os.environ, { "COGNITIVE_AGENT_HARDWARE_EXECUTION_ENABLED": "false", "COGNITIVE_AGENT_VEHICLE_CAN_ENABLED": "false", "COGNITIVE_AGENT_WIRED_PASSENGER_CAN_ENABLED": "false", "COGNITIVE_AGENT_VEHICLE_MQTT_ENABLED": "false", }, ): service = SeatDemoService(REPOSITORY_ROOT) service.artifact_root = tmp_path / "artifacts" class BrowserHandler(SeatDemoHandler): auth = AuthRuntime(AuthConfig(False, "", "", b"", 3600, 5, 300, 120, False)) def do_GET(self) -> None: if urlparse(self.path).path in {"/api/hardware/seat-state", "/api/hardware/vehicle-state"}: self._json({"status": "unavailable", "hardware_execution_allowed": False}) return super().do_GET() def do_POST(self) -> None: # Only GET reaches this test server. Browser requests to the # assistant are intercepted; unexpected writes fail closed. self._json({"error": "browser_test_write_forbidden"}, HTTPStatus.FORBIDDEN) def log_message(self, *_args: object) -> None: pass BrowserHandler.service = service server = ThreadingHTTPServer(("127.0.0.1", 0), BrowserHandler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: completed = subprocess.run( [ node, str(Path(__file__).with_name("mode_rail_browser.cjs")), f"http://127.0.0.1:{server.server_port}", str(tmp_path), ], env=env, capture_output=True, encoding="utf-8", timeout=120, check=False, ) assert completed.returncode == 0, completed.stdout + completed.stderr finally: server.shutdown() server.server_close() thread.join(timeout=3) service.close()