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

nordisk/facett

facett-demo/tests/responsive_fold.rs

//! **facett-demo — the responsive MOBILE/WASM fold proof (#30)** (headless, no window).
//!
//! The deployed wasm demo showed every control button but the demo CANVAS sat BELOW
//! the phone screen fold: the control strip (look / native / palette pickers + the fx +
//! region buttons) is a fixed strip that wraps into many rows and eats a narrow
//! viewport. `draw_app` now classifies the viewport width through the SHARED scene
//! machinery ([`facett_app::scene::Device`]) and, on a phone-class width, FOLDS the whole
//! strip behind a `⚙` drawer (default closed) so the CANVAS gets the screen (canvas-first).
//!
//! This drives the exact `DemoState::draw_app` render path the eframe binary uses, at a
//! phone-width and a desktop-width viewport, and asserts the fold as DATA read back from
//! `state_json.shell`. RED-when-broken: if the strip stops folding on a phone the canvas
//! is shoved down (its height fraction collapses) and `controls_folded` goes false.

use facett_demo::DemoState;
use std::cell::RefCell;
use std::rc::Rc;

/// Run `draw_app` at a given viewport size (optionally with the phone drawer forced
/// open) and return the demo's `state_json.shell` object.
fn shell_at(width: f32, height: f32, drawer_open: bool) -> serde_json::Value {
    let mut demo = DemoState::new();
    demo.controls_open = drawer_open;
    let cell = Rc::new(RefCell::new(serde_json::Value::Null));
    let c = cell.clone();
    let mut h = egui_kittest::Harness::builder()
        .with_size(egui::vec2(width, height))
        .build_ui_state(
            move |ui, demo: &mut DemoState| {
                demo.draw_app(ui);
                *c.borrow_mut() = demo.state_json();
            },
            demo,
        );
    // The live sim requests a repaint every frame, so drive a few fixed frames
    // (deferred fit / layout settles) instead of `run()`-to-quiescence.
    h.run_steps(4);
    let s = cell.borrow();
    s["shell"].clone()
}

#[test]
fn phone_viewport_folds_the_controls_and_gives_the_canvas_the_screen() {
    // ── PHONE (380 pt wide, drawer default CLOSED) ──────────────────────────────────
    // The strip folds behind the `⚙` drawer: the shell reports phone-class + folded,
    // and the canvas (deck) OWNS most of the viewport height — it is NOT below the fold.
    let phone = shell_at(380.0, 780.0, false);
    eprintln!("[responsive] phone(folded) shell = {phone}");
    assert_eq!(phone["device"], "phone", "a 380 pt viewport is phone-class");
    assert_eq!(phone["controls_folded"], true, "phone-class + drawer shut ⇒ the control strip folds away");
    let phone_canvas = phone["canvas_height_frac"].as_f64().unwrap();
    let phone_top = phone["canvas_top_frac"].as_f64().unwrap();
    assert!(phone_canvas > 0.7, "the canvas owns most of the phone viewport height (got {phone_canvas:.3})");
    assert!(phone_top < 0.2, "the canvas starts near the top — not pushed below the fold (top_frac {phone_top:.3})");

    // ── PHONE, drawer OPEN ─────────────────────────────────────────────────────────
    // Opening the `⚙` drawer un-folds the strip; the many control rows now eat into the
    // viewport, so the canvas gets LESS of the screen than when folded. This is the
    // whole point of the fold: closing it RECLAIMS the canvas.
    let phone_open = shell_at(380.0, 780.0, true);
    eprintln!("[responsive] phone(open)   shell = {phone_open}");
    assert_eq!(phone_open["controls_folded"], false, "an open drawer un-folds the strip");
    let open_canvas = phone_open["canvas_height_frac"].as_f64().unwrap();
    assert!(
        phone_canvas > open_canvas,
        "folding the strip RECLAIMS canvas: folded {phone_canvas:.3} > open {open_canvas:.3}"
    );

    // ── DESKTOP (1280 pt wide) ──────────────────────────────────────────────────────
    // A wide viewport is desktop-class: the control strip is always shown (never folded).
    let desk = shell_at(1280.0, 820.0, false);
    eprintln!("[responsive] desktop       shell = {desk}");
    assert_eq!(desk["device"], "desktop", "a 1280 pt viewport is desktop-class");
    assert_eq!(desk["controls_folded"], false, "desktop always shows the control strip");

    #[cfg(feature = "testmatrix")]
    facett_core::testmatrix::emit(
        "facett-demo",
        "responsive_fold_30",
        phone["controls_folded"] == true && phone_canvas > 0.7 && desk["controls_folded"] == false,
        &format!(
            "phone_canvas={phone_canvas:.3} phone_open_canvas={open_canvas:.3} desktop_folded={}",
            desk["controls_folded"]
        ),
    );
}