Files
k-frame/crates/application/tests/data_projection_tests.rs
Gabriel Kaszewski 26ebfad3a2 add SPA config UI, wire media/rss adapters, event-driven layout push
- React SPA: dashboard, data sources CRUD, widgets CRUD, layout builder,
  presets. TanStack Router + Query, shadcn/ui, Vite proxy to :3000
- wire media + rss adapters into polling loop, remove xtb source type
- media adapter: read username/password from headers, proper subsonic auth
- event handler: subscribe to LayoutChanged, push screen update to clients
- fix clippy warnings across workspace (Default impls, collapsible ifs,
  redundant closures, is_none_or, unused imports)
2026-06-19 00:12:42 +02:00

94 lines
2.5 KiB
Rust

use application::DataProjection;
use domain::{DisplayHint, KeyMapping, Value, WidgetConfig, WidgetId, WidgetState};
use std::collections::BTreeMap;
fn weather_widget() -> WidgetConfig {
WidgetConfig::new(
1,
"weather".into(),
DisplayHint::IconValue,
10,
vec![
KeyMapping {
source_path: "$.temp".into(),
target_key: "temperature".into(),
},
KeyMapping {
source_path: "$.icon".into(),
target_key: "icon".into(),
},
],
)
}
fn weather_response(temp: f64) -> Value {
Value::Object(BTreeMap::from([
("temp".into(), Value::Number(temp)),
("icon".into(), Value::String("sunny".into())),
]))
}
#[test]
fn apply_poll_result_detects_new_widget_state() {
let mut projection = DataProjection::new();
let widgets = vec![weather_widget()];
let changed = projection.apply_poll_result(10, &weather_response(5.4), &widgets);
assert_eq!(changed.len(), 1);
assert_eq!(changed[0].0, 1);
assert_eq!(
changed[0].1.data.get("temperature"),
Some(&Value::Number(5.4))
);
}
#[test]
fn apply_poll_result_returns_empty_when_nothing_changed() {
let mut projection = DataProjection::new();
let widgets = vec![weather_widget()];
projection.apply_poll_result(10, &weather_response(5.4), &widgets);
let changed = projection.apply_poll_result(10, &weather_response(5.4), &widgets);
assert!(changed.is_empty());
}
#[test]
fn apply_poll_result_detects_changed_value() {
let mut projection = DataProjection::new();
let widgets = vec![weather_widget()];
projection.apply_poll_result(10, &weather_response(5.4), &widgets);
let changed = projection.apply_poll_result(10, &weather_response(6.1), &widgets);
assert_eq!(changed.len(), 1);
assert_eq!(
changed[0].1.data.get("temperature"),
Some(&Value::Number(6.1))
);
}
#[test]
fn apply_poll_result_only_updates_widgets_bound_to_source() {
let mut projection = DataProjection::new();
let widgets = vec![
weather_widget(),
WidgetConfig::new(
2,
"portfolio".into(),
DisplayHint::KeyValue,
20,
vec![KeyMapping {
source_path: "$.value".into(),
target_key: "amount".into(),
}],
),
];
let changed = projection.apply_poll_result(10, &weather_response(5.4), &widgets);
assert_eq!(changed.len(), 1);
assert_eq!(changed[0].0, 1);
}