Gut
Gut copied to clipboard
[Question] Is it possible to run tests that interact with UI using InputSender?
I'm trying to write a few tests that simulate pressing buttons in a UI. I'm using InputSender to send mouse events to the buttons, but they don't seem to be reacting to the events. I've tried a number of things to get it to work. I first tried just calling _sender.mouse_left_button_up()
on the sender to send an mouse up event to the button, as i've noticed that buttons don't usually toggle unless you release the left mouse button, but this did not work. Next, I tried a combination of _sender.mouse_left_button_down()
and _sender.mouse_left_button_up()
in that order thinking maybe the button won't toggle unless it first receives a mouse down event, but that did not work either. Finally, I did _sender.mouse_motion()
, _sender.mouse_left_button_down()
and _sender.mouse_left_button_up()
in that order, but once again, it did not work. I also checked to make sure that the positions I was passing to those methods were right where the button was located, and it was indeed where it should be.
Here is what my test looks like at the moment:
func test_click_resume() -> void:
_sender.add_receiver(_resume_button)
_sender.mouse_motion(Vector2(960, 460)).wait_secs(0.1)
_sender.mouse_left_button_down(Vector2(960, 460)).hold_for(0.1)
_sender.mouse_left_button_up(Vector2(960, 460)).wait_frames(1)
await _sender.idle
await wait_frames(1)
assert_signal_emitted(_pause_menu, "resume_pressed", "Resume button has been pressed.")
assert_false(_pause_menu.visible, "Pause menu is no longer visible.")
So I have no idea if I'm doing something wrong or if this is even possible to begin with. Can you interact with UI elements using InputSender? How would you write tests that interact with UI elements?
Do you really need to test pressing the actual button, if i test ui i just simulate a mouse press by retrieving the button and call b.pressed.emit()
on it, so i only test what happens after a button was pressed not the button itself.
Do you really need to test pressing the actual button, if i test ui i just simulate a mouse press by retrieving the button and call
b.pressed.emit()
on it, so i only test what happens after a button was pressed not the button itself.
Fair enough, I'll just do this instead. It made sense in my head to simulate it being physically clicked, but this is obviously much easier.
If it helps, the doc says
It’s best to wait at least 2 frames as waiting one frame can be flaky
I'm not in the same situation as you, but for me waiting 2 frames solved my problems.
Tip: If you provide a minimal reproducible example, including .tscn or .gd files under test, it would make it easier to help you.
When testing buttons, it is often best to just emit the signal yourself (an opinion I've come to after trying to simulate it myself). This should be added to the documentation.
The Input mocking is more useful when you have implemented complicated logic in your input handling. Like if you have made your own "pressed" event on an Area2D by
- watching for the mouse to enter/exit the shape
- watching mouse buttons' pressed events
- emitting your own signal or handling the click when you've determined there is one.
Closing this out, reopen if you have any more questions.
When testing buttons, it is often best to just emit the signal yourself (an opinion I've come to after trying to simulate it myself). This should be added to the documentation.
The Input mocking is more useful when you have implemented complicated logic in your input handling. Like if you have made your own "pressed" event on an Area2D by
- watching for the mouse to enter/exit the shape
- watching mouse buttons' pressed events
- emitting your own signal or handling the click when you've determined there is one.
+1 for adding this to the documentation.