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

nordisk/facett

facett-about/tests/robot.rs

//! **Robot render+dismiss scenario for the shared About card** (`egui_kittest`).
//!
//! Renders the REAL [`facett_about::draw_about_window`] body with a sample
//! [`Identity`] and asserts, off the live AccessKit tree, that the surface a robot
//! (or a screen reader) sees is the branding surface — the **logo alt-text**, the
//! **wordmark** heading, the **v{version}** line, and a **framework** bullet all
//! paint — then drives a **real Close click** and proves the window dismisses
//! (`open → false`, and `draw_about_window` returns its dismiss flag `true`).
//!
//! This is the L4 UI proof for the whole suite's About surface: korp/holger delete
//! their egui body and drive THIS one, so this test guards their About too.
//!
//! RED-when-broken (verified by neutralizing): if the logo binding, the wordmark,
//! the version line, or the Close teardown regressed, an assertion below goes red.
//! One matrix cell `facett-about/window`.

use std::sync::{Arc, Mutex};

use egui_kittest::Harness;
use egui_kittest::kittest::Queryable;
use facett_about::{draw_about_window, logo_texture, Identity};

const LOGO_ALT: &str = "TestApp logo — two ravens";
const WORDMARK: &str = "TestApp";
const VERSION: &str = "9.9.9";
const FRAMEWORK_LINE: &str = "jera — the shared job manager";

/// A tiny real PNG so the logo decodes to a texture (the hero image paints with
/// its alt-text, not the text-only fallback).
fn tiny_png() -> Vec<u8> {
    let img = image::RgbaImage::from_pixel(3, 3, image::Rgba([200, 30, 30, 255]));
    let mut buf = std::io::Cursor::new(Vec::new());
    image::DynamicImage::ImageRgba8(img)
        .write_to(&mut buf, image::ImageFormat::Png)
        .expect("encode tiny PNG");
    buf.into_inner()
}

/// A holger-shaped identity (version line + framework list) carrying a real logo.
fn sample_identity(logo: Option<Vec<u8>>) -> Identity {
    Identity {
        subtitle: "the shared About card, robot-tested".into(),
        logo_png: logo,
        logo_alt: LOGO_ALT.into(),
        framework: vec![FRAMEWORK_LINE.into()],
        engines: vec!["Hugin & Munin — two ravens in black vector metal".into()],
        ..Identity::new("testapp", WORDMARK, VERSION, "a test tagline")
    }
}

/// Emit shim (real row with `--features testmatrix`, no-op otherwise).
#[cfg(feature = "testmatrix")]
fn emit(check: &str, ok: bool, detail: &str) {
    nornir_testmatrix::functional_status("facett-about", check, ok, detail);
}
#[cfg(not(feature = "testmatrix"))]
fn emit(_check: &str, _ok: bool, _detail: &str) {}

#[test]
fn about_window_paints_identity_and_close_dismisses() {
    let open = Arc::new(Mutex::new(true));
    let dismissed = Arc::new(Mutex::new(false));
    let logo_bytes = tiny_png();

    let mut harness = Harness::builder().with_size(egui::vec2(680.0, 600.0)).build_ui({
        let open = Arc::clone(&open);
        let dismissed = Arc::clone(&dismissed);
        move |ui| {
            // The identity + decoded logo the app would hold; rebuilt per frame in
            // the test (load_texture just re-registers under the same name).
            let id = sample_identity(Some(logo_bytes.clone()));
            let logo = logo_texture(ui.ctx(), &id);
            let mut o = open.lock().unwrap();
            let d = draw_about_window(ui.ctx(), &mut o, &id, logo.as_ref(), 360.0);
            if d {
                *dismissed.lock().unwrap() = true;
            }
        }
    });
    harness.run();

    // The branding surface painted: logo (by its alt-text), wordmark, version, and
    // a framework bullet all rode into the AccessKit tree.
    let version_label = format!("v{VERSION}");
    let framework_label = format!("· {FRAMEWORK_LINE}");
    let logo_seen = harness.query_by_label(LOGO_ALT).is_some();
    let wordmark_seen = harness.query_by_label(WORDMARK).is_some();
    let version_seen = harness.query_by_label(version_label.as_str()).is_some();
    let framework_seen = harness.query_by_label(framework_label.as_str()).is_some();
    assert!(logo_seen, "the logo painted with its alt-text (a11y + robot-observable)");
    assert!(wordmark_seen, "the wordmark heading painted");
    assert!(version_seen, "the v{VERSION} line painted");
    assert!(framework_seen, "a framework bullet painted (holger's shared-framework list)");

    // Drive a real Close click → the window dismisses.
    harness.get_by_label("Close").click();
    harness.run();

    let still_open = *open.lock().unwrap();
    let got_dismissed = *dismissed.lock().unwrap();
    assert!(!still_open, "Close set open→false");
    assert!(got_dismissed, "draw_about_window returned its dismiss flag on the Close frame");

    emit(
        "window",
        logo_seen && wordmark_seen && version_seen && framework_seen && !still_open && got_dismissed,
        &format!(
            "logo={logo_seen} wordmark={wordmark_seen} version={version_seen} \
             framework={framework_seen} closed={} dismissed={got_dismissed}",
            !still_open
        ),
    );
}

/// A closed card draws nothing and reports not-dismissed (the `*open == false`
/// early-out) — a robot never finds the wordmark when the toggle is off.
#[test]
fn closed_card_paints_nothing() {
    let mut open = false;
    let harness_open = Arc::new(Mutex::new(open));
    let mut harness = Harness::builder().build_ui({
        let harness_open = Arc::clone(&harness_open);
        move |ui| {
            let id = sample_identity(Some(tiny_png()));
            let mut o = harness_open.lock().unwrap();
            let d = draw_about_window(ui.ctx(), &mut o, &id, None, 360.0);
            assert!(!d, "a closed card never reports a dismiss");
        }
    });
    harness.run();
    assert!(harness.query_by_label(WORDMARK).is_none(), "a closed card paints no wordmark");
    let _ = &mut open;
}