@@ -204,3 +204,72 @@ fn test_scroll_without_element_no_state_needed() {
204204
205205 result. stderr ( predicate:: str:: contains ( "xdotool" ) . or ( predicate:: str:: contains ( "screenshot tool" ) . or ( predicate:: str:: contains ( "scroll" ) ) ) ) ;
206206}
207+
208+ // =============================================================================
209+ // Observe --format default (issue #21)
210+ // =============================================================================
211+
212+ #[ test]
213+ fn observe_help_documents_json_as_default ( ) {
214+ agent_desktop_cmd ( )
215+ . args ( [ "observe" , "--help" ] )
216+ . assert ( )
217+ . success ( )
218+ . stdout ( predicate:: str:: contains ( "--format" ) . and ( predicate:: str:: contains ( "json" ) ) ) ;
219+ }
220+
221+ #[ test]
222+ fn observe_default_format_is_json ( ) {
223+ // The default output of `observe` should be valid JSON, not XML.
224+ // A weak "doesn't start with <" check is not enough — empty output
225+ // or an error banner would pass that. We assert the command succeeds
226+ // AND that stdout parses as a JSON value.
227+ let output = agent_desktop_cmd ( )
228+ . args ( [ "observe" ] )
229+ . output ( )
230+ . expect ( "agent-desktop should run" ) ;
231+
232+ assert ! (
233+ output. status. success( ) ,
234+ "observe should exit 0; got status={:?}, stderr={}" ,
235+ output. status,
236+ String :: from_utf8_lossy( & output. stderr)
237+ ) ;
238+
239+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
240+ let trimmed = stdout. trim ( ) ;
241+ assert ! ( !trimmed. is_empty( ) , "expected non-empty stdout" ) ;
242+
243+ let parsed: serde_json:: Value = serde_json:: from_str ( trimmed) . unwrap_or_else ( |e| {
244+ panic ! (
245+ "expected JSON default but parse failed: {}\n first 200 chars of stdout: {}" ,
246+ e,
247+ & trimmed[ ..trimmed. len( ) . min( 200 ) ]
248+ )
249+ } ) ;
250+
251+ // Sanity: the parsed value should be either an object with fields or a
252+ // non-empty array. We don't assume a specific shape — that's another test.
253+ let non_empty = match & parsed {
254+ serde_json:: Value :: Object ( m) => !m. is_empty ( ) ,
255+ serde_json:: Value :: Array ( a) => !a. is_empty ( ) ,
256+ _ => true , // bare scalar is unexpected but technically valid JSON
257+ } ;
258+ assert ! ( non_empty, "parsed JSON should not be an empty object/array" ) ;
259+ }
260+
261+ #[ test]
262+ fn observe_with_explicit_xml_still_works ( ) {
263+ // Backward-compat: --format xml must still work after the default flip.
264+ let output = agent_desktop_cmd ( )
265+ . args ( [ "observe" , "--format" , "xml" ] )
266+ . output ( )
267+ . expect ( "agent-desktop should run with explicit format" ) ;
268+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
269+ let trimmed = stdout. trim_start ( ) ;
270+ assert ! (
271+ trimmed. starts_with( "<" ) ,
272+ "expected XML output with --format xml but got: {}" ,
273+ & trimmed[ ..trimmed. len( ) . min( 80 ) ]
274+ ) ;
275+ }
0 commit comments