From cb5d50de03a002079da17e6f92ea44c32f7ece75 Mon Sep 17 00:00:00 2001 From: Codex-ytr83r Date: Sun, 13 Sep 2026 00:21:27 -0700 Subject: [PATCH] Correct mounted scenario camera and palette assertions --- .../src/behavior/canvas_workspace.rs | 2 +- .../src/behavior/scenario/workspace/tests.rs | 55 +++++++++++++++++-- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/crates/oa-desktop/src/behavior/canvas_workspace.rs b/crates/oa-desktop/src/behavior/canvas_workspace.rs index 7d87e0d4..65a4fb45 100644 --- a/crates/oa-desktop/src/behavior/canvas_workspace.rs +++ b/crates/oa-desktop/src/behavior/canvas_workspace.rs @@ -58,7 +58,7 @@ pub fn controls<'a>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Scope { - pub scenario_view: Option<(super::scenario_layout::Representation, Id)>, + pub(crate) scenario_view: Option<(super::scenario_layout::Representation, Id)>, pub document: Id, pub owner: Id, pub revision: u64, diff --git a/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs b/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs index bb6e6493..025d172a 100644 --- a/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs +++ b/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs @@ -48,8 +48,28 @@ async fn production_scenario_canvas_keeps_bounds_draft_identity_and_camera_throu mounted.pan(&mut app, start, start + delta).await; let diff = app.behavior.scenario.presentation.pan - next_pan; assert!(diff.x.hypot(diff.y) < 0.01); - let tool = mounted.geometry(&app).bounds("behavior-tool:A").center(); - mounted.click(&mut app, tool).await; + // Iced operations report palette children in content coordinates. + // The preceding Action focus may have scrolled this retained palette. + let geometry = mounted.geometry(&app); + let scope = canvas_workspace::Scope::current(&app).unwrap(); + let (palette, offset) = geometry.scrolls[&scope.control_id("palette-scroll")]; + let tool = geometry.bounds("behavior-tool:A").center() - offset; + assert!( + palette.contains(tool), + "visible Action at {tool:?}: {palette:?}" + ); + let chosen = mounted.click(&mut app, tool).await; + assert!( + chosen.iter().any(|message| matches!( + canvas_workspace::tests::intent_action(message), + Message::ScenarioCanvas(CanvasEvent::Choose(_, CanvasTool::Add(Tool::Action))) + )), + "Action palette click at scale {scale}, offset {offset:?}: {chosen:?}" + ); + assert_eq!( + app.behavior.scenario.canvas_tool(f.owner), + CanvasTool::Add(Tool::Action) + ); let messages = mounted.click(&mut app, bounds.position() + desired).await; assert!( messages.iter().any( @@ -57,7 +77,7 @@ async fn production_scenario_canvas_keeps_bounds_draft_identity_and_camera_throu tool: Tool::Action, slot, lifeline: Some(line), .. }) if *slot == expected && *line == f.sender) ), - "scale {scale}: {messages:?}" + "scale {scale}, expected slot {expected:?}: {messages:?}" ); let session = app.behavior.scenario.form_session().unwrap(); let invocation = app.behavior.scenario.draft.as_ref().unwrap().invocation; @@ -1337,7 +1357,18 @@ async fn production_scenario_camera_external_controls_bounds_and_retained_deltas let bounds = mounted.geometry(&app).bounds("scenario-viewport"); let point = bounds.position() + iced::Vector::new(95., 90.); let lifetime = app.camera_epoch; - let pan = app.behavior.scenario.presentation.pan; + // Fit stores no pan offset. A real drag starts from the displayed fitted + // camera, then materializes it before applying its ordered screen deltas. + let shown = app + .behavior + .scenario + .display(app.project(), f.owner, app.selected) + .unwrap(); + let before_camera = app + .behavior + .scenario + .presentation + .camera(shown.bounds().unwrap()); let first = point + iced::Vector::new(13., 9.); let last = first + iced::Vector::new(17., -3.); let emitted = mounted @@ -1352,7 +1383,21 @@ async fn production_scenario_camera_external_controls_bounds_and_retained_deltas mouse::Cursor::Available(last), ) .await; - assert_eq!(app.behavior.scenario.presentation.pan, pan + (last - point)); + let expected_pan = before_camera.pan + (last - point); + let actual_pan = app.behavior.scenario.presentation.pan; + let difference = actual_pan - expected_pan; + assert!( + difference.x.hypot(difference.y) < 0.001, + "{boundary}: displayed pan {actual_pan:?} must follow {expected_pan:?}" + ); + assert_eq!( + app.behavior.scenario.presentation.zoom, + Some(before_camera.scale) + ); + assert!( + !app.behavior.scenario.presentation.fit, + "drag materializes the visible Fit camera" + ); assert_eq!( app.camera_epoch, lifetime, "own ordered deltas retain their lifetime"