@@ -11,28 +11,77 @@ import {
1111import * as simctl from './xcrun/simctl.js' ;
1212import * as devicectl from './xcrun/devicectl.js' ;
1313import { getDeviceName } from './utils.js' ;
14+ import { color , logger } from '@react-native-harness/tools' ;
1415
1516export const getAppleSimulatorPlatformInstance = async (
1617 config : ApplePlatformConfig
1718) : Promise < HarnessPlatformRunner > => {
1819 assertAppleDeviceSimulator ( config . device ) ;
1920
20- const udid = await simctl . getSimulatorId (
21- config . device . name ,
22- config . device . systemVersion
23- ) ;
21+ const logTag = color . bgMagentaBright ( '[AppleSimulatorPlatform]' ) ;
2422
25- if ( ! udid ) {
26- throw new DeviceNotFoundError ( getDeviceName ( config . device ) ) ;
23+ let udid ;
24+ let deviceName = '' ;
25+ if ( config . device . name && config . device . systemVersion ) {
26+ deviceName = getDeviceName ( config . device ) ;
27+ udid = await simctl . getSimulatorId (
28+ config . device . name ,
29+ config . device . systemVersion
30+ ) ;
31+ if ( ! udid ) {
32+ throw new DeviceNotFoundError ( getDeviceName ( config . device ) ) ;
33+ }
34+ } else {
35+ let selectedSimulator ;
36+ let simulators = await simctl . getSimulators ( ) ;
37+ // Filter only iOS devices
38+ const prefix = 'com.apple.CoreSimulator.SimRuntime.' ;
39+ simulators = simulators
40+ . filter ( ( s ) =>
41+ s . runtime . startsWith ( 'com.apple.CoreSimulator.SimRuntime.iOS' )
42+ )
43+ . map ( ( s ) => ( {
44+ ...s ,
45+ runtime : s . runtime . slice ( prefix . length ) ,
46+ } ) ) ;
47+
48+ // Filter only available devices
49+ simulators = simulators . filter ( ( simulator ) => simulator . isAvailable ) ;
50+ simulators . forEach ( ( simulator ) => {
51+ logger . debug (
52+ `${ logTag } : Found simulator id: ${ color . bold ( simulator . udid ) } ${ color . bgBlue (
53+ '[' + simulator . name + ' - ' + simulator . runtime + ']'
54+ ) } - State: ${ simulator . state } `
55+ ) ;
56+ } ) ;
57+ if ( simulators . length === 0 ) {
58+ throw new DeviceNotFoundError ( 'any' ) ;
59+ } else {
60+ // Prefer booted simulator
61+ selectedSimulator = simulators . find (
62+ ( simulator ) => simulator . state === 'Booted'
63+ ) ;
64+ if ( ! selectedSimulator ) {
65+ selectedSimulator = simulators [ 0 ] ;
66+ }
67+
68+ udid = selectedSimulator . udid ;
69+ deviceName = `${ selectedSimulator . name } (${ selectedSimulator . runtime } ) (simulator)` ;
70+
71+ logger . info (
72+ `${ logTag } : Selected simulator id: ${ color . bold (
73+ selectedSimulator . udid
74+ ) } ${ color . bgBlue (
75+ '[' + selectedSimulator . name + ' - ' + selectedSimulator . runtime + ']'
76+ ) } - State: ${ selectedSimulator . state } `
77+ ) ;
78+ }
2779 }
2880
2981 const isInstalled = await simctl . isAppInstalled ( udid , config . bundleId ) ;
3082
3183 if ( ! isInstalled ) {
32- throw new AppNotInstalledError (
33- config . bundleId ,
34- getDeviceName ( config . device )
35- ) ;
84+ throw new AppNotInstalledError ( config . bundleId , deviceName ) ;
3685 }
3786
3887 const simulatorStatus = await simctl . getSimulatorStatus ( udid ) ;
@@ -67,24 +116,59 @@ export const getAppleSimulatorPlatformInstance = async (
67116 } ;
68117} ;
69118
119+ const getDeviceString = ( device : devicectl . AppleDeviceInfo ) => {
120+ return color . bgBlue (
121+ `[${ device . deviceProperties . name } - ${ device . hardwareProperties . marketingName } - ${ device . hardwareProperties . productType } - OS: ${ device . deviceProperties . osVersionNumber } ]`
122+ ) ;
123+ } ;
124+
70125export const getApplePhysicalDevicePlatformInstance = async (
71126 config : ApplePlatformConfig
72127) : Promise < HarnessPlatformRunner > => {
73128 assertAppleDevicePhysical ( config . device ) ;
74129
75- const deviceId = await devicectl . getDeviceId ( config . device . name ) ;
130+ const logTag = color . bgMagentaBright ( '[ApplePhysicalDevicePlatform]' ) ;
131+ let deviceId ;
132+ let deviceName = '' ;
133+
134+ if ( config . device . name ) {
135+ deviceName = getDeviceName ( config . device ) ;
136+ deviceId = await devicectl . getDeviceId ( config . device . name ) ;
137+ if ( ! deviceId ) {
138+ throw new DeviceNotFoundError ( getDeviceName ( config . device ) ) ;
139+ }
140+ } else {
141+ const devicesIds = await devicectl . listDevices ( ) ;
142+ devicesIds . forEach ( ( device ) => {
143+ logger . info (
144+ `${ logTag } Found device id: ${ color . bold (
145+ device . identifier
146+ ) } ${ getDeviceString ( device ) } `
147+ ) ;
148+ } ) ;
149+ if ( devicesIds . length === 0 ) {
150+ throw new DeviceNotFoundError ( 'any' ) ;
151+ } else {
152+ const selectedDevice = devicesIds [ 0 ] ;
153+ deviceId = selectedDevice . identifier ;
154+ deviceName = `${ selectedDevice . deviceProperties . name } (${ selectedDevice . deviceProperties . osVersionNumber } ) (physical)` ;
155+
156+ logger . info (
157+ `${ logTag } Selected device id: ${ color . bold (
158+ selectedDevice . identifier
159+ ) } ${ getDeviceString ( selectedDevice ) } `
160+ ) ;
161+ }
162+ }
76163
77164 if ( ! deviceId ) {
78- throw new DeviceNotFoundError ( getDeviceName ( config . device ) ) ;
165+ throw new DeviceNotFoundError ( deviceName ) ;
79166 }
80167
81168 const isAvailable = await devicectl . isAppInstalled ( deviceId , config . bundleId ) ;
82169
83170 if ( ! isAvailable ) {
84- throw new AppNotInstalledError (
85- config . bundleId ,
86- getDeviceName ( config . device )
87- ) ;
171+ throw new AppNotInstalledError ( config . bundleId , deviceName ) ;
88172 }
89173
90174 return {
0 commit comments