from __future__ import annotations def test_native_ui_has_no_legacy_runtime_js_or_card_shell_tokens(reload_module): ui_layout = reload_module("ui_layout") assert ui_layout.SYNC_JS.strip() == "" css = ui_layout.CSS assert ".native-card" in css forbidden_tokens = [ "card-shell-hit", "card-shell-button", "floating-card", "applyCardShellOnce", "media_card_anchor", "action_selection_card_anchor", "next_task_btn_card_anchor", "MutationObserver", ] for token in forbidden_tokens: assert token not in css def test_native_ui_css_uses_configured_global_font_size_variables(reload_module): config = reload_module("config") ui_layout = reload_module("ui_layout") css = ui_layout.CSS assert f"--body-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--prose-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--input-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--block-label-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--button-large-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--section-header-text-size: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert f"--text-md: {config.UI_GLOBAL_FONT_SIZE} !important;" in css assert "#load_status_mode" not in css def test_native_ui_css_excludes_header_title_from_global_font_size(reload_module): ui_layout = reload_module("ui_layout") assert "#header_title h2" in ui_layout.CSS assert "font-size: var(--text-xxl) !important;" in ui_layout.CSS def test_native_ui_forces_light_theme_and_uses_light_overlay_baseline(reload_module): ui_layout = reload_module("ui_layout") css = ui_layout.CSS assert "color-scheme: light !important;" in css assert "#loading_overlay_group" not in css assert "body.dark," not in css assert ".dark," not in css assert ":root.dark" not in css assert "rgba(15, 23, 42, 0.92)" not in css assert "window.__robommeForceLightTheme = applyLightTheme;" in ui_layout.THEME_LOCK_HEAD assert 'store.setItem("gradio-theme", "light");' in ui_layout.THEME_LOCK_HEAD assert 'node.classList.remove("dark");' in ui_layout.THEME_LOCK_HEAD assert "window.__robommeForceLightTheme();" in ui_layout.THEME_LOCK_JS def test_native_ui_css_highlights_media_card_not_live_obs_transform(reload_module): ui_layout = reload_module("ui_layout") css = ui_layout.CSS assert "#media_card::after" in css assert "--media-card-radius: 8px;" in css assert "#media_card #live_obs button" in css assert "#media_card #live_obs img" in css assert "#media_card:has(#live_obs.live-obs-point-waiting)::after" in css assert "inset: 0;" in css assert "border-radius: inherit;" in css assert "animation: media-card-point-ring 1.2s ease-in-out infinite;" in css assert "@keyframes media-card-point-ring" in css assert "#live_obs.live-obs-point-waiting .image-frame" not in css assert "#live_obs.live-obs-point-waiting .upload-container" not in css assert "transform: scale(" not in css def test_extract_last_goal_prefers_last_list_item(reload_module): ui_layout = reload_module("ui_layout") assert ui_layout.extract_last_goal("['goal a', 'goal b']") == "goal b" def test_render_header_goal_capitalizes_display_value(reload_module): ui_layout = reload_module("ui_layout") assert ui_layout.render_header_goal("place cube on target") == "Place cube on target" assert ui_layout.render_header_goal("['goal a', 'goal b']") == "Goal b" assert ui_layout.render_header_goal("") == "—" def test_header_task_dropdown_uses_task_name_list_order(reload_module): config = reload_module("config") ui_layout = reload_module("ui_layout") ui_layout.user_manager.env_choices = list(config.TASK_NAME_LIST) demo = ui_layout.create_ui_blocks() try: cfg = demo.get_config_file() header_task_comp = next( comp for comp in cfg.get("components", []) if comp.get("props", {}).get("elem_id") == "header_task" ) choices = header_task_comp.get("props", {}).get("choices") or [] normalized_choices = [choice[0] if isinstance(choice, (list, tuple)) else choice for choice in choices] assert normalized_choices == config.TASK_NAME_LIST finally: demo.close() def test_native_ui_config_contains_phase_machine_and_precheck_chain(reload_module): ui_layout = reload_module("ui_layout") demo = ui_layout.create_ui_blocks() try: cfg = demo.get_config_file() assert cfg.get("theme") == "default" assert cfg.get("head") == ui_layout.THEME_LOCK_HEAD elem_ids = { comp.get("props", {}).get("elem_id") for comp in cfg.get("components", []) if comp.get("props", {}).get("elem_id") } required_ids = { "header_task", "main_layout_row", "media_card", "log_card", "right_top_row", "right_action_col", "right_log_col", "control_panel_group", "video_phase_group", "execution_video_group", "action_phase_group", "demo_video", "execute_video", "watch_demo_video_btn", "live_obs", "action_radio", "coords_box", "exec_btn", "reference_action_btn", "restart_episode_btn", "next_task_btn", } missing = required_ids - elem_ids assert not missing, f"missing required elem_ids: {sorted(missing)}" values = [ comp.get("props", {}).get("value") for comp in cfg.get("components", []) if "value" in comp.get("props", {}) ] assert all("_anchor" not in str(v) for v in values) assert all( "Logging in and setting up environment... Please wait." not in str(v) for v in values ) assert all("Loading environment, please wait..." not in str(v) for v in values) assert "The episode is loading..." in ui_layout.PROGRESS_TEXT_REWRITE_JS assert ui_layout.UI_TEXT["progress"]["entry_rejected"] == "Too many users are trying the demo right now. Please try again later." log_output_comp = next( comp for comp in cfg.get("components", []) if comp.get("props", {}).get("elem_id") == "log_output" ) assert log_output_comp.get("props", {}).get("max_lines") is None demo_video_comp = next( comp for comp in cfg.get("components", []) if comp.get("props", {}).get("elem_id") == "demo_video" ) assert demo_video_comp.get("props", {}).get("autoplay") is False execute_video_comp = next( comp for comp in cfg.get("components", []) if comp.get("props", {}).get("elem_id") == "execute_video" ) assert execute_video_comp.get("props", {}).get("autoplay") is True component_types = [comp.get("type") for comp in cfg.get("components", [])] assert "timer" not in component_types api_names = [dep.get("api_name") for dep in cfg.get("dependencies", [])] assert "on_demo_video_play" in api_names assert "on_execute_video_end_transition" in api_names assert "precheck_execute_inputs" in api_names assert "switch_to_execute_phase" in api_names assert "execute_step" in api_names assert "refresh_live_obs" not in api_names finally: demo.close()