crates/nornir-warehouse-nav/tests/robot_camera_rules.rs
//! **Warehouse →: the graph opens centred in what the viewer sees, and a click never
//! moves it** — rendered (kittest, real clicks), with the pane in an OVER-WIDE layout
//! (a 6 000 px wide region on a 1 400 px window, as a scroll area hands its content):
//!
//! * first show (repo grid, and the world graph): fitted, centred (±2 px) and wholly
//! inside the visible canvas;
//! * 📌 Stay: a click that drills (repo → its crates; a world repo → its functions)
//! leaves the camera exactly where it was;
//! * 🎯 Focus: the drill flies to frame what it opened, centred;
//! * ⊙ fit: back to the whole graph, centred.
//!
//! The owner (loki, UI 8d0bb3c): "the fix for when I click the graph and it moves to the
//! right outside the window is not fixed — it's in Warehouse →". RED before: the canvas
//! took the whole 6 000 px (the camera centres on it), every drill reset the camera to
//! zoom 1 with world (0, 0) at that far-right centre, and a world drill re-framed.
#![cfg(not(target_arch = "wasm32"))]
use std::cell::RefCell;
use std::rc::Rc;
use egui::{vec2, Pos2, Rect};
use egui_kittest::kittest::Queryable;
use egui_kittest::Harness;
use facett_core::fly::NavMode;
use facett_core::Facet;
use nornir_warehouse_nav::WarehouseNav;
type Nav = Rc<RefCell<WarehouseNav>>;
fn harness(nav: WarehouseNav, mode: NavMode) -> (Harness<'static>, Nav) {
let nav = Rc::new(RefCell::new(nav));
let n = nav.clone();
let h = Harness::builder().with_size(vec2(1400.0, 900.0)).with_step_dt(1.0 / 60.0).build_ui(move |ui| {
let wide = Rect::from_min_size(ui.max_rect().min, vec2(6000.0, ui.max_rect().height()));
ui.scope_builder(egui::UiBuilder::new().max_rect(wide), |ui| n.borrow_mut().ui(ui));
});
mode.remember(&h.ctx);
(h, nav)
}
fn steps(h: &mut Harness<'static>, n: usize) {
for _ in 0..n {
h.step();
}
}
fn camera(nav: &Nav) -> (egui::Vec2, f32) {
let v = nav.borrow().world_view_snapshot();
(v.pan, v.zoom)
}
fn assert_centred(nav: &Nav, what: &str) {
let (b, seen) = nav.borrow().screen_box().expect("drawn");
assert!(seen.width() <= 1400.0 + 0.5, "{what}: the canvas is the visible width, not the layout's 6 000 px: {seen:?}");
assert!((b.center() - seen.center()).length() <= 2.0, "{what}: centred: box {b:?} in {seen:?}");
assert!(seen.expand(0.5).contains_rect(b), "{what}: wholly visible: box {b:?} in {seen:?}");
}
fn click(h: &mut Harness<'static>, p: Pos2) {
h.input_mut().events.push(egui::Event::PointerMoved(p));
h.step();
for pressed in [true, false] {
h.input_mut().events.push(egui::Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() });
h.step();
}
}
fn first_repo(nav: &Nav) -> (String, Pos2) {
let n = nav.borrow();
let (_, seen) = n.screen_box().unwrap();
let st = Facet::state_json(&*n);
let ids: Vec<String> = st["nodes"].as_array().unwrap().iter().filter_map(|v| v["id"].as_str().or_else(|| v.as_str()).map(str::to_string)).collect();
ids.into_iter()
.filter(|i| i.starts_with("repo:"))
.filter_map(|i| n.node_on_screen(&i).map(|p| (i, p)))
.find(|(_, p)| seen.shrink(20.0).contains(*p))
.expect("a repo on screen")
}
/// First show of the repo grid: centred and wholly visible in the visible canvas.
#[test]
fn the_warehouse_graph_opens_centred() {
let (mut h, nav) = harness(WarehouseNav::from_fixture(), NavMode::Stay);
steps(&mut h, 4);
assert_centred(&nav, "first show");
let (_, seen) = nav.borrow().screen_box().unwrap();
assert!(seen.height() >= 0.6 * 900.0, "the graph covers most of the tab's height: {seen:?}");
}
/// 📌 Stay: a click that drills into a repo leaves the camera exactly where it was.
#[test]
fn stay_a_drill_click_never_moves_the_camera() {
let (mut h, nav) = harness(WarehouseNav::from_fixture(), NavMode::Stay);
steps(&mut h, 4);
let (id, p) = first_repo(&nav);
let cam = camera(&nav);
click(&mut h, p);
steps(&mut h, 40);
assert_eq!(Facet::state_json(&*nav.borrow())["level"], "repo", "the click on {id} drilled");
assert_eq!(camera(&nav), cam, "the camera did not move");
}
/// 🎯 Focus: the drill flies to frame the repo's crates, centred.
#[test]
fn focus_a_drill_click_frames_what_it_opened() {
let (mut h, nav) = harness(WarehouseNav::from_fixture(), NavMode::Focus);
steps(&mut h, 4);
let (_, p) = first_repo(&nav);
click(&mut h, p);
steps(&mut h, 60);
assert_eq!(Facet::state_json(&*nav.borrow())["level"], "repo");
assert_centred(&nav, "after a Focus drill");
}
/// ⊙ fit: after a drag, the whole graph comes back centred.
#[test]
fn fit_brings_the_graph_back_centred() {
let (mut h, nav) = harness(WarehouseNav::from_fixture(), NavMode::Stay);
steps(&mut h, 4);
let (a, b) = (Pos2::new(700.0, 500.0), Pos2::new(1100.0, 700.0));
h.hover_at(a);
h.step();
h.drag_at(a);
h.step();
h.hover_at(b);
h.step();
h.drop_at(b);
h.step();
h.get_by_label("⊙ fit").click();
steps(&mut h, 60);
assert_centred(&nav, "after ⊙ fit");
}
/// The world graph: first show centred in the visible canvas; a 📌 Stay click on a
/// repo star (which focuses that repo) leaves the camera where it was.
#[test]
fn the_world_graph_opens_centred_and_a_click_never_moves_it() {
let (mut h, nav) = harness(WarehouseNav::from_fixture_with_functions(200), NavMode::Stay);
nav.borrow_mut().update_json(r#"{"world":true}"#);
steps(&mut h, 6);
assert_centred(&nav, "world first show");
let p = {
let n = nav.borrow();
let (_, seen) = n.screen_box().unwrap();
let shot = Facet::state_json(&*n);
let _ = shot;
// the first world node (a repo star) on screen
(0..50).filter_map(|i| n.node_on_screen(&format!("w{i}"))).find(|p| seen.shrink(20.0).contains(*p)).expect("a star on screen")
};
let cam = camera(&nav);
click(&mut h, p);
steps(&mut h, 40);
assert_eq!(camera(&nav), cam, "a world click did not move the camera");
}