Skip to content

Add tests for auto-panning #2597

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

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
299 changes: 299 additions & 0 deletions editor/src/messages/tool/common_functionality/auto_panning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,302 @@ impl AutoPanning {
Some(delta)
}
}

#[cfg(test)]
mod test_auto_panning {
use crate::messages::input_mapper::utility_types::input_mouse::EditorMouseState;
use crate::messages::input_mapper::utility_types::input_mouse::ScrollDelta;
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
use crate::test_utils::test_prelude::*;

#[tokio::test]
async fn test_select_tool_drawing_box_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Rectangle, 50., 50., 150., 150., ModifierKeys::empty()).await;
editor.select_tool(ToolType::Select).await;
// Starting selection box inside viewport
editor.left_mousedown(100., 100., ModifierKeys::empty()).await;
// Moving cursor far outside viewport to trigger auto-panning
editor.move_mouse(2000., 100., ModifierKeys::empty(), MouseKeys::LEFT).await;

let pointer_keys = SelectToolPointerKeys {
axis_align: Key::Shift,
snap_angle: Key::Control,
center: Key::Alt,
duplicate: Key::Alt,
};

// Sending multiple pointer outside events to simulate auto-panning over time
for _ in 0..5 {
editor.handle_message(SelectToolMessage::PointerOutsideViewport(pointer_keys.clone())).await;
}

editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(2000., 100.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
},
ModifierKeys::empty(),
)
.await;

let document = editor.active_document();
let selected_node_count = document.network_interface.selected_nodes().selected_nodes_ref().len();
assert!(selected_node_count > 0, "Selection should have included at least one object");
}

#[tokio::test]
async fn test_select_tool_dragging_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Rectangle, 50., 50., 150., 150., ModifierKeys::empty()).await;
let layer = editor.active_document().metadata().all_layers().next().unwrap();
let initial_transform = editor.active_document().metadata().transform_to_viewport(layer);
// Select and start dragging the rectangle
editor.select_tool(ToolType::Select).await;
editor.left_mousedown(100., 100., ModifierKeys::empty()).await;

// Moving cursor outside viewport to trigger auto-panning
editor.move_mouse(2000., 100., ModifierKeys::empty(), MouseKeys::LEFT).await;

let pointer_keys = SelectToolPointerKeys {
axis_align: Key::Shift,
snap_angle: Key::Control,
center: Key::Alt,
duplicate: Key::Alt,
};

// Sending multiple outside viewport events to simulate continuous auto-panning
for _ in 0..5 {
editor.handle_message(SelectToolMessage::PointerOutsideViewport(pointer_keys.clone())).await;
}

editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(2000., 100.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
},
ModifierKeys::empty(),
)
.await;
Comment on lines +147 to +171
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a function instead of duplicating so much code.


// Verifying the rectngle has moved significantly due to auto-panning
let final_transform = editor.active_document().metadata().transform_to_viewport(layer);
let translation_diff = (final_transform.translation - initial_transform.translation).length();

assert!(translation_diff > 10., "Rectangle should have moved significantly due to auto-panning (moved by {})", translation_diff);
}

#[tokio::test]
async fn test_select_tool_resizing_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Rectangle, 50., 50., 150., 150., ModifierKeys::empty()).await;
let layer = editor.active_document().metadata().all_layers().next().unwrap();
let initial_transform = editor.active_document().metadata().transform_to_viewport(layer);

editor.select_tool(ToolType::Select).await;
editor.left_mousedown(150., 150., ModifierKeys::empty()).await; // Click near edge for resize handle
editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(150., 150.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
},
ModifierKeys::empty(),
)
.await;

editor.handle_message(TransformLayerMessage::BeginScale).await;

// Moving cursor to trigger auto-panning
editor.move_mouse(2000., 2000., ModifierKeys::empty(), MouseKeys::LEFT).await;

let pointer_keys = SelectToolPointerKeys {
axis_align: Key::Shift,
snap_angle: Key::Control,
center: Key::Alt,
duplicate: Key::Alt,
};

// Simulatiing auto-panning for several frames
for _ in 0..5 {
editor.handle_message(SelectToolMessage::PointerOutsideViewport(pointer_keys.clone())).await;
}

editor.handle_message(TransformLayerMessage::ApplyTransformOperation { final_transform: true }).await;

// Verifying the transform has changed (scale component should be different)
let final_transform = editor.active_document().metadata().transform_to_viewport(layer);

// Comparing transform matrices to detect scale changes
let initial_scale = initial_transform.matrix2.determinant().sqrt();
let final_scale = final_transform.matrix2.determinant().sqrt();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have assumed that the scale is uniform. Please justify this in a comment.

let scale_ratio = final_scale / initial_scale;

assert!(
scale_ratio > 1.1 || scale_ratio < 0.9,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can you not determine what happens to the scale? Surely the scale should increase.

"Rectangle should have been resized due to auto-panning (scale ratio: {})",
scale_ratio
);
}

#[tokio::test]
async fn test_artboard_tool_drawing_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;

editor.select_tool(ToolType::Artboard).await;
editor.left_mousedown(100., 100., ModifierKeys::empty()).await;

// Moving cursor outside viewport to trigger auto-panning
editor.move_mouse(2000., 100., ModifierKeys::empty(), MouseKeys::LEFT).await;

// Sending pointer outside event multiple times to simulate auto-panning
for _ in 0..5 {
editor
.handle_message(ArtboardToolMessage::PointerOutsideViewport {
constrain_axis_or_aspect: Key::Shift,
center: Key::Alt,
})
.await;
}

editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(2000., 100.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
Comment on lines +260 to +261
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just to ..Default::default()

},
ModifierKeys::empty(),
)
.await;

// Verifying that an artboard was created with significant width due to auto-panning
let artboards = get_artboards(&mut editor).await;
assert!(!artboards.is_empty(), "Artboard should have been created");
assert!(
artboards[0].dimensions.x > 200,
"Artboard should have significant width due to auto-panning: {}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What led you to decide that this was «significant». Please justify in a comment.

artboards[0].dimensions.x
);
}

#[tokio::test]
async fn test_artboard_tool_dragging_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Artboard, 50., 50., 150., 150., ModifierKeys::empty()).await;

let artboards = get_artboards(&mut editor).await;
assert!(!artboards.is_empty(), "Artboard should have been created");
let initial_location = artboards[0].location;

editor.select_tool(ToolType::Artboard).await;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Artboard is already selected.

editor.left_mousedown(100., 100., ModifierKeys::empty()).await;

// Moving cursor outside viewport to trigger auto-panning
editor.move_mouse(2000., 100., ModifierKeys::empty(), MouseKeys::LEFT).await;

// Sending pointer outside event multiple times to simulate auto-panning
for _ in 0..5 {
editor
.handle_message(ArtboardToolMessage::PointerOutsideViewport {
constrain_axis_or_aspect: Key::Shift,
center: Key::Alt,
})
.await;
}

editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(2000., 100.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
},
ModifierKeys::empty(),
)
.await;

// Verifying the artboard moved due to auto-panning
let artboards = get_artboards(&mut editor).await;
let final_location = artboards[0].location;

assert!(
(final_location.x - initial_location.x).abs() > 10 || (final_location.y - initial_location.y).abs() > 10,
"Artboard should have moved significantly due to auto-panning: {:?} -> {:?}",
initial_location,
final_location
);
}

// This test is marked as ignored due to inconsistent behavior when run as part of the test suite.
// It passes when run individually but frequently fails when run with other tests.
// The issue appears to be related to difficulty consistently capturing resize handles with mouse events
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate further.

// and unpredictable behavior of auto-panning in the test environment.
// TODO: Implement a more deterministic approach to test artboard resizing with auto-panning.
#[ignore = "Flaky test - passes alone but fails in suite"]
#[tokio::test]
async fn test_artboard_tool_resizing_auto_panning() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Artboard, 50., 50., 150., 150., ModifierKeys::empty()).await;

let artboards = get_artboards(&mut editor).await;
assert!(!artboards.is_empty(), "Artboard should have been created");
let initial_dimensions = artboards[0].dimensions;

// Selecting the artboard and click on edge to prepare for resizing
editor.select_tool(ToolType::Artboard).await;
editor.left_mousedown(150., 150., ModifierKeys::empty()).await;

// Moving cursor outside viewport to trigger auto-panning
editor.move_mouse(2000., 2000., ModifierKeys::empty(), MouseKeys::LEFT).await;

// Sending pointer outside event multiple times to simulate auto-panning
for _ in 0..5 {
editor
.handle_message(ArtboardToolMessage::PointerOutsideViewport {
constrain_axis_or_aspect: Key::Shift,
center: Key::Alt,
})
.await;
}

editor
.mouseup(
EditorMouseState {
editor_position: DVec2::new(2000., 2000.),
mouse_keys: MouseKeys::empty(),
scroll_delta: ScrollDelta::default(),
},
ModifierKeys::empty(),
)
.await;

// Verifying the artboard was resized due to auto-panning
let artboards = get_artboards(&mut editor).await;
let final_dimensions = artboards[0].dimensions;

assert!(
final_dimensions.x > initial_dimensions.x || final_dimensions.y > initial_dimensions.y,
"Artboard should have been resized due to auto-panning: {:?} -> {:?}",
initial_dimensions,
final_dimensions
);
}

// Helper function to get artboards
async fn get_artboards(editor: &mut EditorTestUtils) -> Vec<graphene_core::Artboard> {
let instrumented = editor.eval_graph().await;
instrumented.grab_all_input::<graphene_core::append_artboard::ArtboardInput>(&editor.runtime).collect()
}
}
Loading