facett-syschart/tests/a11y.rs
//! **FC-4 interaction-layer proof for facett-syschart.** Render a real
//! [`SystemChart`] (a couple of nodes with real labels + badge counts) headless
//! through `egui_kittest`, then assert each painted peer node rode into the
//! AccessKit tree as a queryable Button carrying its badge as `numeric_value`.
//!
//! Before FC-4 the nodes were `painter.circle_filled`/`painter.text` only — zero
//! accesskit nodes, invisible to `get_by_label` / a robot driver. This proves the
//! per-node `facett_core::a11y::node` call (keyed on the stable `SysNode.id`)
//! makes them findable, labelled, and value-carrying.
use std::cell::RefCell;
use std::rc::Rc;
use egui::accesskit::Role;
use egui_kittest::Harness;
use egui_kittest::kittest::{NodeT, Queryable};
use facett_core::Facet;
use facett_syschart::{SysEdge, SysNode, SystemChart};
fn chart() -> SystemChart {
let nodes = vec![
SysNode::new("pki", "PKI", egui::Color32::from_rgb(120, 200, 255), (0.2, 0.2)).badge(3),
SysNode::new("oidc", "OIDC", egui::Color32::from_rgb(200, 160, 255), (0.8, 0.2)).badge(7),
];
let edges = vec![SysEdge::new("pki", "oidc")];
SystemChart::new("System Map", nodes, edges)
}
#[test]
fn painted_nodes_are_queryable_buttons_with_badge_value() {
let mut c = chart();
let mut harness = Harness::new_ui(move |ui| {
c.ui(ui);
});
harness.run();
// "PKI · 3 events" — role Button, numeric_value = the badge count 3.
let pki = harness.get_by_label("PKI · 3 events").accesskit_node();
assert_eq!(pki.role(), Role::Button, "a painted peer node must expose a Button role (FC-4)");
assert_eq!(
pki.numeric_value(),
Some(3.0),
"the node's badge count must ride into the AccessKit tree as numeric_value"
);
// "OIDC · 7 events" — a second node, different stable id → distinct addressable node.
let oidc = harness.get_by_label("OIDC · 7 events").accesskit_node();
assert_eq!(oidc.role(), Role::Button);
assert_eq!(oidc.numeric_value(), Some(7.0));
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"SystemChart",
"fc4_node_badge_value",
pki.numeric_value() == Some(3.0) && oidc.numeric_value() == Some(7.0),
"PKI badge=3, OIDC badge=7 as a11y values",
);
}
#[test]
fn clicking_a_node_selects_it_by_stable_id() {
// Share the chart with the closure so we can read its real selection back out
// after driving a real click through the AccessKit node (inject input → assert
// output). FC-5: selection must land on the stable SysNode.id, not a loop index.
let chart_ref = Rc::new(RefCell::new(chart()));
let in_ui = chart_ref.clone();
let mut harness = Harness::new_ui(move |ui| {
in_ui.borrow_mut().ui(ui);
});
harness.run();
assert!(chart_ref.borrow().selected().is_none(), "starts unselected");
// Click the OIDC node's accesskit button, then let the click flow into ui().
harness.get_by_label("OIDC · 7 events").click();
harness.run();
assert_eq!(
chart_ref.borrow().selected(),
Some("oidc"),
"clicking the painted node selects it by its stable id (FC-4 click → FC-5 id)"
);
assert_eq!(chart_ref.borrow().state_json()["selected"], "oidc");
// Clicking the same node again toggles it back off.
harness.get_by_label("OIDC · 7 events").click();
harness.run();
assert!(chart_ref.borrow().selected().is_none(), "re-click toggles selection off");
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"SystemChart",
"fc5_click_selects_by_stable_id",
chart_ref.borrow().selected().is_none(),
"click oidc selected then re-click toggled off (stable id)",
);
}