tests/the_board_is_mounted.rs
//! ★ **The artifact flow stays mounted, on the Flow page and only there** (HBOARD-1; HOL-SEC,
//! owner 2026-10-27; HOL-SVG-RON, owner 2026-10-30; HOL-UI-FIX, owner 2026-10-31: "3 menus doing
//! the same flow"). The board went missing from where the owner looks once already, and then
//! it drew front | main | twin and nothing of the RON; later the Overview, the console's home
//! and the Flow page showed it two and three times. This guard holds: the Flow page (`/flow`)
//! mounts the ONE component `<EstateBoard/>`; the Overview shows the estate's state in cards and
//! links to the Flow, drawing nothing; the Admin page links to it; the Security page shows
//! security and NOT the board; the component shows holger's own drawing
//! (`AdminService.FlowSvg`) as an image, and the console carries no renderer of its own.
const ROOT: &str = env!("CARGO_MANIFEST_DIR");
/// A source file with its `//` comment lines dropped: a mount in a comment is no mount.
fn code(path: &str) -> String {
let text = std::fs::read_to_string(format!("{ROOT}/{path}")).unwrap_or_else(|e| panic!("{path}: {e}"));
text.lines().filter(|l| !l.trim_start().starts_with("//")).collect::<Vec<_>>().join("\n")
}
/// The component's own body in `page`: up to the next top-level component.
fn body(page: &str, component: &str) -> String {
let src = code(page);
let at = src.find(component).unwrap_or_else(|| panic!("{page}: no {component}"));
let body = &src[at..];
body[..body[1..].find("\n#[component]").map(|i| i + 1).unwrap_or(body.len())].to_string()
}
/// ★ **One picture, one page** (HOL-UI-FIX): the Flow page shows what its address opens (main
/// by default; level 2 or 3); the Overview (and the console's home, the same page) draws no
/// board and links to the Flow.
#[test]
fn the_flow_page_alone_mounts_the_board_and_the_others_link_to_it() {
let flow = body("src/pages/estate_board.rs", "pub fn Flow");
assert!(flow.contains("<EstateBoard") && flow.contains("sec::flow_open("), "the Flow page opens what its address names");
let mounts: Vec<String> = std::fs::read_dir(format!("{ROOT}/src/pages"))
.unwrap()
.map(|e| e.unwrap().path())
.filter(|p| p.file_name().is_some_and(|n| n != "estate_board.rs"))
.filter(|p| code(&format!("src/pages/{}", p.file_name().unwrap().to_string_lossy())).contains("EstateBoard"))
.map(|p| p.display().to_string())
.collect();
assert!(mounts.is_empty(), "the board is mounted again outside the Flow page: {mounts:?}");
let overview = code("src/pages/dashboard.rs");
assert!(!overview.contains("Machines") && !overview.contains("board-img"), "the Overview draws the flow again");
assert!(overview.contains("ov::FLOW"), "the Overview links to the Flow page");
assert!(code("src/overview.rs").contains(r#"pub const FLOW: &str = "/flow";"#));
let admin = body("src/pages/admin.rs", "pub fn Admin");
assert!(admin.contains(r#"data-board-link="estate""#) && admin.contains(r#"href="/flow""#), "the Admin page links to the board on the Flow page");
}
#[test]
fn the_security_page_shows_security_and_not_the_board() {
let sec = body("src/pages/security.rs", "pub fn SecurityDashboard");
assert!(!code("src/pages/security.rs").contains("EstateBoard"), "the Security page shows the machinery board again");
assert!(sec.contains("<SecuritySummary/>"), "the Security page no longer shows the gateway's summary");
let summary = body("src/pages/security.rs", "fn SecuritySummary");
assert!(summary.contains("sec::load_security(&GrpcDoor)") && summary.contains("data-section"), "the summary is holger's SecuritySummary answer, a card per section");
}
#[test]
fn the_routes_lead_to_the_pages_that_mount_it() {
let app = code("src/app.rs");
for route in [r#"path!("/overview") view=Dashboard"#, r#"path!("/") view=Dashboard"#, r#"path!("/flow") view=Flow"#, r#"path!("/admin") view=Admin"#, r#"path!("/security") view=SecurityDashboard"#] {
assert!(app.contains(route), "src/app.rs: the route {route} is gone");
}
}
#[test]
fn the_board_component_shows_holgers_flow_drawing_and_draws_nothing_itself() {
let c = code("src/pages/estate_board.rs");
assert!(c.contains("sec::load_board(&GrpcDoor, &open)"), "the board is holger's answer, at the zoom the page asks");
assert!(c.contains(r#"class="board-img""#) && c.contains("board-summary"), "the drawing and the server's line under it");
assert!(c.contains(r#"class="board-hit""#) && c.contains("b.links"), "holger's clickable places, laid over the image as plain links");
let sec = code("src/security.rs");
assert!(sec.contains("crate::grpc::admin().flow_svg(pb::FlowSvgRequest { open"), "the drawing is holger's AdminService.FlowSvg, at the zoom the page asks");
assert!(sec.contains("enc(&flow.svg)"), "shown as holger sent it");
assert!(!std::path::Path::new(&format!("{ROOT}/src/board.rs")).exists() && !code("src/main.rs").contains("mod board;"), "the console carries no renderer of its own");
assert!(!code("Cargo.toml").contains("nordisk-estate-svg"), "and no renderer crate");
assert!(code("src/pages/mod.rs").contains("pub mod estate_board;"));
}