@@ -967,6 +967,80 @@ test("setup uses the device-type inventory when a runtime omits supportedDeviceT
967967 assert . equal ( emptyArrayPreview . devices . length , 6 ) ;
968968} ) ;
969969
970+ test ( "setup fallback device types stay stable when preferred names are absent" , ( ) => {
971+ const root = makeTempDir ( ) ;
972+ const deviceTypes = [
973+ {
974+ identifier : "com.apple.CoreSimulator.SimDeviceType.iPhone-SE" ,
975+ name : "iPhone SE" ,
976+ productFamily : "iPhone" ,
977+ } ,
978+ {
979+ identifier : "com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro" ,
980+ name : "iPhone 16 Pro" ,
981+ productFamily : "iPhone" ,
982+ } ,
983+ {
984+ identifier : "com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11" ,
985+ name : "iPad Pro 11-inch" ,
986+ productFamily : "iPad" ,
987+ } ,
988+ {
989+ identifier : "com.apple.CoreSimulator.SimDeviceType.iPad-Air" ,
990+ name : "iPad Air" ,
991+ productFamily : "iPad" ,
992+ } ,
993+ ] ;
994+ const runtime = {
995+ buildversion : "23F76" ,
996+ identifier : "com.apple.CoreSimulator.SimRuntime.iOS-26-5" ,
997+ isAvailable : true ,
998+ version : "26.5" ,
999+ } ;
1000+ const forwardSimctl = createSimctlFixture ( root , {
1001+ runtimes : [ { ...runtime , supportedDeviceTypes : deviceTypes } ] ,
1002+ } ) ;
1003+ const reversedRoot = makeTempDir ( ) ;
1004+ const reversedSimctl = createSimctlFixture ( reversedRoot , {
1005+ runtimes : [ { ...runtime , supportedDeviceTypes : [ ...deviceTypes ] . reverse ( ) } ] ,
1006+ } ) ;
1007+ const forwardPaths = resolveBrokerPaths ( {
1008+ hostConfigPath : path . join ( root , "host-config.json" ) ,
1009+ stateRoot : path . join ( root , "state" ) ,
1010+ } ) ;
1011+ const reversedPaths = resolveBrokerPaths ( {
1012+ hostConfigPath : path . join ( reversedRoot , "host-config.json" ) ,
1013+ stateRoot : path . join ( reversedRoot , "state" ) ,
1014+ } ) ;
1015+
1016+ const forward = previewSetupBroker ( forwardPaths , {
1017+ hostId : "fallback-device-types" ,
1018+ simctlAdapter : forwardSimctl . adapter ,
1019+ } ) ;
1020+ const reversed = previewSetupBroker ( reversedPaths , {
1021+ hostId : "fallback-device-types" ,
1022+ simctlAdapter : reversedSimctl . adapter ,
1023+ } ) ;
1024+
1025+ assert . equal ( forward . planId , reversed . planId ) ;
1026+ assert . equal (
1027+ forward . devices . find ( ( device ) => device . deviceFamily === "iPhone" ) . deviceTypeIdentifier ,
1028+ "com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro" ,
1029+ ) ;
1030+ assert . equal (
1031+ reversed . devices . find ( ( device ) => device . deviceFamily === "iPhone" ) . deviceTypeIdentifier ,
1032+ "com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro" ,
1033+ ) ;
1034+ assert . equal (
1035+ forward . devices . find ( ( device ) => device . deviceFamily === "iPad" ) . deviceTypeIdentifier ,
1036+ "com.apple.CoreSimulator.SimDeviceType.iPad-Air" ,
1037+ ) ;
1038+ assert . equal (
1039+ reversed . devices . find ( ( device ) => device . deviceFamily === "iPad" ) . deviceTypeIdentifier ,
1040+ "com.apple.CoreSimulator.SimDeviceType.iPad-Air" ,
1041+ ) ;
1042+ } ) ;
1043+
9701044test ( "setup preview is an exact stable six-device plan with strict reuse matching" , ( ) => {
9711045 const root = makeTempDir ( ) ;
9721046 const matchingName = "Simulator Broker setup-plan ui-1" ;
@@ -1123,6 +1197,24 @@ test("setup blocks an existing host when doctor-relevant state files are malform
11231197 assert . equal ( leasesBlocked . status , "blocked" ) ;
11241198 assert . ok ( leasesBlocked . prerequisites . some ( ( issue ) =>
11251199 issue . id === "leases" && issue . status === "blocked" ) ) ;
1200+
1201+ fs . writeFileSync ( path . join ( resolvedPaths . leasesDir , "broken.json" ) , "{}\n" ) ;
1202+ const emptyLeaseBlocked = previewSetupBroker ( resolvedPaths , {
1203+ simctlAdapter : paths . simctl . adapter ,
1204+ } ) ;
1205+ assert . equal ( emptyLeaseBlocked . status , "blocked" ) ;
1206+ assert . ok ( emptyLeaseBlocked . prerequisites . some ( ( issue ) =>
1207+ issue . id === "leases" && issue . status === "blocked" ) ) ;
1208+
1209+ fs . rmSync ( path . join ( resolvedPaths . leasesDir , "broken.json" ) ) ;
1210+ fs . mkdirSync ( resolvedPaths . pinsDir , { recursive : true } ) ;
1211+ writeJson ( path . join ( resolvedPaths . pinsDir , "empty-pin.json" ) , { } ) ;
1212+ const emptyPinBlocked = previewSetupBroker ( resolvedPaths , {
1213+ simctlAdapter : paths . simctl . adapter ,
1214+ } ) ;
1215+ assert . equal ( emptyPinBlocked . status , "blocked" ) ;
1216+ assert . ok ( emptyPinBlocked . prerequisites . some ( ( issue ) =>
1217+ issue . id === "leases" && issue . status === "blocked" ) ) ;
11261218} ) ;
11271219
11281220test ( "setup blocks an existing host whose registry marks an alias for repair" , ( ) => {
0 commit comments