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

nordisk/facett

facett-cfd/tests/robot.rs

//! **Robot render proof for facett-cfd.** The `Cfd::ui()` render path — the
//! stacked-quad area fill (the `tops` cumulative geometry), the axes, the
//! date labels and the color legend — is never touched by the unit tests, and
//! the `<2 snapshots` placeholder branch has its own early return. This drives
//! both paths through a real `egui_kittest` frame so a geometry panic (e.g. the
//! `n - 1` divisor when a stray single-snapshot slips through) is caught, and
//! asserts the heading / placeholder text reach the AccessKit tree.

use std::collections::BTreeMap;

use chrono::NaiveDate;
use egui_kittest::Harness;
use egui_kittest::kittest::Queryable;

use facett_cfd::{Band, Cfd, Snapshot};

fn d(y: i32, m: u32, day: u32) -> NaiveDate {
    NaiveDate::from_ymd_opt(y, m, day).unwrap()
}

fn snap(date: NaiveDate, todo: usize, doing: usize, done: usize) -> Snapshot {
    let mut counts = BTreeMap::new();
    counts.insert("todo".to_string(), todo);
    counts.insert("doing".to_string(), doing);
    counts.insert("done".to_string(), done);
    Snapshot { date, counts }
}

fn cfd() -> Cfd {
    let mut c = Cfd::new(
        "Flow",
        vec![Band::new("todo", "To do"), Band::new("doing", "Doing"), Band::new("done", "Done")],
    );
    c.set_series(vec![
        snap(d(2026, 6, 1), 8, 1, 0),
        snap(d(2026, 6, 3), 5, 2, 2),
        snap(d(2026, 6, 5), 3, 3, 4),
    ]);
    c
}

#[test]
fn cfd_renders_the_stacked_area_and_is_addressable() {
    let mut c = cfd();
    let mut harness = Harness::new_ui(move |ui| {
        c.ui(ui);
    });
    // The full render: cumulative band quads, axes, date labels, the legend.
    harness.run();

    // The heading + at least one legend label reached the AccessKit tree.
    let _heading = harness.get_by_label("Flow");
    let _legend = harness.get_by_label("Doing");
}

#[test]
fn cfd_placeholder_path_renders_below_two_snapshots() {
    // Zero snapshots → the "need ≥2 daily snapshots" placeholder, not the area.
    let mut empty = Cfd::new("Flow", vec![Band::new("todo", "To do")]);
    let mut harness = Harness::new_ui(move |ui| {
        empty.ui(ui);
    });
    harness.run();
    let _placeholder = harness.get_by_label("Not enough data yet — need ≥2 daily snapshots.");

    // Exactly one snapshot → still the placeholder (never reaches the `n - 1`
    // divisor), proving the guard holds at the boundary.
    let mut one = Cfd::new("Flow", vec![Band::new("todo", "To do")]);
    let mut counts = BTreeMap::new();
    counts.insert("todo".to_string(), 3usize);
    one.set_series(vec![Snapshot { date: d(2026, 6, 1), counts }]);
    let mut h2 = Harness::new_ui(move |ui| {
        one.ui(ui);
    });
    h2.run();
    let _p2 = h2.get_by_label("Not enough data yet — need ≥2 daily snapshots.");
}

#[test]
fn cfd_state_survives_a_render() {
    let c = cfd();
    let before = c.state_json();
    let mut c2 = cfd();
    let mut harness = Harness::new_ui(move |ui| {
        c2.ui(ui);
    });
    harness.run();
    assert_eq!(before["snapshots"], 3);
    // totals per snapshot: 9, 9, 10 → max 10.
    assert_eq!(before["max_total"], 10);
    assert_eq!(cfd().state_json(), before);
}