Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

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)",
    );
}