-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get_viewport().get_mouse_position() does not work with InputSender #646
Comments
Try adding I can't remember if this is experimental (why it might not be documented) or not. I do know that you shouldn't touch the mouse while tests that use this are running...for fairly obvious reasons. Since you are using a double, it might be easier to add a private |
Yeah, this works! Thanks. Also, thanks for the idea to stub the get_mouse_position using a private method. It works too. But for the reported way to get the mouse position get_viewport().get_mouse_position(), will it be supported anytime? |
I was playing with the suggestions of @bitwes and got a solution to what I was seeking. 1. Add a private method to get the cursor position (as was suggested):At Node2D's script: extends Node2D
@onready var label: Label = $Label
var offset: Vector2 = Vector2(10,50)
# Added private method
func _get_mouse_position() -> Vector2:
return self.get_viewport().get_mouse_position()
func _process(_delta: float) -> void:
# Replaced by the private method call here
var mouse_pos = _get_mouse_position()
var label_pos = mouse_pos + offset
label.position = label_pos 2. Stub the _get_mouse_position:At test script: func _get_inputsender_mouse_position(sender):
return sender._mouse_draw._draw_at
func test_label_workaround_with_stub():
var _sender = InputSender.new(Input)
var my_scene = load("res://node_2d.tscn")
var scene = partial_double(my_scene).instantiate()
stub(scene.get_node("."), "_get_mouse_position").to_call(_get_inputsender_mouse_position.bind(_sender))
add_child_autofree(scene)
_sender = _sender.mouse_set_position(Vector2i(20,20)).wait_frames(1)
await _sender.idle
for i in range(0,20):
_sender = _sender.mouse_relative_motion(Vector2(1,1)).wait_frames(2)
await _sender.idle
await wait_frames(1)
assert_eq(scene.get_node("./Label").position, Vector2(40,40) + Vector2(10,50), "Wrong label position") Here, the sender._mouse_draw._draw_at get where the fake mouse cursor is drawn by the InputSender. So, I use it to return the fake mouse position by the stub. This way, moving the real mouse cursor will not impact on the test, but the "follow the fake cursor moving part" of the label also works without changing any code of the original Node2D (in addition to add the private method). PS: If your Node2D is translated or rotated, you need to use it's Transform2D to get the real position, because the _draw_at is the position of the mouse cursor on screen, not in the viewport/transform of the Node. Mine was at origin (0,0), so I didn't need it. PS2: I updated the GUT to 9.3.0 to use the to_call on stub. It was not present on 9.2.1 as I used on the original report. |
If I'm understanding all this right, you are trying to verify that the label moves with the cursor. If that is the case, then I think you can simplify things a bit and not use the input sender at all. This is a little more in-line with a unit test approach, where as what you posted would be considered an integration test. In this code, I put all the code into a extends GutTest
class SuperLabel:
extends Label
var offset: Vector2 = Vector2(10,50)
func _get_mouse_position() -> Vector2:
return self.get_viewport().get_mouse_position()
func _process(_delta: float) -> void:
var mouse_pos = _get_mouse_position()
var label_pos = mouse_pos + offset
position = label_pos
func before_all():
register_inner_classes(get_script())
func test_something():
var _sender = InputSender.new(Input)
var scene = partial_double(SuperLabel).new()
stub(scene._get_mouse_position).to_return(Vector2(50, 50))
add_child_autofree(scene)
await wait_frames(10) # 5 didn't give _process time to kick in
assert_eq(scene.position, Vector2(50, 50) + scene.offset) I think I need to add a blurb to the Input Mocking documentation that tells you not to use it unless you absolutely have to. I always want to use it. It's cool, it's fun. I wanna watch the cursor move around...but most of the time you can simplify things and test the code without having to involve input. A great example is pushing a button. I want to write a test that moves the mouse over a button and pushes the button down and then releases it to test my button press logic...but it's way easier, and tests the same thing, to just make your test do |
Thought of this right after I hit "comment". You don't even need to await. You an use func test_something_using_simulate():
var scene = partial_double(SuperLabel).new()
stub(scene._get_mouse_position).to_return(Vector2(50, 50))
add_child_autofree(scene)
simulate(scene, 1, .1)
assert_eq(scene.position, Vector2(50, 50) + scene.offset) |
Versions
(list all versions where you have replicated the bug)
The Bug
In my script, I use the method Node.get_viewport().get_mouse_position() to get the coordinates and position another node near the mouse.
Using the InputSender's mouse_set_position and mouse_relative_motion methods, it doesn't propagate the mouse position to the Node.get_viewport().get_mouse_position(). In the docs, I haven't found anything about this method also.
Steps To Reproduce
1. Scene setup
Create a scene with a Node2D and a Label.
Set any text to the Label.
2. Node2D script
Attach this script to Node2D node:
3. Create the test script
Expected result (Running the game)
It is expected that the Label follows the mouse pointer with the defined offset.
Workaround
If I use the function Input.warp_mouse, I can simulate the OS's mouse cursor moving, and the test scenario works:
The text was updated successfully, but these errors were encountered: