@@ -38,6 +38,8 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
38
38
readonly _defaultContext : CRBrowserContext ;
39
39
readonly _contexts = new Map < string , CRBrowserContext > ( ) ;
40
40
_targets = new Map < string , CRTarget > ( ) ;
41
+ readonly _firstPagePromise : Promise < void > ;
42
+ private _firstPageCallback = ( ) => { } ;
41
43
42
44
private _tracingRecording = false ;
43
45
private _tracingPath : string | null = '' ;
@@ -83,6 +85,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
83
85
this . _session . on ( 'Target.targetDestroyed' , this . _targetDestroyed . bind ( this ) ) ;
84
86
this . _session . on ( 'Target.targetInfoChanged' , this . _targetInfoChanged . bind ( this ) ) ;
85
87
this . _session . on ( 'Target.attachedToTarget' , this . _onAttachedToTarget . bind ( this ) ) ;
88
+ this . _firstPagePromise = new Promise ( f => this . _firstPageCallback = f ) ;
86
89
}
87
90
88
91
async newContext ( options : BrowserContextOptions = { } ) : Promise < BrowserContext > {
@@ -102,7 +105,7 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
102
105
return createPageInNewContext ( this , options ) ;
103
106
}
104
107
105
- async _onAttachedToTarget ( { targetInfo, sessionId, waitingForDebugger} : Protocol . Target . attachedToTargetPayload ) {
108
+ _onAttachedToTarget ( { targetInfo, sessionId, waitingForDebugger} : Protocol . Target . attachedToTargetPayload ) {
106
109
const session = this . _connection . session ( sessionId ) ! ;
107
110
if ( ! CRTarget . isPageType ( targetInfo . type ) ) {
108
111
assert ( targetInfo . type === 'service_worker' || targetInfo . type === 'browser' || targetInfo . type === 'other' ) ;
@@ -115,29 +118,24 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
115
118
return ;
116
119
}
117
120
const { context, target } = this . _createTarget ( targetInfo , session ) ;
118
- try {
119
- switch ( targetInfo . type ) {
120
- case 'page' : {
121
- const event = new PageEvent ( context , target . pageOrError ( ) ) ;
122
- context . emit ( CommonEvents . BrowserContext . Page , event ) ;
123
- const opener = target . opener ( ) ;
124
- if ( ! opener )
125
- break ;
126
- const openerPage = await opener . pageOrError ( ) ;
127
- if ( openerPage instanceof Page && ! openerPage . isClosed ( ) )
128
- openerPage . emit ( CommonEvents . Page . Popup , new PageEvent ( context , target . pageOrError ( ) ) ) ;
129
- break ;
130
- }
131
- case 'background_page' : {
132
- const event = new PageEvent ( context , target . pageOrError ( ) ) ;
133
- context . emit ( Events . CRBrowserContext . BackgroundPage , event ) ;
134
- break ;
135
- }
121
+
122
+ if ( ! CRTarget . isPageType ( targetInfo . type ) )
123
+ return ;
124
+ const pageEvent = new PageEvent ( context , target . pageOrError ( ) ) ;
125
+ target . pageOrError ( ) . then ( async ( ) => {
126
+ if ( targetInfo . type === 'page' ) {
127
+ this . _firstPageCallback ( ) ;
128
+ context . emit ( CommonEvents . BrowserContext . Page , pageEvent ) ;
129
+ const opener = target . opener ( ) ;
130
+ if ( ! opener )
131
+ return ;
132
+ const openerPage = await opener . pageOrError ( ) ;
133
+ if ( openerPage instanceof Page && ! openerPage . isClosed ( ) )
134
+ openerPage . emit ( CommonEvents . Page . Popup , pageEvent ) ;
135
+ } else if ( targetInfo . type === 'background_page' ) {
136
+ context . emit ( Events . CRBrowserContext . BackgroundPage , pageEvent ) ;
136
137
}
137
- } catch ( e ) {
138
- // Do not dispatch the event if initialization failed.
139
- debugError ( e ) ;
140
- }
138
+ } ) ;
141
139
}
142
140
143
141
async _targetCreated ( { targetInfo} : Protocol . Target . targetCreatedPayload ) {
@@ -176,10 +174,6 @@ export class CRBrowser extends platform.EventEmitter implements Browser {
176
174
await this . _session . send ( 'Target.closeTarget' , { targetId : CRTarget . fromPage ( page ) . _targetId } ) ;
177
175
}
178
176
179
- _allTargets ( ) : CRTarget [ ] {
180
- return Array . from ( this . _targets . values ( ) ) ;
181
- }
182
-
183
177
async close ( ) {
184
178
const disconnected = new Promise ( f => this . _connection . once ( ConnectionEvents . Disconnected , f ) ) ;
185
179
await Promise . all ( this . contexts ( ) . map ( context => context . close ( ) ) ) ;
@@ -268,19 +262,12 @@ export class CRBrowserContext extends BrowserContextBase {
268
262
await this . setHTTPCredentials ( this . _options . httpCredentials ) ;
269
263
}
270
264
271
- _existingPages ( ) : Page [ ] {
272
- const pages : Page [ ] = [ ] ;
273
- for ( const target of this . _browser . _allTargets ( ) ) {
274
- if ( target . context ( ) === this && target . _crPage )
275
- pages . push ( target . _crPage . page ( ) ) ;
276
- }
277
- return pages ;
265
+ _targets ( ) : CRTarget [ ] {
266
+ return Array . from ( this . _browser . _targets . values ( ) ) . filter ( target => target . context ( ) === this ) ;
278
267
}
279
268
280
- async pages ( ) : Promise < Page [ ] > {
281
- const targets = this . _browser . _allTargets ( ) . filter ( target => target . context ( ) === this && target . type ( ) === 'page' ) ;
282
- const pages = await Promise . all ( targets . map ( target => target . pageOrError ( ) ) ) ;
283
- return pages . filter ( page => ( page instanceof Page ) && ! page . isClosed ( ) ) as Page [ ] ;
269
+ pages ( ) : Page [ ] {
270
+ return this . _targets ( ) . filter ( target => target . type ( ) === 'page' ) . map ( target => target . _initializedPage ( ) ) . filter ( pageOrNull => ! ! pageOrNull ) as Page [ ] ;
284
271
}
285
272
286
273
async newPage ( ) : Promise < Page > {
@@ -351,51 +338,51 @@ export class CRBrowserContext extends BrowserContextBase {
351
338
if ( geolocation )
352
339
geolocation = verifyGeolocation ( geolocation ) ;
353
340
this . _options . geolocation = geolocation || undefined ;
354
- for ( const page of this . _existingPages ( ) )
341
+ for ( const page of this . pages ( ) )
355
342
await ( page . _delegate as CRPage ) . _client . send ( 'Emulation.setGeolocationOverride' , geolocation || { } ) ;
356
343
}
357
344
358
345
async setExtraHTTPHeaders ( headers : network . Headers ) : Promise < void > {
359
346
this . _options . extraHTTPHeaders = network . verifyHeaders ( headers ) ;
360
- for ( const page of this . _existingPages ( ) )
347
+ for ( const page of this . pages ( ) )
361
348
await ( page . _delegate as CRPage ) . updateExtraHTTPHeaders ( ) ;
362
349
}
363
350
364
351
async setOffline ( offline : boolean ) : Promise < void > {
365
352
this . _options . offline = offline ;
366
- for ( const page of this . _existingPages ( ) )
353
+ for ( const page of this . pages ( ) )
367
354
await ( page . _delegate as CRPage ) . _networkManager . setOffline ( offline ) ;
368
355
}
369
356
370
357
async setHTTPCredentials ( httpCredentials : types . Credentials | null ) : Promise < void > {
371
358
this . _options . httpCredentials = httpCredentials || undefined ;
372
- for ( const page of this . _existingPages ( ) )
359
+ for ( const page of this . pages ( ) )
373
360
await ( page . _delegate as CRPage ) . _networkManager . authenticate ( httpCredentials ) ;
374
361
}
375
362
376
363
async addInitScript ( script : Function | string | { path ?: string , content ?: string } , ...args : any [ ] ) {
377
364
const source = await helper . evaluationScript ( script , args ) ;
378
365
this . _evaluateOnNewDocumentSources . push ( source ) ;
379
- for ( const page of this . _existingPages ( ) )
366
+ for ( const page of this . pages ( ) )
380
367
await ( page . _delegate as CRPage ) . evaluateOnNewDocument ( source ) ;
381
368
}
382
369
383
370
async exposeFunction ( name : string , playwrightFunction : Function ) : Promise < void > {
384
- for ( const page of this . _existingPages ( ) ) {
371
+ for ( const page of this . pages ( ) ) {
385
372
if ( page . _pageBindings . has ( name ) )
386
373
throw new Error ( `Function "${ name } " has been already registered in one of the pages` ) ;
387
374
}
388
375
if ( this . _pageBindings . has ( name ) )
389
376
throw new Error ( `Function "${ name } " has been already registered` ) ;
390
377
const binding = new PageBinding ( name , playwrightFunction ) ;
391
378
this . _pageBindings . set ( name , binding ) ;
392
- for ( const page of this . _existingPages ( ) )
379
+ for ( const page of this . pages ( ) )
393
380
await ( page . _delegate as CRPage ) . exposeBinding ( binding ) ;
394
381
}
395
382
396
383
async route ( url : types . URLMatch , handler : network . RouteHandler ) : Promise < void > {
397
384
this . _routes . push ( { url, handler } ) ;
398
- for ( const page of this . _existingPages ( ) )
385
+ for ( const page of this . pages ( ) )
399
386
await ( page . _delegate as CRPage ) . updateRequestInterception ( ) ;
400
387
}
401
388
@@ -413,10 +400,8 @@ export class CRBrowserContext extends BrowserContextBase {
413
400
this . _didCloseInternal ( ) ;
414
401
}
415
402
416
- async backgroundPages ( ) : Promise < Page [ ] > {
417
- const targets = this . _browser . _allTargets ( ) . filter ( target => target . context ( ) === this && target . type ( ) === 'background_page' ) ;
418
- const pages = await Promise . all ( targets . map ( target => target . pageOrError ( ) ) ) ;
419
- return pages . filter ( page => ( page instanceof Page ) && ! page . isClosed ( ) ) as Page [ ] ;
403
+ backgroundPages ( ) : Page [ ] {
404
+ return this . _targets ( ) . filter ( target => target . type ( ) === 'background_page' ) . map ( target => target . _initializedPage ( ) ) . filter ( pageOrNull => ! ! pageOrNull ) as Page [ ] ;
420
405
}
421
406
422
407
async newCDPSession ( page : Page ) : Promise < CRSession > {
0 commit comments