frontend tui tests
This commit is contained in:
44
Cargo.lock
generated
44
Cargo.lock
generated
@@ -163,6 +163,28 @@ dependencies = [
|
|||||||
"abi_stable",
|
"abi_stable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-stream"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||||
|
dependencies = [
|
||||||
|
"async-stream-impl",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-stream-impl"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.88"
|
version = "0.1.88"
|
||||||
@@ -531,10 +553,12 @@ dependencies = [
|
|||||||
"prost",
|
"prost",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"rstest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-test",
|
||||||
"toml",
|
"toml",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -542,6 +566,7 @@ dependencies = [
|
|||||||
"tui-textarea",
|
"tui-textarea",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width 0.2.0",
|
"unicode-width 0.2.0",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3949,6 +3974,19 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-test"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
|
||||||
|
dependencies = [
|
||||||
|
"async-stream",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.14"
|
version = "0.7.14"
|
||||||
@@ -4279,12 +4317,14 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.2",
|
"getrandom 0.3.2",
|
||||||
|
"js-sys",
|
||||||
"serde",
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -31,3 +31,8 @@ unicode-width = "0.2.0"
|
|||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
ui-debug = []
|
ui-debug = []
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rstest = "0.25.0"
|
||||||
|
tokio-test = "0.4.4"
|
||||||
|
uuid = { version = "1.17.0", features = ["v4"] }
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// src/components/form/form.rs
|
// src/components/form/form.rs
|
||||||
use crate::components::common::autocomplete; // <--- ADD THIS IMPORT
|
use crate::components::common::autocomplete;
|
||||||
use crate::components::handlers::canvas::render_canvas;
|
use crate::components::handlers::canvas::render_canvas;
|
||||||
use crate::config::colors::themes::Theme;
|
use crate::config::colors::themes::Theme;
|
||||||
use crate::state::app::highlight::HighlightState;
|
use crate::state::app::highlight::HighlightState;
|
||||||
use crate::state::pages::canvas_state::CanvasState;
|
use crate::state::pages::canvas_state::CanvasState;
|
||||||
use crate::state::pages::form::FormState; // <--- CHANGE THIS IMPORT
|
use crate::state::pages::form::FormState;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Constraint, Direction, Layout, Margin, Rect},
|
layout::{Alignment, Constraint, Direction, Layout, Margin, Rect},
|
||||||
style::Style,
|
style::Style,
|
||||||
|
|||||||
262
client/tests/form_tests.rs
Normal file
262
client/tests/form_tests.rs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
// client/tests/form_tests.rs
|
||||||
|
use rstest::{fixture, rstest};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use client::state::pages::form::{FormState, FieldDefinition};
|
||||||
|
use client::state::pages::canvas_state::CanvasState;
|
||||||
|
|
||||||
|
#[fixture]
|
||||||
|
fn test_form_state() -> FormState {
|
||||||
|
let fields = vec![
|
||||||
|
FieldDefinition {
|
||||||
|
display_name: "Company".to_string(),
|
||||||
|
data_key: "firma".to_string(),
|
||||||
|
is_link: false,
|
||||||
|
link_target_table: None,
|
||||||
|
},
|
||||||
|
FieldDefinition {
|
||||||
|
display_name: "Phone".to_string(),
|
||||||
|
data_key: "telefon".to_string(),
|
||||||
|
is_link: false,
|
||||||
|
link_target_table: None,
|
||||||
|
},
|
||||||
|
FieldDefinition {
|
||||||
|
display_name: "Email".to_string(),
|
||||||
|
data_key: "email".to_string(),
|
||||||
|
is_link: false,
|
||||||
|
link_target_table: None,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
FormState::new("test_profile".to_string(), "test_table".to_string(), fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[fixture]
|
||||||
|
fn test_form_data() -> HashMap<String, String> {
|
||||||
|
let mut data = HashMap::new();
|
||||||
|
data.insert("firma".to_string(), "Test Company".to_string());
|
||||||
|
data.insert("telefon".to_string(), "+421123456789".to_string());
|
||||||
|
data.insert("email".to_string(), "test@example.com".to_string());
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_state_creation(test_form_state: FormState) {
|
||||||
|
assert_eq!(test_form_state.profile_name, "test_profile");
|
||||||
|
assert_eq!(test_form_state.table_name, "test_table");
|
||||||
|
assert_eq!(test_form_state.fields.len(), 3);
|
||||||
|
assert_eq!(test_form_state.current_field(), 0);
|
||||||
|
assert!(!test_form_state.has_unsaved_changes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_field_navigation(mut test_form_state: FormState) {
|
||||||
|
// Test initial field
|
||||||
|
assert_eq!(test_form_state.current_field(), 0);
|
||||||
|
|
||||||
|
// Test navigation to next field
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
assert_eq!(test_form_state.current_field(), 1);
|
||||||
|
|
||||||
|
// Test navigation to last field
|
||||||
|
test_form_state.set_current_field(2);
|
||||||
|
assert_eq!(test_form_state.current_field(), 2);
|
||||||
|
|
||||||
|
// Test invalid field (should not crash)
|
||||||
|
test_form_state.set_current_field(999);
|
||||||
|
assert_eq!(test_form_state.current_field(), 2); // Should stay at valid field
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_data_entry(mut test_form_state: FormState) {
|
||||||
|
// Test entering data in first field
|
||||||
|
*test_form_state.get_current_input_mut() = "Test Company".to_string();
|
||||||
|
test_form_state.set_has_unsaved_changes(true);
|
||||||
|
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "Test Company");
|
||||||
|
assert!(test_form_state.has_unsaved_changes());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_field_switching_with_data(mut test_form_state: FormState) {
|
||||||
|
// Enter data in first field
|
||||||
|
*test_form_state.get_current_input_mut() = "Company Name".to_string();
|
||||||
|
|
||||||
|
// Switch to second field
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
*test_form_state.get_current_input_mut() = "+421123456789".to_string();
|
||||||
|
|
||||||
|
// Switch back to first field
|
||||||
|
test_form_state.set_current_field(0);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "Company Name");
|
||||||
|
|
||||||
|
// Switch to second field again
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "+421123456789");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_reset_functionality(mut test_form_state: FormState) {
|
||||||
|
// Add some data
|
||||||
|
test_form_state.set_current_field(0);
|
||||||
|
*test_form_state.get_current_input_mut() = "Test Company".to_string();
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
*test_form_state.get_current_input_mut() = "+421123456789".to_string();
|
||||||
|
test_form_state.set_has_unsaved_changes(true);
|
||||||
|
test_form_state.id = 123;
|
||||||
|
test_form_state.current_position = 5;
|
||||||
|
|
||||||
|
// Reset the form
|
||||||
|
test_form_state.reset_to_empty();
|
||||||
|
|
||||||
|
// Verify reset
|
||||||
|
assert_eq!(test_form_state.id, 0);
|
||||||
|
assert!(!test_form_state.has_unsaved_changes());
|
||||||
|
assert_eq!(test_form_state.current_field(), 0);
|
||||||
|
|
||||||
|
// Check all fields are empty
|
||||||
|
for i in 0..test_form_state.fields.len() {
|
||||||
|
test_form_state.set_current_field(i);
|
||||||
|
assert!(test_form_state.get_current_input().is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_update_from_response(mut test_form_state: FormState, test_form_data: HashMap<String, String>) {
|
||||||
|
let position = 3;
|
||||||
|
|
||||||
|
// Update form with response data
|
||||||
|
test_form_state.update_from_response(&test_form_data, position);
|
||||||
|
|
||||||
|
// Verify data was loaded
|
||||||
|
assert_eq!(test_form_state.current_position, position);
|
||||||
|
assert!(!test_form_state.has_unsaved_changes());
|
||||||
|
assert_eq!(test_form_state.current_field(), 0);
|
||||||
|
|
||||||
|
// Check field values
|
||||||
|
test_form_state.set_current_field(0);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "Test Company");
|
||||||
|
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "+421123456789");
|
||||||
|
|
||||||
|
test_form_state.set_current_field(2);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "test@example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_cursor_position(mut test_form_state: FormState) {
|
||||||
|
// Test initial cursor position
|
||||||
|
assert_eq!(test_form_state.current_cursor_pos(), 0);
|
||||||
|
|
||||||
|
// Add some text
|
||||||
|
*test_form_state.get_current_input_mut() = "Test Company".to_string();
|
||||||
|
|
||||||
|
// Test cursor positioning
|
||||||
|
test_form_state.set_current_cursor_pos(5);
|
||||||
|
assert_eq!(test_form_state.current_cursor_pos(), 5);
|
||||||
|
|
||||||
|
// Test cursor bounds
|
||||||
|
test_form_state.set_current_cursor_pos(999);
|
||||||
|
// Should be clamped to text length
|
||||||
|
assert!(test_form_state.current_cursor_pos() <= "Test Company".len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_field_display_names(test_form_state: FormState) {
|
||||||
|
let field_names = test_form_state.fields();
|
||||||
|
|
||||||
|
assert_eq!(field_names.len(), 3);
|
||||||
|
assert_eq!(field_names[0], "Company");
|
||||||
|
assert_eq!(field_names[1], "Phone");
|
||||||
|
assert_eq!(field_names[2], "Email");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_inputs_vector(mut test_form_state: FormState) {
|
||||||
|
// Add data to fields
|
||||||
|
test_form_state.set_current_field(0);
|
||||||
|
*test_form_state.get_current_input_mut() = "Company A".to_string();
|
||||||
|
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
*test_form_state.get_current_input_mut() = "123456789".to_string();
|
||||||
|
|
||||||
|
test_form_state.set_current_field(2);
|
||||||
|
*test_form_state.get_current_input_mut() = "test@test.com".to_string();
|
||||||
|
|
||||||
|
// Get inputs vector
|
||||||
|
let inputs = test_form_state.inputs();
|
||||||
|
|
||||||
|
assert_eq!(inputs.len(), 3);
|
||||||
|
assert_eq!(inputs[0], "Company A");
|
||||||
|
assert_eq!(inputs[1], "123456789");
|
||||||
|
assert_eq!(inputs[2], "test@test.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_position_management(mut test_form_state: FormState) {
|
||||||
|
// Test initial position
|
||||||
|
assert_eq!(test_form_state.current_position, 1);
|
||||||
|
assert_eq!(test_form_state.total_count, 0);
|
||||||
|
|
||||||
|
// Set some values
|
||||||
|
test_form_state.total_count = 10;
|
||||||
|
test_form_state.current_position = 5;
|
||||||
|
|
||||||
|
assert_eq!(test_form_state.current_position, 5);
|
||||||
|
assert_eq!(test_form_state.total_count, 10);
|
||||||
|
|
||||||
|
// Test reset affects position
|
||||||
|
test_form_state.reset_to_empty();
|
||||||
|
assert_eq!(test_form_state.current_position, 11); // total_count + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_autocomplete_state(mut test_form_state: FormState) {
|
||||||
|
// Test initial autocomplete state
|
||||||
|
assert!(!test_form_state.autocomplete_active);
|
||||||
|
assert!(test_form_state.autocomplete_suggestions.is_empty());
|
||||||
|
assert!(test_form_state.selected_suggestion_index.is_none());
|
||||||
|
|
||||||
|
// Test deactivating autocomplete
|
||||||
|
test_form_state.autocomplete_active = true;
|
||||||
|
test_form_state.deactivate_autocomplete();
|
||||||
|
|
||||||
|
assert!(!test_form_state.autocomplete_active);
|
||||||
|
assert!(test_form_state.autocomplete_suggestions.is_empty());
|
||||||
|
assert!(test_form_state.selected_suggestion_index.is_none());
|
||||||
|
assert!(!test_form_state.autocomplete_loading);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_empty_data_handling(mut test_form_state: FormState) {
|
||||||
|
let empty_data = HashMap::new();
|
||||||
|
|
||||||
|
// Update with empty data
|
||||||
|
test_form_state.update_from_response(&empty_data, 1);
|
||||||
|
|
||||||
|
// All fields should be empty
|
||||||
|
for i in 0..test_form_state.fields.len() {
|
||||||
|
test_form_state.set_current_field(i);
|
||||||
|
assert!(test_form_state.get_current_input().is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_form_partial_data_handling(mut test_form_state: FormState) {
|
||||||
|
let mut partial_data = HashMap::new();
|
||||||
|
partial_data.insert("firma".to_string(), "Partial Company".to_string());
|
||||||
|
// Intentionally missing telefon and email
|
||||||
|
|
||||||
|
test_form_state.update_from_response(&partial_data, 1);
|
||||||
|
|
||||||
|
// First field should have data
|
||||||
|
test_form_state.set_current_field(0);
|
||||||
|
assert_eq!(test_form_state.get_current_input(), "Partial Company");
|
||||||
|
|
||||||
|
// Other fields should be empty
|
||||||
|
test_form_state.set_current_field(1);
|
||||||
|
assert!(test_form_state.get_current_input().is_empty());
|
||||||
|
|
||||||
|
test_form_state.set_current_field(2);
|
||||||
|
assert!(test_form_state.get_current_input().is_empty());
|
||||||
|
}
|
||||||
3
client/tests/mod.rs
Normal file
3
client/tests/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// tests/mod.rs
|
||||||
|
|
||||||
|
pub mod form_tests;
|
||||||
Reference in New Issue
Block a user