Testing
Running Tests
Section titled “Running Tests”cargo test --workspace # All Rust testscargo check --workspace # Compile check onlyflutter test # Dart testsflutter test --coverage # With coverageTest Pattern
Section titled “Test Pattern”Tests construct a modality directly with state and services, then exercise compilation and dispatch:
#[test]fn test_compile() { let state = State { synced: WhiteboardSynced::default(), ephemeral: Default::default(), }; let services = Arc::new(ModalityServices::new(AgentService::noop())); let modality = Whiteboard::new(state, services); let result = modality.compile( &WhiteboardMetadata::default(), &HashMap::new(), ); assert!(result.is_ok());}Key helpers
Section titled “Key helpers”AgentService::noop()— creates a no-op agent service for tests (no AI channel)State { synced, ephemeral: Default::default() }— minimal state constructionModalityServices::new(agent)— wraps anAgentServicefor modalities without extra domain services
Testing Reducers
Section titled “Testing Reducers”Test reduce() directly (it’s static — no instance needed):
#[test]fn test_reduce_add_placement() { let mut state = State { synced: WhiteboardSynced::default(), ephemeral: Default::default(), }; let services = Arc::new(ModalityServices::new(AgentService::noop())); let (send_tx, _) = mpsc::channel(); let (spawn_tx, _) = mpsc::channel(); let mut fx = Effects::new(services, send_tx, spawn_tx);
Whiteboard::reduce( Command::Intent(WhiteboardIntent::AddPlacement { /* ... */ }), &mut state, &mut fx, );
assert_eq!(state.synced.placements.len(), 1);}Testing Sessions
Section titled “Testing Sessions”Session tests need a Doc, backend, and sinks:
#[test]fn test_session_dispatch() { let session = Session::new(/* modality, doc, services, sinks */); session.dispatch(Command::Intent( SessionIntent::Modality(WhiteboardIntent::AddPlacement { /* ... */ }) )); assert_eq!(session.modality.state().synced.placements.len(), 1);}