@@ -4,6 +4,53 @@ import path from 'path';
44import { ConformanceCheck } from '../types.js' ;
55import { getScenario } from '../scenarios/index.js' ;
66
7+ // ANSI color codes
8+ const COLORS = {
9+ RESET : '\x1b[0m' ,
10+ GRAY : '\x1b[90m' ,
11+ GREEN : '\x1b[32m' ,
12+ YELLOW : '\x1b[33m' ,
13+ RED : '\x1b[31m' ,
14+ BLUE : '\x1b[36m'
15+ } ;
16+
17+ function getStatusColor ( status : string ) : string {
18+ switch ( status ) {
19+ case 'SUCCESS' :
20+ return COLORS . GREEN ;
21+ case 'FAILURE' :
22+ return COLORS . RED ;
23+ case 'INFO' :
24+ return COLORS . BLUE ;
25+ default :
26+ return COLORS . RESET ;
27+ }
28+ }
29+
30+ function formatPrettyChecks ( checks : ConformanceCheck [ ] ) : string {
31+ // Find the longest id and status for column alignment
32+ const maxIdLength = Math . max ( ...checks . map ( ( c ) => c . id . length ) ) ;
33+ const maxStatusLength = Math . max ( ...checks . map ( ( c ) => c . status . length ) ) ;
34+
35+ return checks
36+ . map ( ( check ) => {
37+ const timestamp = `${ COLORS . GRAY } ${ check . timestamp } ${ COLORS . RESET } ` ;
38+ const id = check . id . padEnd ( maxIdLength ) ;
39+ const statusColor = getStatusColor ( check . status ) ;
40+ const status = `${ statusColor } ${ check . status . padEnd ( maxStatusLength ) } ${ COLORS . RESET } ` ;
41+ const description = check . description ;
42+ const line = `${ timestamp } [${ id } ] ${ status } ${ description } ` ;
43+ // Add newline after outgoing responses for better visual separation
44+ return (
45+ line +
46+ ( check . id . includes ( 'outgoing' ) && check . id . includes ( 'response' )
47+ ? '\n'
48+ : '' )
49+ ) ;
50+ } )
51+ . join ( '\n' ) ;
52+ }
53+
754export interface ClientExecutionResult {
855 exitCode : number ;
956 stdout : string ;
@@ -110,6 +157,21 @@ export async function runConformanceTest(
110157 timeout
111158 ) ;
112159
160+ // Print stdout/stderr if client exited with nonzero code
161+ if ( clientOutput . exitCode !== 0 ) {
162+ console . error ( `\nClient exited with code ${ clientOutput . exitCode } ` ) ;
163+ if ( clientOutput . stdout ) {
164+ console . error ( `\nStdout:\n${ clientOutput . stdout } ` ) ;
165+ }
166+ if ( clientOutput . stderr ) {
167+ console . error ( `\nStderr:\n${ clientOutput . stderr } ` ) ;
168+ }
169+ }
170+
171+ if ( clientOutput . timedOut ) {
172+ console . error ( `\nClient timed out after ${ timeout } ms` ) ;
173+ }
174+
113175 const checks = scenario . getChecks ( ) ;
114176
115177 await fs . writeFile (
@@ -175,6 +237,7 @@ async function main(): Promise<void> {
175237 const args = process . argv . slice ( 2 ) ;
176238 let command : string | null = null ;
177239 let scenario : string | null = null ;
240+ let verbose = false ;
178241
179242 for ( let i = 0 ; i < args . length ; i ++ ) {
180243 if ( args [ i ] === '--command' && i + 1 < args . length ) {
@@ -183,12 +246,14 @@ async function main(): Promise<void> {
183246 } else if ( args [ i ] === '--scenario' && i + 1 < args . length ) {
184247 scenario = args [ i + 1 ] ;
185248 i ++ ;
249+ } else if ( args [ i ] === '--verbose' ) {
250+ verbose = true ;
186251 }
187252 }
188253
189254 if ( ! scenario ) {
190255 console . error (
191- 'Usage: runner --scenario <scenario> [--command "<command>"]'
256+ 'Usage: runner --scenario <scenario> [--command "<command>"] [--verbose] '
192257 ) ;
193258 console . error (
194259 'Example: runner --scenario initialize --command "tsx examples/clients/typescript/test1.ts"'
@@ -216,7 +281,11 @@ async function main(): Promise<void> {
216281 const passed = result . checks . filter ( ( c ) => c . status === 'SUCCESS' ) . length ;
217282 const failed = result . checks . filter ( ( c ) => c . status === 'FAILURE' ) . length ;
218283
219- console . log ( `Checks:\n${ JSON . stringify ( result . checks , null , 2 ) } ` ) ;
284+ if ( verbose ) {
285+ console . log ( `Checks:\n${ JSON . stringify ( result . checks , null , 2 ) } ` ) ;
286+ } else {
287+ console . log ( `Checks:\n${ formatPrettyChecks ( result . checks ) } ` ) ;
288+ }
220289
221290 console . log ( `\nTest Results:` ) ;
222291 console . log ( `Passed: ${ passed } /${ denominator } , ${ failed } failed` ) ;
0 commit comments