Files
ARCADIA-Studio/crates/oa-desktop/src/app/state_picker_escape_tests.rs
T

105 lines
3.9 KiB
Rust

//! The actual State workspace picker, App root and subscriptions.
use super::*;
use crate::behavior::canvas_workspace::tests::{Mounted, key};
use iced::{keyboard::key::Named, mouse};
async fn press_escape(mounted: &mut Mounted, app: &mut App) -> Vec<Message> {
let input = key(Named::Escape);
let (mut messages, statuses) = mounted.input_with_status(
app,
std::slice::from_ref(&input),
mouse::Cursor::Unavailable,
);
assert_eq!(
statuses,
[iced::event::Status::Captured],
"the mounted picker must capture Escape before App subscriptions"
);
crate::app::escape::tests::subscriptions(app, input, statuses[0], &mut messages);
for message in messages.iter().cloned() {
let task = app.update(message);
mounted.perform(app, task).await;
}
mounted.settle(app).await;
messages
}
#[tokio::test]
async fn mounted_state_missing_picker_escape_preserves_exact_document_then_reopens_and_places() {
let mut f = fixture();
let diagram = create_view(&mut f).diagram;
let mut project = f.app.project().clone();
project
.diagrams
.get_mut(&diagram)
.unwrap()
.nodes
.retain(|_, node| node.element != f.b);
let mut app = App::with_project(project);
app.window_size = iced::Size::new(1800., 1100.);
send(&mut app, Message::Select(f.a));
send(&mut app, Message::Page(Page::Behavior));
let choice = Choice {
id: diagram,
label: app.project().diagrams[&diagram].name.clone(),
};
send(&mut app, Message::BehaviorDiagram(choice));
let mut mounted = Mounted::new(&mut app).await;
assert_eq!(state_edit::unplaced(app.project(), diagram), vec![f.b]);
// Locate the stable picker slot itself: selection controls may sit between
// it and the canvas. The single menu option opens below this slot.
let bounds = mounted.geometry(&app).bounds("state-missing-picker");
let picker = bounds.center();
let option = iced::Point::new(picker.x, bounds.y + bounds.height * 1.5);
let before = app.document.snapshot();
let original = app.project().clone();
let source = app.document.bundle().clone();
let selection = (
app.selected,
app.selected_node,
app.behavior.diagram.placement,
);
let camera = (
app.behavior.diagram.zoom,
app.behavior.diagram.pan,
app.behavior.diagram.fit,
);
let revision = app.document.revision();
let history = (app.document.can_undo(), app.document.can_redo());
mounted.click(&mut app, picker).await;
assert!(
press_escape(&mut mounted, &mut app).await.is_empty(),
"open picker owns Escape, not the State canvas or App"
);
assert!(std::sync::Arc::ptr_eq(&before, &app.document.snapshot()));
assert_eq!(app.document.bundle(), &source);
assert_eq!(
(
app.selected,
app.selected_node,
app.behavior.diagram.placement
),
selection
);
assert_eq!(
(
app.behavior.diagram.zoom,
app.behavior.diagram.pan,
app.behavior.diagram.fit
),
camera
);
assert_eq!(app.document.revision(), revision);
assert_eq!((app.document.can_undo(), app.document.can_redo()), history);
// If Escape left the menu open this click would close it, and the following
// option click would fail to place. This checks actual overlay dismissal.
mounted.click(&mut app, picker).await;
let messages = mounted.click(&mut app, option).await;
assert!(messages.iter().any(|message| matches!(message, Message::StateDiagram(Event::Place { element, .. }) if *element == f.b)));
assert!(state_edit::unplaced(app.project(), diagram).is_empty());
assert_eq!(app.project().elements, original.elements);
assert_eq!(app.project().relations, original.relations);
let _ = app.update(Message::Undo);
assert_eq!(app.document.bundle(), &source);
}