@@ -803,13 +803,61 @@ sessionDefaults:
803803 expect ( parsed . sessionDefaults ?. simulatorName ) . toBeUndefined ( ) ;
804804 } ) ;
805805
806- it ( 'continues setup with no default device when temp path creation fails' , async ( ) => {
806+ it ( 'uses xctrace fallback when temp path creation fails' , async ( ) => {
807807 const { fs, getStoredConfig } = createSetupFs ( ) ;
808808 fs . tmpdir = ( ) => {
809809 throw new Error ( 'tmpdir unavailable' ) ;
810810 } ;
811811
812812 const executor : CommandExecutor = async ( command ) => {
813+ if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'xctrace' ) {
814+ return createMockCommandResponse ( {
815+ success : true ,
816+ output : 'Cam iPhone (12345678-1234-1234-1234-123456789ABC)' ,
817+ } ) ;
818+ }
819+
820+ return createMockCommandResponse ( {
821+ success : true ,
822+ output : `Information about workspace "App":\n Schemes:\n App` ,
823+ } ) ;
824+ } ;
825+
826+ const prompter : Prompter = {
827+ selectOne : async < T > ( opts : { options : Array < { value : T } > } ) =>
828+ opts . options . find ( ( option ) => option . value != null ) ?. value ?? opts . options [ 0 ] . value ,
829+ selectMany : async < T > ( opts : { options : Array < { value : T } > } ) => {
830+ const loggingOption = opts . options . find ( ( option ) => option . value === ( 'logging' as T ) ) ;
831+ return loggingOption ? [ loggingOption . value ] : opts . options . map ( ( option ) => option . value ) ;
832+ } ,
833+ confirm : async ( opts : { defaultValue : boolean } ) => opts . defaultValue ,
834+ } ;
835+
836+ await runSetupWizard ( {
837+ cwd,
838+ fs,
839+ executor,
840+ prompter,
841+ quietOutput : true ,
842+ } ) ;
843+
844+ const parsed = parseYaml ( getStoredConfig ( ) ) as {
845+ sessionDefaults ?: Record < string , unknown > ;
846+ } ;
847+
848+ expect ( parsed . sessionDefaults ?. deviceId ) . toBe ( '12345678-1234-1234-1234-123456789ABC' ) ;
849+ } ) ;
850+
851+ it ( 'continues setup with no default device when device json parsing fails' , async ( ) => {
852+ const { fs, getStoredConfig, setTempFile } = createSetupFs ( ) ;
853+
854+ const executor : CommandExecutor = async ( command ) => {
855+ if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'devicectl' ) {
856+ const jsonPath = command [ command . length - 1 ] ;
857+ setTempFile ( jsonPath , 'not json' ) ;
858+ return createMockCommandResponse ( { success : true , output : '' } ) ;
859+ }
860+
813861 if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'xctrace' ) {
814862 throw new Error ( 'xctrace spawn failed' ) ;
815863 }
@@ -842,6 +890,67 @@ sessionDefaults:
842890 } ;
843891
844892 expect ( parsed . sessionDefaults ?. deviceId ) . toBeUndefined ( ) ;
893+ } ) ;
894+
895+ it ( 'continues setup with no default simulator when simctl text fallback fails' , async ( ) => {
896+ const { fs, getStoredConfig } = createSetupFs ( ) ;
897+
898+ const executor : CommandExecutor = async ( command ) => {
899+ if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'devicectl' ) {
900+ throw new Error ( 'device lookup should not run for simulator-only workflows' ) ;
901+ }
902+
903+ if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'simctl' && command . includes ( '--json' ) ) {
904+ return createMockCommandResponse ( {
905+ success : true ,
906+ output : JSON . stringify ( {
907+ devices : {
908+ 'iOS 17.0' : [
909+ {
910+ name : 'iPhone 15' ,
911+ udid : 'SIM-1' ,
912+ state : 'Shutdown' ,
913+ isAvailable : true ,
914+ } ,
915+ ] ,
916+ } ,
917+ } ) ,
918+ } ) ;
919+ }
920+
921+ if ( command [ 0 ] === 'xcrun' && command [ 1 ] === 'simctl' ) {
922+ throw new Error ( 'simctl text fallback unavailable' ) ;
923+ }
924+
925+ return createMockCommandResponse ( {
926+ success : true ,
927+ output : `Information about workspace "App":\n Schemes:\n App` ,
928+ } ) ;
929+ } ;
930+
931+ const prompter : Prompter = {
932+ selectOne : async < T > ( opts : { options : Array < { value : T } > } ) => opts . options [ 0 ] . value ,
933+ selectMany : async < T > ( opts : { options : Array < { value : T } > } ) => {
934+ const simulatorOption = opts . options . find ( ( option ) => option . value === ( 'simulator' as T ) ) ;
935+ return simulatorOption
936+ ? [ simulatorOption . value ]
937+ : opts . options . map ( ( option ) => option . value ) ;
938+ } ,
939+ confirm : async ( opts : { defaultValue : boolean } ) => opts . defaultValue ,
940+ } ;
941+
942+ await runSetupWizard ( {
943+ cwd,
944+ fs,
945+ executor,
946+ prompter,
947+ quietOutput : true ,
948+ } ) ;
949+
950+ const parsed = parseYaml ( getStoredConfig ( ) ) as {
951+ sessionDefaults ?: Record < string , unknown > ;
952+ } ;
953+
845954 expect ( parsed . sessionDefaults ?. simulatorId ) . toBeUndefined ( ) ;
846955 expect ( parsed . sessionDefaults ?. simulatorName ) . toBeUndefined ( ) ;
847956 } ) ;
0 commit comments