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

nordisk/facett

facett-toast/tests/matrix.rs

//! **The functional matrix cell for facett-toast** — the pane emitted NO
//! testmatrix row of either aspect before this file (see
//! `.nornir/docs/test-matrix-inventory-history.md`, "~10 panes emit no cell").
//!
//! ONE call through the shared generic-`Facet` probe (L5) — no bespoke harness.
//! The toast stack is an OVERLAY (it paints into a ctx `Area`, not the inline
//! `Ui`), which is exactly why it had no render cell: the probe's `Facet::ui`
//! adapter forwards `ui.ctx()` so the overlay tessellates in the same frame.

use facett_toast::Toasts;

#[test]
fn toasts_probe_emits_render_and_input_cells() {
    let mut view = Toasts::local();

    let script = [
        r#"{"push":{"text":"Nytt beslut","level":"Error","ttl":9.0,"case":"BL-13"}}"#,
        r#"{"tick":5.0}"#, // ages the stack — the 4.0s Success toast expires
        r#""clear""#,
    ];
    let probe = facett_core::testmatrix::probe_and_emit("facett-toast", &mut view, &script);

    assert!(probe.drew(), "the toast overlay must tessellate to vertices");
    assert!(probe.cardinality() > 0, "state_json reports the stack");
    assert!(probe.responded(), "update_json must drive state — a dead seam is a regression");

    assert_eq!(probe.initial_state["count"], 4);
    assert_eq!(probe.steps[0].state["count"], 5);
    // EXACT expiry contract: tick(5.0) drops every toast whose ttl was ≤ 5.0
    // (Sparat 4.0 and 3 nya ärenden 5.0) and keeps the three longer ones.
    assert_eq!(probe.steps[1].state["count"], 3, "tick expires the short-lived toasts");
    assert_eq!(probe.steps[2].state["count"], 0, "clear empties the stack");
}

/// RED-when-broken: `tick` must decay each toast by EXACTLY the elapsed time and
/// evict at zero — a loose "count went down" oracle would pass a decay that
/// dropped the wrong toasts.
#[test]
fn tick_decays_each_remaining_toast_by_the_exact_elapsed_time() {
    let mut t = Toasts::local();
    let before: Vec<f64> = t.state_json()["toasts"]
        .as_array()
        .unwrap()
        .iter()
        .map(|x| x["remaining"].as_f64().unwrap())
        .collect();
    assert_eq!(before, vec![4.0, 6.0, 8.0, 5.0]);

    t.tick(3.5);
    let after: Vec<f64> = t.state_json()["toasts"]
        .as_array()
        .unwrap()
        .iter()
        .map(|x| x["remaining"].as_f64().unwrap())
        .collect();
    assert_eq!(after.len(), 4, "nothing expires before its ttl");
    for (b, a) in before.iter().zip(&after) {
        assert!((b - a - 3.5).abs() < 1e-5, "each toast decays by exactly 3.5s: {b} → {a}");
    }

    t.tick(1.0); // the 4.0s toast now hits 0.5-1.0 < 0 → evicted
    assert_eq!(t.len(), 3);
    t.tick(100.0);
    assert!(t.is_empty(), "everything expires eventually");
}