facett-demo/tests/errcode_showcase.rs
//! **Robot-UI proof of the facett error-code showcase** (Phase-1 deliverable E).
//!
//! Asserts, as DATA (not a matched string):
//! 1. a raised error surfaces its CODE in `state_json` (not just a message string);
//! 2. the pink render appears in a debug build (the `Errors` tab renders the code
//! atoms + reports `code_visible_onscreen`);
//! 3. the uniqueness guard passes (no duplicate `facet-<component>-<n>`);
//! 4. the About / Diagnostics popup carries the git hash + a source link per
//! component;
//! 5. the error-code MATRIX slide renders every registry row.
//!
//! The bulk is read straight off `DemoState::state_json` (fast, no window). ONE light
//! `egui_kittest` render drives just the `Errors` tab (cheap — no graph3d) to prove
//! the pink code atoms actually reach the AccessKit tree.
use egui_kittest::kittest::{By, Queryable};
use egui_kittest::Harness;
use facett::core::errcode;
use facett_demo::DemoState;
#[test]
fn registry_uniqueness_guard_is_green() {
// No duplicate code globally; no duplicate n within a component; well-formed codes.
use std::collections::{HashMap, HashSet};
let mut codes: HashSet<&str> = HashSet::new();
let mut per: HashMap<&str, HashSet<u32>> = HashMap::new();
for e in errcode::registry() {
assert!(codes.insert(e.code), "duplicate code {}", e.code);
assert!(per.entry(e.component).or_default().insert(e.n), "duplicate n in {}", e.component);
assert_eq!(e.code, format!("facet-{}-{}", e.component, e.n));
}
assert!(errcode::registry().len() >= 20, "the catalog is populated");
}
#[test]
fn errors_tab_surfaces_codes_and_matrix_in_state_json() {
let demo = DemoState::new();
let state = demo.state_json();
// 1. The `Errors` facet is registered and carries the codes as DATA.
let errors = &state["deck"]["facets"]["Errors"];
assert_eq!(errors["scheme"], "facet-<component>-<n>");
// A raised error surfaces its CODE (not just the string).
let raised = errors["raised"].as_array().expect("raised errors present");
assert!(!raised.is_empty());
assert_eq!(raised[0]["code"], "facet-demo-1");
assert_eq!(raised[0]["severity"], "error");
assert!(raised[0]["message"].as_str().unwrap().contains("example error"));
// 5. The MATRIX slide carries one row per registry code.
let matrix = errors["matrix"].as_array().expect("matrix present");
assert_eq!(matrix.len(), errcode::registry().len());
// Every row carries code + source url.
for row in matrix {
assert!(row["code"].as_str().unwrap().starts_with("facet-"));
assert!(row["source_url"].as_str().unwrap().starts_with("https://gunnar.rs/nordisk/facett"));
}
// The graph3d HOST-PLACEMENT code (facet-graph3d-5, added with `Layout3D::Given`
// and the `graph3d-given` tab) is on the showcase slide — and WIRED, i.e. raised
// by a real pane rather than merely catalogued. A code that reaches the registry
// but never the showcase is exactly the invisible change this gate exists for.
let g3d5 = matrix
.iter()
.find(|row| row["code"] == "facet-graph3d-5")
.expect("facet-graph3d-5 (the Layout3D::Given short-placement fallback) is on the matrix slide");
assert_eq!(g3d5["component"], "graph3d");
assert_eq!(g3d5["n"], 5);
assert_eq!(g3d5["status"], "wired", "facet-graph3d-5 is raised by Graph3D, not merely reserved");
assert!(
g3d5["message"].as_str().unwrap().contains("given"),
"the message names the `given` layout it degrades from, got {}",
g3d5["message"],
);
// Every graph3d code the registry knows is surfaced here (1..=5 today) — the
// per-component enumeration, so a NEW graph3d code cannot land unseen either.
let graph3d_codes: Vec<u64> =
matrix.iter().filter(|r| r["component"] == "graph3d").map(|r| r["n"].as_u64().unwrap()).collect();
let registry_graph3d: Vec<u64> =
errcode::registry().iter().filter(|e| e.component == "graph3d").map(|e| e.n as u64).collect();
assert_eq!(graph3d_codes, registry_graph3d, "the showcase enumerates EVERY graph3d code");
assert!(graph3d_codes.contains(&5), "…including the host-placement fallback -5");
// The consumer mount-prefix demo is present (Phase-2 hook).
assert_eq!(errors["mount_example"]["cases"], "korp/cases:facet-demo-1");
// 2. Pink-on-screen flag: true in a debug (non-release) test build.
assert_eq!(errors["code_visible_onscreen"], cfg!(debug_assertions));
}
#[test]
fn about_popup_carries_git_hash_and_a_source_per_component() {
let demo = DemoState::new();
let about = demo.about_json();
// The WHICH-build stamp.
assert!(about["git_hash"].as_str().is_some());
assert!(about["version"].as_str().unwrap().contains("facett-demo v"));
assert_eq!(about["errcode_scheme"], "facet-<component>-<n>");
// A source link per facet-component.
let sources = about["source_links"].as_array().expect("source links");
assert_eq!(sources.len(), errcode::components().len());
for s in sources {
assert!(s["source_url"].as_str().unwrap().starts_with("https://gunnar.rs/nordisk/facett/blob/main/"));
}
// Every named facet-component has a source link.
let comps: Vec<&str> = sources.iter().map(|s| s["component"].as_str().unwrap()).collect();
for want in ["map", "map3d", "geomap", "graph3d", "graphview", "systemmap", "cfd", "korp"] {
assert!(comps.contains(&want), "component {want} missing from About source links");
}
}
#[test]
fn errors_tab_renders_pink_code_atoms_into_the_accesskit_tree() {
// Drive JUST the Errors tab (cheap) through a real harness and prove the code
// atoms reach the AccessKit tree — the code is readable off the tree, not pixels.
let mut demo = DemoState::new();
assert!(demo.deck.set_active_by_title("Errors"), "activate the Errors tab");
let mut harness = Harness::new_ui(move |ui| {
demo.deck.ui(ui);
});
harness.run_steps(3);
// The demo error codes appear as atoms (render_demo emits a "code facet-demo-N"
// label; the matrix renders the code strings as labels).
let hits = harness.query_all(By::new().label_contains("facet-demo-1")).count();
assert!(hits > 0, "the pink code facet-demo-1 reached the AccessKit tree");
}