@@ -319,6 +319,9 @@ pub enum FrameworkConfig {
319319
320320 /// Discover and run tests with custom shell commands.
321321 Default ( DefaultFrameworkConfig ) ,
322+
323+ /// Discover and run JavaScript/TypeScript tests with vitest.
324+ Vitest ( VitestFrameworkConfig ) ,
322325}
323326
324327impl FrameworkConfig {
@@ -331,6 +334,7 @@ impl FrameworkConfig {
331334 FrameworkConfig :: Pytest ( config) => & config. test_id_format ,
332335 FrameworkConfig :: Cargo ( config) => & config. test_id_format ,
333336 FrameworkConfig :: Default ( config) => & config. test_id_format ,
337+ FrameworkConfig :: Vitest ( config) => & config. test_id_format ,
334338 }
335339 }
336340}
@@ -394,6 +398,44 @@ fn default_cargo_test_id_format() -> String {
394398 "{classname} {name}" . to_string ( )
395399}
396400
401+ fn default_vitest_command ( ) -> String {
402+ "npx vitest" . to_string ( )
403+ }
404+
405+ fn default_vitest_test_id_format ( ) -> String {
406+ "{classname} > {name}" . to_string ( )
407+ }
408+
409+ /// Configuration for vitest test framework.
410+ #[ derive( Debug , Clone , Deserialize , Serialize ) ]
411+ pub struct VitestFrameworkConfig {
412+ /// Full command prefix for invoking vitest (e.g. `"npx vitest"`).
413+ ///
414+ /// Default: `"npx vitest"`
415+ #[ serde( default = "default_vitest_command" ) ]
416+ pub command : String ,
417+
418+ /// Extra arguments appended only during test execution (not discovery).
419+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
420+ pub run_args : Option < String > ,
421+
422+ /// Format string for constructing test IDs from JUnit XML attributes.
423+ ///
424+ /// Default: `"{classname} > {name}"`
425+ #[ serde( default = "default_vitest_test_id_format" ) ]
426+ pub test_id_format : String ,
427+ }
428+
429+ impl Default for VitestFrameworkConfig {
430+ fn default ( ) -> Self {
431+ Self {
432+ command : default_vitest_command ( ) ,
433+ run_args : None ,
434+ test_id_format : default_vitest_test_id_format ( ) ,
435+ }
436+ }
437+ }
438+
397439/// Configuration for Rust/Cargo test framework.
398440#[ derive( Debug , Clone , Default , Deserialize , Serialize ) ]
399441pub struct CargoFrameworkConfig {
@@ -854,4 +896,70 @@ mod tests {
854896
855897 Ok ( ( ) )
856898 }
899+
900+ fn vitest_local_config ( ) -> Config {
901+ Config {
902+ offload : OffloadConfig {
903+ max_parallel : 10 ,
904+ test_timeout_secs : 900 ,
905+ working_dir : None ,
906+ sandbox_project_root : "/app" . to_string ( ) ,
907+ sandbox_init_cmd : None ,
908+ } ,
909+ provider : ProviderConfig :: Local ( LocalProviderConfig {
910+ working_dir : Some ( PathBuf :: from ( "." ) ) ,
911+ ..Default :: default ( )
912+ } ) ,
913+ framework : FrameworkConfig :: Vitest ( VitestFrameworkConfig {
914+ command : "npx vitest" . into ( ) ,
915+ test_id_format : "{classname} > {name}" . into ( ) ,
916+ ..Default :: default ( )
917+ } ) ,
918+ groups : HashMap :: from ( [ (
919+ "default" . to_string ( ) ,
920+ GroupConfig {
921+ retry_count : 0 ,
922+ filters : String :: new ( ) ,
923+ } ,
924+ ) ] ) ,
925+ report : ReportConfig :: default ( ) ,
926+ }
927+ }
928+
929+ #[ test]
930+ fn test_init_config_vitest_deserializes ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
931+ let config = vitest_local_config ( ) ;
932+ let toml_str = toml:: to_string_pretty ( & config) ?;
933+ let deserialized: Config = toml:: from_str ( & toml_str) ?;
934+ assert_eq ! (
935+ deserialized. framework. test_id_format( ) ,
936+ "{classname} > {name}"
937+ ) ;
938+ Ok ( ( ) )
939+ }
940+
941+ #[ test]
942+ fn test_vitest_default_command ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
943+ let toml_str = r#"
944+ [offload]
945+ sandbox_project_root = "/app"
946+
947+ [provider]
948+ type = "local"
949+
950+ [framework]
951+ type = "vitest"
952+
953+ [groups.all]
954+ retry_count = 0
955+ "# ;
956+ let config: Config = toml:: from_str ( toml_str) ?;
957+ if let FrameworkConfig :: Vitest ( ref vitest) = config. framework {
958+ assert_eq ! ( vitest. command, "npx vitest" ) ;
959+ assert ! ( vitest. run_args. is_none( ) ) ;
960+ } else {
961+ return Err ( "Expected Vitest framework" . into ( ) ) ;
962+ }
963+ Ok ( ( ) )
964+ }
857965}
0 commit comments