mobius-cli 0.9.16

The terminal client for a möbius gateway
Documentation
use super::support::*;
use super::*;

#[test]
fn live_transcript_preview_uses_the_full_frame_and_new_entries() {
    let mut state = state();
    state.transcript.clear();
    state.open_transcript_preview();
    state.push_entry("new live row".into(), TranscriptTone::Neutral);
    let mut terminal = Terminal::new(TestBackend::new(40, 16)).expect("terminal");

    terminal
        .draw(|frame| view::render_preview(frame, &mut state))
        .expect("preview draw");
    let rendered = terminal.backend().to_string();

    assert!(rendered.contains("new live row"));
    assert!(
        rendered
            .lines()
            .next()
            .is_some_and(|line| line.contains('')),
        "{rendered}"
    );
    assert!(
        rendered
            .lines()
            .last()
            .is_some_and(|line| line.contains('')),
        "{rendered}"
    );
}

#[test]
fn snapshot_preview_scrolls_with_the_mouse_wheel() {
    let mut state = state();
    events::handle_gateway_event(
        &mut state,
        recorded(
            EventMsg::ContextCompacted,
            Vec::new(),
            Some(RenderedPreview {
                id: "/root/subagent".into(),
                title: "subagent".into(),
                subtitle: String::new(),
                page_id: "subagent:latest".into(),
                update: mobius::protocol::FrontendPreviewUpdate::Replace,
                events: (0..30)
                    .map(|index| RenderedEvent {
                        recorded_at_ms: i64::from(index),
                        event: EventMsg::UserMessage(mobius::protocol::UserMessageEvent {
                            message: format!("subagent row {index}"),
                            attachments: Vec::new(),
                            message_target: None,
                        }),
                        blocks: Vec::new(),
                    })
                    .collect(),
                next: None,
            }),
        ),
    );
    let mut terminal = Terminal::new(TestBackend::new(40, 10)).expect("terminal");
    terminal
        .draw(|frame| view::render_preview(frame, &mut state))
        .expect("preview draw");
    let bottom = terminal.backend().to_string();
    assert!(bottom.contains("subagent row 29"), "{bottom}");

    assert!(!state.handle_mouse(MouseEvent {
        kind: MouseEventKind::Moved,
        column: 0,
        row: 0,
        modifiers: KeyModifiers::NONE,
    }));
    assert!(state.handle_mouse(MouseEvent {
        kind: MouseEventKind::ScrollUp,
        column: 0,
        row: 0,
        modifiers: KeyModifiers::NONE,
    }));
    terminal
        .draw(|frame| view::render_preview(frame, &mut state))
        .expect("scrolled preview draw");
    let scrolled = terminal.backend().to_string();
    assert!(scrolled.contains("subagent row 24"), "{scrolled}");
    assert!(!scrolled.contains("subagent row 29"), "{scrolled}");

    state.handle_mouse(MouseEvent {
        kind: MouseEventKind::ScrollDown,
        column: 0,
        row: 0,
        modifiers: KeyModifiers::NONE,
    });
    terminal
        .draw(|frame| view::render_preview(frame, &mut state))
        .expect("restored preview draw");
    let restored = terminal.backend().to_string();
    assert!(restored.contains("subagent row 29"), "{restored}");
}

#[test]
fn snapshot_preview_prepends_an_older_page_without_losing_the_latest_page() {
    let mut state = state();
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/agent",
            "latest",
            FrontendPreviewUpdate::Replace,
            &["latest"],
            Some(preview_continuation("older")),
        ),
    );
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/agent",
            "older",
            FrontendPreviewUpdate::Prepend,
            &["older"],
            None,
        ),
    );

    let snapshot = snapshot(&state);
    assert_eq!(
        (
            snapshot.id.as_str(),
            snapshot.page_ids.len(),
            preview_messages(snapshot),
            snapshot.next.as_ref(),
        ),
        ("/root/agent", 2, vec!["› older", "› latest"], None,)
    );
}

#[test]
fn snapshot_preview_deduplicates_page_ids() {
    let mut state = state();
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/agent",
            "latest",
            FrontendPreviewUpdate::Replace,
            &["latest"],
            None,
        ),
    );
    for message in ["older", "duplicate"] {
        events::handle_gateway_event(
            &mut state,
            preview_record(
                "/root/agent",
                "older",
                FrontendPreviewUpdate::Prepend,
                &[message],
                None,
            ),
        );
    }

    assert_eq!(
        preview_messages(snapshot(&state)),
        vec!["› older", "› latest"]
    );
}

#[test]
fn snapshot_preview_replace_refreshes_a_reused_latest_page_id() {
    let mut state = state();
    for message in ["stale", "fresh"] {
        events::handle_gateway_event(
            &mut state,
            preview_record(
                "/root/agent",
                "latest",
                FrontendPreviewUpdate::Replace,
                &[message],
                None,
            ),
        );
    }

    assert_eq!(preview_messages(snapshot(&state)), vec!["› fresh"]);
}

#[test]
fn snapshot_preview_does_not_merge_a_page_for_another_preview_id() {
    let mut state = state();
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/agent",
            "latest",
            FrontendPreviewUpdate::Replace,
            &["latest"],
            None,
        ),
    );
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/other",
            "older",
            FrontendPreviewUpdate::Prepend,
            &["wrong preview"],
            None,
        ),
    );

    let snapshot = snapshot(&state);
    assert_eq!(
        (snapshot.id.as_str(), preview_messages(snapshot)),
        ("/root/agent", vec!["› latest"])
    );
}

#[test]
fn snapshot_preview_older_key_submits_the_retained_continuation() {
    let mut state = state();
    let next = preview_continuation("older");
    events::handle_gateway_event(
        &mut state,
        preview_record(
            "/root/agent",
            "latest",
            FrontendPreviewUpdate::Replace,
            &["latest"],
            Some(next.clone()),
        ),
    );
    let mut terminal = Terminal::new(TestBackend::new(120, 10)).expect("terminal");
    terminal
        .draw(|frame| view::render_preview(frame, &mut state))
        .expect("preview draw");
    let rendered = terminal.backend().to_string();
    let action = state.handle_key(
        KeyEvent::new(KeyCode::Char('o'), KeyModifiers::NONE),
        &default_catalog(),
    );
    let retained = snapshot(&state).next.as_ref();

    assert_eq!(
        (rendered.contains("O older"), action, retained),
        (true, UiAction::Submit(next.clone()), Some(&next))
    );
}