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

nordisk/facett

facett-korp/tests/graph_render.rs

//! Real `egui_kittest` render + click proof for the korp **GraphPane** — the
//! visible (watch-on-DISPLAY) leg of the robot scenario the headless `update_json`
//! drive covers. The pane paints its query bar + expand/path controls, and a real
//! click on the *Run query* button drives the Elm loop to emit a `RunQuery` effect.

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

use egui_kittest::Harness;
use egui_kittest::kittest::Queryable;
use facett_core::{Elm, Panel};
use facett_korp::{CentralityRow, GraphEffect, GraphMsg, GraphNodeRef, GraphPane};

fn seeded() -> GraphPane {
    let mut p = GraphPane::new("Graph");
    p.sync_scene(
        vec![GraphNodeRef::new(1, "Person"), GraphNodeRef::new(2, "Company")],
        1,
    );
    p
}

#[test]
fn graph_pane_paints_the_controls() {
    let mut pane = seeded();
    let mut harness = Harness::builder().with_size(egui::vec2(520.0, 420.0)).build_ui(move |ui| {
        Panel::ui(&mut pane, ui);
    });
    harness.run();
    // The Run button rode into the AccessKit tree as a queryable widget.
    assert!(harness.query_by_label("▶ Run query").is_some(), "the query bar painted");
}

#[test]
fn clicking_run_emits_a_run_query_effect() {
    let effects: Arc<Mutex<Vec<GraphEffect>>> = Arc::new(Mutex::new(Vec::new()));
    let sink = Arc::clone(&effects);
    let mut pane = seeded();
    let mut harness = Harness::builder().with_size(egui::vec2(520.0, 420.0)).build_ui(move |ui| {
        // The host wiring: view emits msgs, update yields effects → record them.
        let msgs = pane.view(ui);
        for m in msgs {
            for e in pane.update(m) {
                sink.lock().unwrap().push(e);
            }
        }
    });
    harness.run();
    harness.get_by_label("▶ Run query").click();
    harness.run();

    let got = effects.lock().unwrap();
    assert!(
        matches!(got.first(), Some(GraphEffect::RunQuery(_))),
        "a real click on Run drove the Elm loop to emit RunQuery, got {got:?}",
    );
}

#[test]
fn centrality_readout_paints_the_ranked_broker() {
    // Host feeds the P5-path scores: node #3 is the top broker.
    let mut pane = seeded();
    pane.sync_centrality(
        vec![
            CentralityRow::new(3, "N3", 2, 4.0, 0),
            CentralityRow::new(2, "N2", 2, 3.0, 0),
            CentralityRow::new(4, "N4", 2, 3.0, 1),
        ],
        1,
        2,
        0.25,
    );
    // headless assertion first: the top broker rode into state_json.
    assert_eq!(Panel::state_json(&pane)["top_central_id"], 3);
    assert_eq!(Panel::state_json(&pane)["communities"], 2);
    let mut harness = Harness::builder().with_size(egui::vec2(520.0, 560.0)).build_ui(move |ui| {
        Panel::ui(&mut pane, ui);
    });
    harness.run();
    // The L-5 readout painted: its heading + the component/community line + the top
    // row's caption (incl. its Louvain community tag) all rode into the AccessKit tree.
    assert!(harness.query_by_label("Centrality (L-5)").is_some(), "the readout heading painted");
    assert!(
        harness.query_by_label("1 connected components · 2 communities (Q 0.25)").is_some(),
        "the component + community count painted",
    );
    assert!(
        harness.query_by_label("N3 #3  deg 2 · btw 4.0 · c0").is_some(),
        "the ranked broker row painted with its community tag",
    );
}

#[test]
fn crossfilter_status_paints_when_a_timeline_brush_crops_the_graph() {
    // Host reports: a timeline brush cropped the scene to 2 of 5 nodes (G-9).
    let mut pane = seeded();
    pane.sync_crossfilter(true, 2, 5, 3);
    assert_eq!(Panel::state_json(&pane)["crossfilter"]["active"], true);
    let mut harness = Harness::builder().with_size(egui::vec2(560.0, 480.0)).build_ui(move |ui| {
        Panel::ui(&mut pane, ui);
    });
    harness.run();
    assert!(
        harness
            .query_by_label("⏱ timeline cross-filter: showing 2 of 5 nodes (3 subjects in window)")
            .is_some(),
        "the G-9 cross-filter status painted",
    );
}

#[test]
fn graph_pane_paints_after_json_drive() {
    let mut pane = seeded();
    Panel::update_json(&mut pane, r#"{"select_expand":0}"#);
    Panel::update_json(&mut pane, "\"expand\"");
    assert_eq!(Panel::state_json(&pane)["expand_id"], 1);
    let mut harness = Harness::builder().with_size(egui::vec2(520.0, 420.0)).build_ui(move |ui| {
        Panel::ui(&mut pane, ui);
    });
    harness.run();
    let _ = GraphMsg::Clear; // msg type is public/constructible
}