extends Node # Test-only helper (tests/main_menu_smoke.gd). Not referenced by production # code. Registered as a temporary project autoload only while running this # test — see the test's own header for why an autoload (rather than a # scene-child driver) is needed: main_menu.tscn IS the real current_scene # here (run directly via --path Game res://scenes/main_menu.tscn, exactly # like production), so unlike lobby_smoke.gd's driver this doesn't even # need to survive a scene swap — it just needs to exist independently of # main_menu.gd so main_menu.gd itself stays untouched by test concerns. var _role := "" func _ready() -> void: for arg in OS.get_cmdline_user_args(): if arg.begins_with("--role="): _role = arg.substr("--role=".length()) if _role.is_empty(): return # main_menu.gd's own _ready() (which builds %-unique-name refs) must run # before we touch its nodes; autoloads run first, so wait a frame. await get_tree().process_frame await get_tree().process_frame match _role: "host": _run_host() "join_ok": _run_join_ok() "join_refused": _run_join_refused() "join_cancel": _run_join_cancel() func _run_host() -> void: var menu := get_tree().current_scene var host_btn: Button = menu.get_node("MarginContainer/ScrollContainer/CenterContainer/VBoxContainer/HostButton") host_btn.emit_signal("pressed") await get_tree().create_timer(1.0).timeout var scene := get_tree().current_scene var ok := scene != null and scene.scene_file_path == "res://scenes/lobby.tscn" print("SMOKE %s: host -> current_scene=%s" % ["PASS" if ok else "FAIL", scene.scene_file_path if scene else "null"]) if not ok: _finish(false, "host transition check failed") return # Stay up long enough for a separate join_ok/join_refused/join_cancel # process (started after this one) to actually exercise the host — # unlike _finish()'s normal 0.3s beat, this test's whole point is being # a live target for a while. await get_tree().create_timer(6.0).timeout _finish(true, "host ran and stayed up for a joiner") func _run_join_ok() -> void: # Give the host process (started first by the shell script) time to be listening. await get_tree().create_timer(1.5).timeout var menu := get_tree().current_scene var address_edit: LineEdit = menu.get_node("%JoinAddressEdit") address_edit.text = "127.0.0.1" var join_btn: Button = menu.get_node("MarginContainer/ScrollContainer/CenterContainer/VBoxContainer/JoinRow/JoinButton") join_btn.emit_signal("pressed") var overlay: Control = menu.get_node("%ConnectingOverlay") print("SMOKE INFO: overlay visible right after Join press = %s" % str(overlay.visible)) await get_tree().create_timer(2.0).timeout var scene := get_tree().current_scene var ok := scene != null and scene.scene_file_path == "res://scenes/lobby.tscn" _finish(ok, "join_ok -> current_scene=%s" % (scene.scene_file_path if scene else "null")) func _run_join_refused() -> void: var menu := get_tree().current_scene var address_edit: LineEdit = menu.get_node("%JoinAddressEdit") address_edit.text = "127.0.0.1" var join_btn: Button = menu.get_node("MarginContainer/ScrollContainer/CenterContainer/VBoxContainer/JoinRow/JoinButton") join_btn.emit_signal("pressed") var overlay: Control = menu.get_node("%ConnectingOverlay") print("SMOKE INFO: overlay visible right after Join press (no server) = %s" % str(overlay.visible)) # main_menu.gd's own CONNECT_TIMEOUT_SECONDS (6.0) is what actually # bounds this now — ENet's own connection_failed proved unbounded in # practice against a genuinely refused loopback connection. await get_tree().create_timer(8.0).timeout var error_label: Label = menu.get_node("%MultiplayerErrorLabel") var still_on_menu := get_tree().current_scene == menu var ok := still_on_menu and not overlay.visible and error_label.visible _finish(ok, "join_refused -> still_on_menu=%s overlay_visible=%s error_visible=%s error_text='%s'" % [ str(still_on_menu), str(overlay.visible), str(error_label.visible), error_label.text ]) func _run_join_cancel() -> void: var menu := get_tree().current_scene var address_edit: LineEdit = menu.get_node("%JoinAddressEdit") address_edit.text = "10.255.255.1" # non-routable; connect attempt just hangs until timeout/cancel var join_btn: Button = menu.get_node("MarginContainer/ScrollContainer/CenterContainer/VBoxContainer/JoinRow/JoinButton") join_btn.emit_signal("pressed") var overlay: Control = menu.get_node("%ConnectingOverlay") await get_tree().create_timer(0.5).timeout var overlay_shown := overlay.visible var cancel_btn: Button = menu.get_node("%ConnectingCancelButton") cancel_btn.emit_signal("pressed") await get_tree().create_timer(0.5).timeout var still_on_menu := get_tree().current_scene == menu var ok := overlay_shown and not overlay.visible and still_on_menu and not NetworkManager.is_client _finish(ok, "join_cancel -> overlay_shown=%s overlay_now=%s still_on_menu=%s is_client=%s" % [ str(overlay_shown), str(overlay.visible), str(still_on_menu), str(NetworkManager.is_client) ]) func _finish(success: bool, message: String) -> void: print("SMOKE %s: %s" % ["PASS" if success else "FAIL", message]) await get_tree().create_timer(0.3).timeout NetworkManager.shutdown() get_tree().quit(0 if success else 1)