facett-card/tests/a11y.rs
//! **FC-4 interaction-layer proof for facett-card.** Render a real [`CardView`]
//! whose read view paints an enum *chip* and a user *avatar* through
//! `egui_kittest`, then assert each painter-only element rode into the AccessKit
//! tree as a queryable, labelled node.
//!
//! Before FC-4 the chip (`painter.rect_*` + `painter.galley`) and the avatar
//! (`painter.circle_*` + `painter.text`) emitted **zero** accesskit nodes —
//! invisible to `get_by_label` / a robot driver / a screen reader. This proves
//! the per-element `facett_core::a11y::node` calls (keyed on the chip text / the
//! user name — a stable domain key, not a loop index, FC-5) make them findable,
//! labelled, and (for the enum chip) value-carrying.
use egui::accesskit::Role;
use egui_kittest::Harness;
use egui_kittest::kittest::{NodeT, Queryable};
use facett_core::Facet;
use facett_card::{Card, CardField, CardView, FieldValue};
/// A read-mode card with one enum field (→ chip) and one user field (→ avatar),
/// using labels that don't collide with the grid's label column.
fn card() -> Card {
Card::new("Investigate vessel Nordkapp")
.with_id("CASE-42")
.field(CardField::new(
"Status",
FieldValue::Enum {
// The chip paints "escalated"; the option set has three states,
// which rides into the node as numeric_value (3.0).
state: "escalated".into(),
options: vec!["open".into(), "escalated".into(), "closed".into()],
},
))
.field(CardField::new("Assignee", FieldValue::User("hugin".into())))
}
#[test]
fn painted_chip_and_avatar_enter_the_accesskit_tree() {
let mut view = CardView::new("Issue", card());
assert!(!view.is_editing(), "starts in read mode so the chip + avatar paint");
let mut harness = Harness::new_ui(move |ui| {
view.ui(ui);
});
harness.run();
// The enum chip: a painter-only pill is now a queryable Label node carrying
// its option-set size (3) as numeric_value. "escalated" is unique on the
// surface (no grid label/value collides), so get_by_label resolves it.
let chip = harness.get_by_label("escalated").accesskit_node();
assert_eq!(
chip.role(),
Role::Label,
"the painted enum chip must expose a Label role in the AccessKit tree (FC-4)"
);
assert_eq!(
chip.numeric_value(),
Some(3.0),
"the enum chip carries its option-set size as numeric_value"
);
// The avatar paints only the initial 'H', but its AccessKit node carries the
// *full* name "hugin". The read view also renders a plain `ui.label("hugin")`
// beside it, so after FC-4 there are TWO nodes labelled "hugin" (the label +
// the avatar). Before FC-4 there was exactly one — proving the avatar entered
// the tree. Both are Label-role.
let huginen = harness.get_all_by_label("hugin");
let labels: Vec<_> = huginen.collect();
assert_eq!(
labels.len(),
2,
"the avatar's a11y node joins the plain name label → two 'hugin' nodes (FC-4)"
);
for n in &labels {
assert_eq!(
n.accesskit_node().role(),
Role::Label,
"both the name label and the avatar node are Label-role"
);
}
#[cfg(feature = "testmatrix")]
facett_core::testmatrix::emit(
"CardView",
"fc4_chip_and_avatar_nodes",
chip.numeric_value() == Some(3.0) && labels.len() == 2,
"enum chip Label value=3, avatar 'hugin' joins name label (2 nodes)",
);
}