Godot Version
4.2
Question
I’ve been using the GUT add on to add unit tests to my project, but have hit a snag with a scene node not getting added to the tree (when running it in editor is fine). I suspect it’s an issue with a combination of Godot 4.x, GUT, autoload singletons, signals, and myself.
I’ve whittled it down to a the bare bones - so it might look like a contrived scene switcher but you can assume I use some of this plumbing/pattern for other things.
Pieces involved:
- RootScene.tscn (main scene). A
Node2D
and has either of the following two scenes as a child: - Splash.tscn (A
Node2D
with aSprite2D
background. This one is a child of the RooteScene to start with. - MainMenu.tscn (A
Node2D
with a differentSprite2D
background. This is the one we transition to on user input (hitting enter). - EventBus.gd, an autoload singleton, where all events get listed
- GlobalStore.gd, an autoload singleton, where state that will persist accross scene changes lives.
- test_LeaveSplash.gd - the unit test
User sees splash, user hits enter, user sees “menu”. Works in editor. Here is _on_leave_splash
in RootScenen.tscn
:
func _on_leave_splash():
var splash = get_node("Splash")
splash.queue_free()
await splash.tree_exited
# add the main menu scene to the root scene:
var mainMenuScene = load("res://scenes/MainMenu.tscn")
var mainMenuInstance = mainMenuScene.instantiate()
mainMenuInstance.name = "MainMenu"
add_child(mainMenuInstance, true)
Here is the test:
func test_can_leave_splash_screen():
var rootScene
var rootSceneInstance
rootScene = load("res://scenes/RootScene.tscn")
rootSceneInstance = rootScene.instantiate()
await wait_until(func ():
return rootSceneInstance.is_inside_tree()
, 5)
# these pass:
assert_not_null(rootSceneInstance.get_node("Splash"), "Splash screen should be present.")
assert_eq(GlobalStore.current_game_mode, GlobalStore.GAME_MODE.SPLASH_SCREEN, "Splash screen should be current game mode.")
# send input event to leave splash screen:
gut.p("sending input event to leave splash screen", 2)
_sender.add_receiver(rootSceneInstance)
_sender.action_down("start").hold_for(0.5)
_sender.action_up("start")
_sender.is_idle()
await wait_until(func ():
return GlobalStore.current_game_mode == GlobalStore.GAME_MODE.MAIN_MENU
, 5)
assert_true(GlobalStore.ui_loading == false, "UI should be loaded.")
assert_true(GlobalStore.current_game_mode == GlobalStore.GAME_MODE.MAIN_MENU, "Main menu should be current game mode.")
assert_freed(rootSceneInstance.get_node("Splash").is_inside_tree(), "Splash screen should be gone.")
# doesn't work: (error no node named MainMenu relative to UI_Root)
assert_not_null(rootSceneInstance.get_node("MainMenu"), "Main menu should be present.")
I’ve tried a variety of things, like having MainMenu emit an event through the ‘bus’ and use wait_for_signal
but it never reaches the test. Otherwise I just get “No node named MainMenu relative to UI_Root” or data.tree is null.