11import { AppiumXCUITestCapabilities } from '@wdio/types/build/Capabilities' ;
22import { W3CCapabilities } from '@wdio/types/build/Capabilities' ;
33import dotenv from 'dotenv' ;
4+ import { existsSync , readFileSync } from 'fs' ;
45
56import { IntRange } from '../../../types/RangeType' ;
7+
68dotenv . config ( ) ;
9+
710const iosPathPrefix = process . env . IOS_APP_PATH_PREFIX ;
811
912if ( ! iosPathPrefix ) {
@@ -16,8 +19,8 @@ console.log(`iOS app full path: ${iosAppFullPath}`);
1619const sharediOSCapabilities : AppiumXCUITestCapabilities = {
1720 'appium:app' : iosAppFullPath ,
1821 'appium:platformName' : 'iOS' ,
19- 'appium:platformVersion' : '17.2 ' ,
20- 'appium:deviceName' : 'iPhone 15 Pro Max' ,
22+ 'appium:platformVersion' : '18.3 ' ,
23+ 'appium:deviceName' : 'iPhone 16 Pro Max' ,
2124 'appium:automationName' : 'XCUITest' ,
2225 'appium:bundleId' : 'com.loki-project.loki-messenger' ,
2326 'appium:newCommandTimeout' : 300000 ,
@@ -31,62 +34,92 @@ const sharediOSCapabilities: AppiumXCUITestCapabilities = {
3134 communityPollLimit : 5 ,
3235 } ,
3336 } ,
34- // "appium:isHeadless": true,
3537} as AppiumXCUITestCapabilities ;
3638
37- const envVars = [
38- 'IOS_1_SIMULATOR' ,
39- 'IOS_2_SIMULATOR' ,
40- 'IOS_3_SIMULATOR' ,
41- 'IOS_4_SIMULATOR' ,
42- 'IOS_5_SIMULATOR' ,
43- 'IOS_6_SIMULATOR' ,
44- 'IOS_7_SIMULATOR' ,
45- 'IOS_8_SIMULATOR' ,
46- 'IOS_9_SIMULATOR' ,
47- 'IOS_10_SIMULATOR' ,
48- 'IOS_11_SIMULATOR' ,
49- 'IOS_12_SIMULATOR' ,
50- ] as const ;
51-
52- function getIOSSimulatorUUIDFromEnv ( index : CapabilitiesIndexType ) : string {
53- const envVar = envVars [ index ] ;
54- const uuid = process . env [ envVar ] ;
55-
56- if ( ! uuid ) {
57- throw new Error ( `Environment variable ${ envVar } is not set` ) ;
39+ export type Simulator = {
40+ name : string ;
41+ udid : string ;
42+ wdaPort : number ;
43+ } ;
44+
45+ function loadSimulators ( ) : Simulator [ ] {
46+ const jsonPath = 'ci-simulators.json' ;
47+
48+ // Load from .env variables
49+ const envVars = [
50+ 'IOS_1_SIMULATOR' ,
51+ 'IOS_2_SIMULATOR' ,
52+ 'IOS_3_SIMULATOR' ,
53+ 'IOS_4_SIMULATOR' ,
54+ 'IOS_5_SIMULATOR' ,
55+ 'IOS_6_SIMULATOR' ,
56+ 'IOS_7_SIMULATOR' ,
57+ 'IOS_8_SIMULATOR' ,
58+ 'IOS_9_SIMULATOR' ,
59+ 'IOS_10_SIMULATOR' ,
60+ 'IOS_11_SIMULATOR' ,
61+ 'IOS_12_SIMULATOR' ,
62+ ] ;
63+
64+ const simulators = envVars
65+ . map ( ( envVar , index ) => {
66+ const udid = process . env [ envVar ] ;
67+ if ( ! udid ) return null ; // No need for all 12 sim variables to be set
68+ return { name : `Sim-${ index + 1 } ` , udid, wdaPort : 1253 + index } ;
69+ } )
70+ . filter ( ( sim ) : sim is Simulator => sim !== null ) ;
71+
72+ // If we have simulators from env, use them (local dev)
73+ if ( simulators . length > 0 ) {
74+ console . log ( `Using ${ simulators . length } simulators from .env file` ) ;
75+ return simulators ;
76+ }
77+
78+ // No env simulators - check if we're on CI
79+ if ( process . env . CI === '1' ) {
80+ // CI should use JSON
81+ if ( existsSync ( jsonPath ) ) {
82+ console . log ( 'Using simulators from ios-simulators.json (CI)' ) ;
83+ const sims : Simulator [ ] = JSON . parse ( readFileSync ( jsonPath , 'utf-8' ) ) ;
84+ return sims ;
85+ }
86+ throw new Error ( 'CI mode: ios-simulators.json not found' ) ;
5887 }
5988
60- return uuid ;
89+ // Local dev with no .env entries
90+ throw new Error (
91+ 'No iOS simulators found in .env\n' +
92+ 'Run: yarn create-simulators <number>\n' +
93+ 'Example: yarn create-simulators 4'
94+ ) ;
6195}
62- const MAX_CAPABILITIES_INDEX = envVars . length ;
96+ const simulators = loadSimulators ( ) ;
97+
98+ const capabilities = simulators . map ( sim => ( {
99+ ...sharediOSCapabilities ,
100+ 'appium:udid' : sim . udid ,
101+ 'appium:wdaLocalPort' : sim . wdaPort ,
102+ } ) ) ;
103+
104+ // Use a constant max that matches the envVars array length for type safety
105+ const _MAX_CAPABILITIES_INDEX = 12 as const ;
63106
64- export type CapabilitiesIndexType = IntRange < 0 , typeof MAX_CAPABILITIES_INDEX > ;
107+ // For runtime validation, check against actual loaded simulators
108+ export const getMaxCapabilitiesIndex = ( ) => capabilities . length ;
109+
110+ // Type is still based on the constant for compile-time safety
111+ export type CapabilitiesIndexType = IntRange < 0 , typeof _MAX_CAPABILITIES_INDEX > ;
65112
66113export function capabilityIsValid (
67114 capabilitiesIndex : number
68115) : capabilitiesIndex is CapabilitiesIndexType {
69- if ( capabilitiesIndex < 0 || capabilitiesIndex > MAX_CAPABILITIES_INDEX ) {
116+ // Runtime validation against actual loaded capabilities
117+ if ( capabilitiesIndex < 0 || capabilitiesIndex >= capabilities . length ) {
70118 return false ;
71119 }
72120 return true ;
73121}
74122
75- interface CustomW3CCapabilities extends W3CCapabilities {
76- 'appium:wdaLocalPort' : number ;
77- 'appium:udid' : string ;
78- }
79-
80- const emulatorUUIDs = Array . from ( { length : MAX_CAPABILITIES_INDEX } , ( _ , index ) =>
81- getIOSSimulatorUUIDFromEnv ( index as CapabilitiesIndexType )
82- ) ;
83-
84- const capabilities = emulatorUUIDs . map ( ( udid , index ) => ( {
85- ...sharediOSCapabilities ,
86- 'appium:udid' : udid ,
87- 'appium:wdaLocalPort' : 1253 + index ,
88- } ) ) ;
89-
90123export function getIosCapabilities ( capabilitiesIndex : CapabilitiesIndexType ) : W3CCapabilities {
91124 if ( capabilitiesIndex >= capabilities . length ) {
92125 throw new Error (
@@ -102,11 +135,11 @@ export function getIosCapabilities(capabilitiesIndex: CapabilitiesIndexType): W3
102135 } ;
103136}
104137
105- export function getCapabilitiesForWorker ( workerId : number ) : CustomW3CCapabilities {
138+ export function getCapabilitiesForWorker ( workerId : number ) {
106139 const emulator = capabilities [ workerId % capabilities . length ] ;
107140 return {
108141 ...sharediOSCapabilities ,
109142 'appium:udid' : emulator [ 'appium:udid' ] ,
110143 'appium:wdaLocalPort' : emulator [ 'appium:wdaLocalPort' ] ,
111- } as CustomW3CCapabilities ;
144+ } ;
112145}
0 commit comments