@@ -29,6 +29,9 @@ const XCTEST_AGENT_SCHEME_NAME = 'HarnessXCTestAgent';
2929const XCTEST_AGENT_PORT_ENV = 'HARNESS_XCTEST_AGENT_PORT' ;
3030const XCTEST_AGENT_TARGET_BUNDLE_ID_ENV =
3131 'HARNESS_XCTEST_AGENT_TARGET_BUNDLE_ID' ;
32+ const XCTEST_AGENT_XCTESTRUN_FILE_ENV = 'HARNESS_IOS_XCTESTRUN_FILE' ;
33+ const XCTEST_AGENT_DERIVED_DATA_PATH_ENV =
34+ 'HARNESS_IOS_XCTEST_DERIVED_DATA_PATH' ;
3235const XCTEST_AGENT_STARTUP_TIMEOUT_MS = 120_000 ;
3336const XCTEST_AGENT_SHUTDOWN_TIMEOUT_MS = 5_000 ;
3437const XCTEST_AGENT_STARTUP_POLL_INTERVAL_MS = 250 ;
@@ -125,6 +128,34 @@ const getXCTestAgentDerivedDataPath = (target: XCTestAgentTarget): string => {
125128 return path . join ( getXCTestAgentBuildRoot ( ) , target . kind ) ;
126129} ;
127130
131+ const getEnvironmentPath = ( name : string ) : string | null => {
132+ const value = process . env [ name ] ?. trim ( ) ;
133+
134+ if ( ! value ) {
135+ return null ;
136+ }
137+
138+ return value ;
139+ } ;
140+
141+ const getExternalXCTestRunFilePath = ( ) : string | null => {
142+ return getEnvironmentPath ( XCTEST_AGENT_XCTESTRUN_FILE_ENV ) ;
143+ } ;
144+
145+ const getExternalDerivedDataPath = ( ) : string | null => {
146+ return getEnvironmentPath ( XCTEST_AGENT_DERIVED_DATA_PATH_ENV ) ;
147+ } ;
148+
149+ const assertExternalXCTestRunFileExists = ( filePath : string ) => {
150+ if ( fs . existsSync ( filePath ) ) {
151+ return ;
152+ }
153+
154+ throw new Error (
155+ `Missing external XCTest run file at ${ filePath } . Check ${ XCTEST_AGENT_XCTESTRUN_FILE_ENV } .`
156+ ) ;
157+ } ;
158+
128159const getXCTestAgentBuildManifestPath = ( derivedDataPath : string ) : string =>
129160 path . join ( derivedDataPath , 'build-manifest.json' ) ;
130161
@@ -724,6 +755,24 @@ export const createXCTestAgentController = (options: {
724755 return ;
725756 }
726757
758+ const externalXCTestRunFilePath = getExternalXCTestRunFilePath ( ) ;
759+ if ( externalXCTestRunFilePath ) {
760+ assertExternalXCTestRunFileExists ( externalXCTestRunFilePath ) ;
761+
762+ const externalDerivedDataPath = getExternalDerivedDataPath ( ) ;
763+ if ( externalDerivedDataPath ) {
764+ preparedDerivedDataPath = externalDerivedDataPath ;
765+ }
766+
767+ prepared = true ;
768+ xctestAgentLogger . info (
769+ 'Using external XCTest run file for %s target: %s' ,
770+ target . kind ,
771+ externalXCTestRunFilePath
772+ ) ;
773+ return ;
774+ }
775+
727776 const buildInputsHash = getProjectInputsHash ( ) ;
728777
729778 xctestAgentLogger . debug (
@@ -841,12 +890,23 @@ export const createXCTestAgentController = (options: {
841890 target . kind
842891 ) ;
843892 xctestAgentLogger . debug ( 'Using XCTest agent port %d' , port ) ;
893+ const externalXCTestRunFilePath = getExternalXCTestRunFilePath ( ) ;
894+ let xcodebuildRunInputArgs : string [ ] ;
895+
896+ if ( externalXCTestRunFilePath ) {
897+ xcodebuildRunInputArgs = [ '-xctestrun' , externalXCTestRunFilePath ] ;
898+ } else {
899+ xcodebuildRunInputArgs = [
900+ '-project' ,
901+ getXCTestAgentProjectFilePath ( ) ,
902+ '-scheme' ,
903+ XCTEST_AGENT_SCHEME_NAME ,
904+ ] ;
905+ }
906+
844907 const xcodebuildArgs = [
845908 'test-without-building' ,
846- '-project' ,
847- getXCTestAgentProjectFilePath ( ) ,
848- '-scheme' ,
849- XCTEST_AGENT_SCHEME_NAME ,
909+ ...xcodebuildRunInputArgs ,
850910 '-destination' ,
851911 getXCTestAgentRunDestination ( target ) ,
852912 '-parallel-testing-enabled' ,
0 commit comments