use pathfinder_geometry::vector::Vector2F;use warpui::SingletonEntity;use warpui::integration::TestStep;use warpui::windowing::WindowManager; use crate::ai::blocklist::agent_view::AgentInputFooterEvent;use crate::ai::blocklist::{InputConfig, InputType};use crate::integration_testing::input::{inline_model_selector_is_open, input_is_empty};use crate::integration_testing::step::new_step_with_default_assertions;use crate::integration_testing::terminal::assert_context_menu_is_open;use crate::integration_testing::view_getters::{ single_input_view_for_tab, single_terminal_view, single_terminal_view_for_tab,};use crate::terminal::CLIAgent;use crate::terminal::cli_agent_sessions::{ CLIAgentInputEntrypoint, CLIAgentInputState, CLIAgentSession, CLIAgentSessionContext, CLIAgentSessionStatus, CLIAgentSessionsModel,};use crate::terminal::input::models::InlineModelSelectorTab;use crate::terminal::view::TerminalAction; /// Opens the CLI-agent Rich Input for the terminal view at `tab_index`.pub fn open_cli_agent_rich_input(tab_index: usize) -> TestStep { new_step_with_default_assertions("Open CLI Agent Rich Input").with_action( move |app, window_id, _step_data| { let terminal_view = single_terminal_view_for_tab(app, window_id, tab_index); terminal_view.update(app, |view, ctx| { let view_id = view.view_id(); CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| { sessions.set_session( view_id, CLIAgentSession { agent: CLIAgent::Claude, status: CLIAgentSessionStatus::InProgress, session_context: CLIAgentSessionContext::default(), input_state: CLIAgentInputState::Closed, should_auto_toggle_input: false, listener: None, remote_host: None, plugin_version: None, draft_text: None, custom_command_prefix: None, received_rich_notification: false, }, ctx, ); }); CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| { sessions.open_input( view_id, CLIAgentInputEntrypoint::CtrlG, InputConfig { input_type: InputType::AI, is_locked: true, }, false, false, ctx, ); }); }); }, )} /// Asserts that the Rich Input buffer text for `tab_index` is empty.pub fn rich_input_buffer_text_is_empty(tab_index: usize) -> warpui::integration::AssertionCallback { Box::new(move |app, window_id| { let input_view = single_input_view_for_tab(app, window_id, tab_index); input_view.read(app, |view, ctx| { let text = view.buffer_text(ctx); warpui::async_assert!( text.is_empty(), "Expected Rich Input buffer to be empty; got: {text:?}" ) }) })} /// Asserts that the Rich Input buffer text for `tab_index` contains a newline character.pub fn rich_input_buffer_contains_newline( tab_index: usize,) -> warpui::integration::AssertionCallback { Box::new(move |app, window_id| { let input_view = single_input_view_for_tab(app, window_id, tab_index); input_view.read(app, |view, ctx| { let text = view.buffer_text(ctx); warpui::async_assert!( text.contains('\n'), "Expected Rich Input buffer to contain a newline; got: {text:?}" ) }) })} /// Asserts that the Rich Input buffer for `tab_index` contains no newline (verifies menu-acceptance, not newline insertion).pub fn rich_input_buffer_does_not_contain_newline( tab_index: usize,) -> warpui::integration::AssertionCallback { Box::new(move |app, window_id| { let input_view = single_input_view_for_tab(app, window_id, tab_index); input_view.read(app, |view, ctx| { let text = view.buffer_text(ctx); warpui::async_assert!( !text.contains('\n'), "Expected Rich Input buffer to NOT contain a newline; got: {text:?}" ) }) })} pub fn open_input_context_menu() -> TestStep { new_step_with_default_assertions("Open input context menu") .with_action(move |app, _, _| { let window_id = app.read(|ctx| { WindowManager::as_ref(ctx) .active_window() .expect("no active window") }); let terminal_view_id = single_terminal_view(app, window_id).id(); app.dispatch_typed_action( window_id, &[terminal_view_id], &TerminalAction::OpenInputContextMenu { position: Vector2F::new(8.5, 8.5), }, ); }) .add_assertion(assert_context_menu_is_open(true))} /// Toggles the inline model selector by emitting the same footer event the model/// chip emits when clicked, exercising the real `Input` event-handling path.pub fn toggle_inline_model_selector_from_chip() -> TestStep { new_step_with_default_assertions("Toggle inline model selector from model chip").with_action( |app, window_id, _| { let input = single_input_view_for_tab(app, window_id, 0); let footer = input.read(app, |view, _| view.agent_input_footer().clone()); footer.update(app, |_, ctx| { ctx.emit(AgentInputFooterEvent::ToggleInlineModelSelector { initial_tab: InlineModelSelectorTab::BaseAgent, }); }); }, )} /// Opens the inline model selector from the model chip and asserts it opened with/// a cleared input buffer (so the input can be used to search models).pub fn open_inline_model_selector_from_chip() -> TestStep { toggle_inline_model_selector_from_chip() .add_named_assertion( "Inline model selector is open", inline_model_selector_is_open(0), ) .add_named_assertion("Prompt is cleared for model search", input_is_empty(0))}
use pathfinder_geometry::vector::Vector2F;
use warpui::SingletonEntity;
use warpui::integration::TestStep;
use warpui::windowing::WindowManager;
use crate::ai::blocklist::agent_view::AgentInputFooterEvent;
use crate::ai::blocklist::{InputConfig, InputType};
use crate::integration_testing::input::{inline_model_selector_is_open, input_is_empty};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::integration_testing::terminal::assert_context_menu_is_open;
use crate::integration_testing::view_getters::{
single_input_view_for_tab, single_terminal_view, single_terminal_view_for_tab,
};
use crate::terminal::CLIAgent;
use crate::terminal::cli_agent_sessions::{
CLIAgentInputEntrypoint, CLIAgentInputState, CLIAgentSession, CLIAgentSessionContext,
CLIAgentSessionStatus, CLIAgentSessionsModel,
};
use crate::terminal::input::models::InlineModelSelectorTab;
use crate::terminal::view::TerminalAction;
/// Opens the CLI-agent Rich Input for the terminal view at `tab_index`.
pub fn open_cli_agent_rich_input(tab_index: usize) -> TestStep {
new_step_with_default_assertions("Open CLI Agent Rich Input").with_action(
move |app, window_id, _step_data| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_index);
terminal_view.update(app, |view, ctx| {
let view_id = view.view_id();
CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| {
sessions.set_session(
view_id,
CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
remote_host: None,
plugin_version: None,
draft_text: None,
custom_command_prefix: None,
received_rich_notification: false,
},
ctx,
);
});
CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| {
sessions.open_input(
view_id,
CLIAgentInputEntrypoint::CtrlG,
InputConfig {
input_type: InputType::AI,
is_locked: true,
},
false,
false,
ctx,
);
});
});
},
)
}
/// Asserts that the Rich Input buffer text for `tab_index` is empty.
pub fn rich_input_buffer_text_is_empty(tab_index: usize) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
text.is_empty(),
"Expected Rich Input buffer to be empty; got: {text:?}"
)
})
})
}
/// Asserts that the Rich Input buffer text for `tab_index` contains a newline character.
pub fn rich_input_buffer_contains_newline(
tab_index: usize,
) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
text.contains('\n'),
"Expected Rich Input buffer to contain a newline; got: {text:?}"
)
})
})
}
/// Asserts that the Rich Input buffer for `tab_index` contains no newline (verifies menu-acceptance, not newline insertion).
pub fn rich_input_buffer_does_not_contain_newline(
tab_index: usize,
) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
!text.contains('\n'),
"Expected Rich Input buffer to NOT contain a newline; got: {text:?}"
)
})
})
}
pub fn open_input_context_menu() -> TestStep {
new_step_with_default_assertions("Open input context menu")
.with_action(move |app, _, _| {
let window_id = app.read(|ctx| {
WindowManager::as_ref(ctx)
.active_window()
.expect("no active window")
});
let terminal_view_id = single_terminal_view(app, window_id).id();
app.dispatch_typed_action(
window_id,
&[terminal_view_id],
&TerminalAction::OpenInputContextMenu {
position: Vector2F::new(8.5, 8.5),
},
);
})
.add_assertion(assert_context_menu_is_open(true))
}
/// Toggles the inline model selector by emitting the same footer event the model
/// chip emits when clicked, exercising the real `Input` event-handling path.
pub fn toggle_inline_model_selector_from_chip() -> TestStep {
new_step_with_default_assertions("Toggle inline model selector from model chip").with_action(
|app, window_id, _| {
let input = single_input_view_for_tab(app, window_id, 0);
let footer = input.read(app, |view, _| view.agent_input_footer().clone());
footer.update(app, |_, ctx| {
ctx.emit(AgentInputFooterEvent::ToggleInlineModelSelector {
initial_tab: InlineModelSelectorTab::BaseAgent,
});
});
},
)
}
/// Opens the inline model selector from the model chip and asserts it opened with
/// a cleared input buffer (so the input can be used to search models).
pub fn open_inline_model_selector_from_chip() -> TestStep {
toggle_inline_model_selector_from_chip()
.add_named_assertion(
"Inline model selector is open",
inline_model_selector_is_open(0),
)
.add_named_assertion("Prompt is cleared for model search", input_is_empty(0))
}