from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[4] SETTINGS_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/settings.js" ROUTER_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/router.js" INDEX_PATH = REPO_ROOT / "starpilot/system/the_galaxy/templates/index.html" BLUETOOTH_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/tools/bluetooth.js" CONTROLLERS_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/tools/wheel_controls.js" MOBILE_CONTROLLERS_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/mobile/js/components/WheelControls.js" SIDEBAR_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/sidebar.js" MODEL_LAB_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/tools/model_laboratory.js" def test_settings_does_not_create_a_second_router_module(): source = SETTINGS_PATH.read_text(encoding="utf-8") assert "/assets/components/router.js" not in source assert "window.__theGalaxyNavigate" in source def test_router_and_settings_cache_bust_is_consistent(): router = ROUTER_PATH.read_text(encoding="utf-8") index = INDEX_PATH.read_text(encoding="utf-8") assert "/assets/components/settings.js?v=router-cycle-fix-5" in router assert "/assets/components/router.js?v=router-cycle-fix-8" in index assert "/assets/components/sidebar.js?v=sidebar-pin-2" in router assert "/assets/components/main.css?v=sidebar-pin-2" in index assert "/assets/components/sidebar.css?v=sidebar-pin-2" in index def test_bluetooth_actions_use_reactive_disabled_bindings(): source = BLUETOOTH_PATH.read_text(encoding="utf-8") assert 'disabled="${pairingDisabled}"' not in source assert 'disabled="${disabled}"' not in source assert 'disabled="${() => !state.offroad || !!state.busy}"' in source assert "bluetoothAddress" not in source assert 'address: audioSelected() ? "" : device.address' in source assert 'audioSelected() ? "Stop Using for Audio" : "Use for Audio"' in source assert 'request("test_audio", { address: device.address })' in source assert "startAudioTestCountdown" in source assert "The test sound is sent at NOW" in source assert 'renderDeviceSection("My Devices"' in source assert 'renderDeviceSection("Available Devices"' in source assert "bluetoothForgetButton" in source assert "bi-trash3" in source assert "state.pairingAddress" in source assert "state.busy !== \"power\"" in source assert "Turning Bluetooth" in source assert "!device.paired" in source assert 'galaxyPath("/bluetooth")' in source assert 'window.location.pathname === "/bluetooth"' not in source assert "schedulePoll(250)" in source assert "while (refreshRequested)" in source assert 'cache: "no-store"' in source assert "const ACTIVE_POLL_INTERVAL_MS = 250" in source assert "document.visibilityState !== \"hidden\"" in source assert "window.addEventListener(\"pageshow\", refresh)" in source assert 'state.revision)' in source assert "const revisionAttribute" in source assert 'data-revision="${revision}"' in source assert 'bluetooth-live-15' in ROUTER_PATH.read_text(encoding="utf-8") def test_controller_test_mode_has_explicit_start_and_stop(): source = CONTROLLERS_PATH.read_text(encoding="utf-8") assert 'state.testing ? "test-stop" : "test"' in source assert 'state.lastTested.mapped ? "Successful" : "Not mapped"' in source assert "Controller inputs are temporarily consumed" in source def test_controller_joystick_mode_requires_explicit_device_selection(): source = CONTROLLERS_PATH.read_text(encoding="utf-8") assert "Favorite buttons are the default" in source assert "Enable for Joystick Mode" in source assert 'request("joystick", { device_id: device.device_id, enabled: !selected() })' in source def test_controller_offroad_disconnect_is_opt_in(): source = CONTROLLERS_PATH.read_text(encoding="utf-8") mobile_source = MOBILE_CONTROLLERS_PATH.read_text(encoding="utf-8") for frontend in (source, mobile_source): assert "Disconnect controllers when offroad" in frontend assert "After two minutes offroad" in frontend assert "offroad-disconnect" in frontend def test_controller_page_has_ten_controller_only_action_slots(): source = CONTROLLERS_PATH.read_text(encoding="utf-8") assert "Controller-only Actions" in source assert "These never appear as on-screen Favorites" in source assert 'request("action", { slot: index, key, value })' in source assert "const targetIndex = 3 + index" in source assert "state.controllerSlots.map(controllerSlotCard)" in source assert "Set speed (${() => state.speedUnit})" in source assert "Galaxy → Sentry Mode" in source def test_bluetooth_and_controllers_sidebar_order(): source = SIDEBAR_PATH.read_text(encoding="utf-8") toggles = source.index('{ name: "Toggles"') bluetooth = source.index('{ name: "Bluetooth"') sentry = source.index('{ name: "Sentry Mode"') controllers = source.index('{ name: "Controllers"') assert toggles < bluetooth < sentry < controllers def test_sidebar_pin_state_and_responsive_drawer_are_wired(): sidebar = SIDEBAR_PATH.read_text(encoding="utf-8") template = INDEX_PATH.read_text(encoding="utf-8") sidebar_css = (REPO_ROOT / "starpilot/system/the_galaxy/assets/components/sidebar.css").read_text(encoding="utf-8") main_css = (REPO_ROOT / "starpilot/system/the_galaxy/assets/components/main.css").read_text(encoding="utf-8") navigation_css = (REPO_ROOT / "starpilot/system/the_galaxy/assets/components/navigation/navigation_destination.css").read_text(encoding="utf-8") assert 'window.localStorage?.getItem(SIDEBAR_PINNED_KEY)' in sidebar assert 'stored === "true"' in sidebar and 'defaultSidebarPinned' in sidebar assert "try {" in sidebar assert 'menuButton.dataset.boundClick !== "1"' in sidebar assert 'class="sidebar-pin-button"' in sidebar assert '