@@ -50,6 +50,8 @@ export class WorkerMain extends ProcessRunner {
5050 private _didRunFullCleanup = false ;
5151 // Whether the worker was requested to stop.
5252 private _isStopped = false ;
53+ // Whether a fatal error was caused by a missing project.
54+ private _isMissingProject = false ;
5355 // This promise resolves once the single "run test group" call finishes.
5456 private _runFinished = new ManualPromise < void > ( ) ;
5557 private _currentTest : TestInfoImpl | null = null ;
@@ -103,13 +105,18 @@ export class WorkerMain extends ProcessRunner {
103105 }
104106
105107 override async gracefullyClose ( ) {
108+ if ( this . _isMissingProject ) {
109+ // Never set anything up and we can crash on attempting cleanup
110+ return ;
111+ }
112+
106113 try {
107114 await this . _stop ( ) ;
108115 // Ignore top-level errors, they are already inside TestInfo.errors.
109116 const fakeTestInfo = new TestInfoImpl ( this . _config , this . _project , this . _params , undefined , 0 , ( ) => { } , ( ) => { } , ( ) => { } ) ;
110117 const runnable = { type : 'teardown' } as const ;
111118 // We have to load the project to get the right deadline below.
112- await fakeTestInfo . _runAsStage ( { title : 'worker cleanup' , runnable } , ( ) => this . _loadIfNeeded ( ) ) . catch ( ( ) => { } ) ;
119+ await fakeTestInfo . _runAsStage ( { title : 'worker cleanup' , runnable } , ( ) => this . _load ( ) ) . catch ( ( ) => { } ) ;
113120 await this . _fixtureRunner . teardownScope ( 'test' , fakeTestInfo , runnable ) . catch ( ( ) => { } ) ;
114121 await this . _fixtureRunner . teardownScope ( 'worker' , fakeTestInfo , runnable ) . catch ( ( ) => { } ) ;
115122 // Close any other browsers launched in this process. This includes anything launched
@@ -186,28 +193,43 @@ export class WorkerMain extends ProcessRunner {
186193 void this . _stop ( ) ;
187194 }
188195
189- private async _loadIfNeeded ( ) {
196+ private async _load ( ) : Promise < {
197+ config : FullConfigInternal ,
198+ project : FullProjectInternal ,
199+ poolBuilder : PoolBuilder ,
200+ } | undefined > {
190201 if ( this . _config )
191- return ;
202+ return { config : this . _config , project : this . _project , poolBuilder : this . _poolBuilder } ;
192203
193204 this . _config = await deserializeConfig ( this . _params . config ) ;
194- this . _project = this . _config . projects . find ( p => p . id === this . _params . projectId ) ! ;
205+ const project = this . _config . projects . find ( p => p . id === this . _params . projectId ) ;
206+ if ( ! project )
207+ return undefined ;
208+ this . _project = project ;
195209 this . _poolBuilder = PoolBuilder . createForWorker ( this . _project ) ;
210+
211+ return { config : this . _config , project : this . _project , poolBuilder : this . _poolBuilder } ;
196212 }
197213
198214 async runTestGroup ( runPayload : RunPayload ) {
199215 this . _runFinished = new ManualPromise < void > ( ) ;
200216 const entries = new Map ( runPayload . entries . map ( e => [ e . testId , e ] ) ) ;
201- let fatalUnknownTestIds ;
217+ let fatalUnknownTestIds : string [ ] | undefined ;
202218 try {
203- await this . _loadIfNeeded ( ) ;
204- const fileSuite = await loadTestFile ( runPayload . file , this . _config . config . rootDir ) ;
205- const suite = bindFileSuiteToProject ( this . _project , fileSuite ) ;
219+ const workerState = await this . _load ( ) ;
220+ if ( ! workerState ) {
221+ this . _isMissingProject = true ;
222+ void this . _stop ( ) ;
223+ return ;
224+ }
225+ const { config, project, poolBuilder } = workerState ;
226+ const fileSuite = await loadTestFile ( runPayload . file , config . config . rootDir ) ;
227+ const suite = bindFileSuiteToProject ( project , fileSuite ) ;
206228 if ( this . _params . repeatEachIndex )
207- applyRepeatEachIndex ( this . _project , suite , this . _params . repeatEachIndex ) ;
229+ applyRepeatEachIndex ( project , suite , this . _params . repeatEachIndex ) ;
208230 const hasEntries = filterTestsRemoveEmptySuites ( suite , test => entries . has ( test . id ) ) ;
209231 if ( hasEntries ) {
210- this . _poolBuilder . buildPools ( suite ) ;
232+ poolBuilder . buildPools ( suite ) ;
211233 this . _activeSuites = new Map ( ) ;
212234 this . _didRunFullCleanup = false ;
213235 const tests = suite . allTests ( ) ;
@@ -235,7 +257,8 @@ export class WorkerMain extends ProcessRunner {
235257 const donePayload : DonePayload = {
236258 fatalErrors : this . _fatalErrors ,
237259 skipTestsDueToSetupFailure : [ ] ,
238- fatalUnknownTestIds
260+ fatalUnknownTestIds,
261+ missingProjectById : this . _isMissingProject ? this . _params . projectId : undefined
239262 } ;
240263 for ( const test of this . _skipRemainingTestsInSuite ?. allTests ( ) || [ ] ) {
241264 if ( entries . has ( test . id ) )
0 commit comments