use super::*;
use harness::{table_detail_loaded_state, with_current_result};
use sabiql_app::model::app_state::AppState;
use sabiql_app::services::AppServices;
use sabiql_app::update::action::{Action, CursorMove, InputTarget, ModalKind};
use sabiql_app::update::browse::result::reduce_result;
use sabiql_domain::{Column, ColumnAttributes, QueryResult};
fn jsonb_detail_state() -> (AppState, std::time::Instant) {
let now = test_instant();
let mut state = create_test_state();
state
.session
.mark_connected(Arc::new(fixtures::sample_metadata(now)));
let mut table = fixtures::sample_table_detail();
table.columns.push(Column {
name: "settings".to_string(),
data_type: "jsonb".to_string(),
attributes: ColumnAttributes::NULLABLE,
default: None,
comment: None,
ordinal_position: 4,
});
let _ = state.session.set_table_detail(table, 0);
state.query.set_current_result(Arc::new(QueryResult {
query: "SELECT id, name, email, settings FROM users LIMIT 100".to_string(),
columns: vec![
"id".to_string(),
"name".to_string(),
"email".to_string(),
"settings".to_string(),
],
rows: vec![vec![
"1".to_string(),
"Alice".to_string(),
"alice@example.com".to_string(),
r#"{"theme":"dark","count":5,"nested":{"enabled":true,"roles":["admin","writer"]}}"#
.to_string(),
]],
row_count: 1,
execution_time_ms: 1,
executed_at: now,
source: QuerySource::Preview,
error: None,
command_tag: None,
}));
state.query.pagination.schema = "public".to_string();
state.query.pagination.table = "users".to_string();
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(0, 3);
(state, now)
}
#[test]
fn result_pane_first_cell_active_mode() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(0, 0);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_active_mode() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_edit_mode() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
state.modal.set_mode(InputMode::CellEdit);
state
.result_interaction
.begin_cell_edit(1, 2, "bob@example.com".to_string());
state
.result_interaction
.cell_edit_input_mut()
.set_content("new@example.com".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_edit_cursor_at_head() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
state.modal.set_mode(InputMode::CellEdit);
state
.result_interaction
.begin_cell_edit(1, 2, "bob@example.com".to_string());
state.result_interaction.cell_edit_input_mut().set_cursor(0);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_edit_cursor_at_middle() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
state.modal.set_mode(InputMode::CellEdit);
state
.result_interaction
.begin_cell_edit(1, 2, "bob@example.com".to_string());
state.result_interaction.cell_edit_input_mut().set_cursor(7);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_active_pending_draft() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
state.modal.set_mode(InputMode::Normal);
state
.result_interaction
.begin_cell_edit(1, 2, "bob@example.com".to_string());
state
.result_interaction
.cell_edit_input_mut()
.set_content("new@example.com".to_string());
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_cell_edit_cursor_at_tail() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(1, 2);
state.modal.set_mode(InputMode::CellEdit);
state
.result_interaction
.begin_cell_edit(1, 2, "bob@example.com".to_string());
let len = state.result_interaction.cell_edit().input.content().len();
state
.result_interaction
.cell_edit_input_mut()
.set_cursor(len);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_staged_delete_row() {
let (mut state, now) = table_detail_loaded_state();
let mut terminal = create_test_terminal();
with_current_result(&mut state, now);
state.ui.focused_pane = FocusedPane::Result;
state.result_interaction.activate_cell(0, 0);
state.result_interaction.stage_row(1);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_jsonb_detail_mode() {
let (mut state, now) = jsonb_detail_state();
let mut terminal = create_test_terminal();
reduce_result(
&mut state,
&Action::OpenModal(ModalKind::JsonbDetail),
&AppServices::stub(),
now,
);
assert_eq!(state.input_mode(), InputMode::JsonbDetail);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}
#[test]
fn result_pane_jsonb_edit_mode() {
let (mut state, now) = jsonb_detail_state();
let mut terminal = create_test_terminal();
reduce_result(
&mut state,
&Action::OpenModal(ModalKind::JsonbDetail),
&AppServices::stub(),
now,
);
assert_eq!(state.input_mode(), InputMode::JsonbDetail);
reduce_result(
&mut state,
&Action::TextMoveCursor {
target: InputTarget::JsonbEdit,
direction: CursorMove::Down,
},
&AppServices::stub(),
now,
);
reduce_result(
&mut state,
&Action::TextMoveCursor {
target: InputTarget::JsonbEdit,
direction: CursorMove::Right,
},
&AppServices::stub(),
now,
);
reduce_result(
&mut state,
&Action::JsonbEnterEdit,
&AppServices::stub(),
now,
);
assert_eq!(state.input_mode(), InputMode::JsonbEdit);
let output = render_to_string(&mut terminal, &mut state);
insta::assert_snapshot!(output);
}