@@ -479,6 +479,8 @@ try {
479479 )
480480 return
481481 document . body . dataset . captureReceipts = String ( ++ receipts )
482+ if ( 'sessionId' in event . data && typeof event . data . sessionId === 'string' )
483+ document . body . dataset . captureSession = event . data . sessionId
482484 } )
483485 } , base . origin )
484486 await observeCaptureReceipts ( )
@@ -556,7 +558,106 @@ try {
556558 captureText . replace ( 'QA_PRIVATE_PAGE_MARKER:' , 'Delivery plan\nQA_PRIVATE_PAGE_MARKER:' )
557559 )
558560 await screenshot ( 'page-preview' )
559- await preview . getByRole ( 'button' , { name : 'Close' , exact : true } ) . click ( )
561+ const focusSession = await shell . locator ( 'body' ) . getAttribute ( 'data-capture-session' )
562+ assert ( focusSession , 'The real capture did not acknowledge its session' )
563+ const focusObserver = await shell . evaluateHandle (
564+ ( { origin, sessionId } ) => {
565+ let focused = 0
566+ let processed = 0
567+ document . body . dataset . composerFocused = '0'
568+ document . body . dataset . focusProcessed = '0'
569+ const receive = ( event : MessageEvent < unknown > ) => {
570+ if (
571+ event . origin !== origin ||
572+ event . source !== document . querySelector ( 'iframe' ) ?. contentWindow ||
573+ typeof event . data !== 'object' ||
574+ event . data === null ||
575+ ! ( 'sessionId' in event . data ) ||
576+ event . data . sessionId !== sessionId ||
577+ ! ( 'type' in event . data )
578+ )
579+ return
580+ if ( event . data . type === 'composer-focused' )
581+ document . body . dataset . composerFocused = String ( ++ focused )
582+ if ( event . data . type === 'e2e-focus-processed' )
583+ document . body . dataset . focusProcessed = String ( ++ processed )
584+ }
585+ window . addEventListener ( 'message' , receive )
586+ return ( ) => window . removeEventListener ( 'message' , receive )
587+ } ,
588+ { origin : base . origin , sessionId : focusSession }
589+ )
590+ const focusBarrier = await frame ( ) . evaluateHandle (
591+ ( { origin, sessionId } ) => {
592+ const receive = ( event : MessageEvent < unknown > ) => {
593+ if (
594+ event . origin !== origin ||
595+ event . source !== parent ||
596+ typeof event . data !== 'object' ||
597+ event . data === null ||
598+ ! ( 'sessionId' in event . data ) ||
599+ event . data . sessionId !== sessionId ||
600+ ! ( 'type' in event . data ) ||
601+ event . data . type !== 'focus-composer'
602+ )
603+ return
604+ parent . postMessage ( { type : 'e2e-focus-processed' , sessionId } , origin )
605+ }
606+ window . addEventListener ( 'message' , receive )
607+ return ( ) => window . removeEventListener ( 'message' , receive )
608+ } ,
609+ { origin : `chrome-extension://${ extensionId } ` , sessionId : focusSession }
610+ )
611+ const requestComposerFocus = async ( processed : number ) => {
612+ await shell . evaluate (
613+ ( { origin, sessionId } ) =>
614+ document
615+ . querySelector ( 'iframe' )
616+ ?. contentWindow ?. postMessage (
617+ { channel : 'sim-extension' , version : 1 , type : 'focus-composer' , sessionId } ,
618+ origin
619+ ) ,
620+ { origin : base . origin , sessionId : focusSession }
621+ )
622+ await expect ( shell . locator ( 'body' ) ) . toHaveAttribute (
623+ 'data-focus-processed' ,
624+ String ( processed )
625+ )
626+ }
627+ try {
628+ await shell . bringToFront ( )
629+ const close = preview . getByRole ( 'button' , { name : 'Close' , exact : true } )
630+ await close . focus ( )
631+ await expect ( close ) . toBeFocused ( )
632+ assert ( await frame ( ) . evaluate ( ( ) => document . hasFocus ( ) ) )
633+ await requestComposerFocus ( 1 )
634+ assert . equal (
635+ await shell . locator ( 'body' ) . getAttribute ( 'data-composer-focused' ) ,
636+ '0' ,
637+ 'An app dialog must not acknowledge composer focus'
638+ )
639+ await expect ( close ) . toBeFocused ( )
640+ await close . press ( 'Tab' )
641+ assert ( await preview . evaluate ( ( element ) => element . contains ( document . activeElement ) ) )
642+ await requestComposerFocus ( 2 )
643+ assert . equal ( await shell . locator ( 'body' ) . getAttribute ( 'data-composer-focused' ) , '0' )
644+ await screenshot ( 'focus-deferred-by-page-preview' )
645+ await close . click ( )
646+ await expect ( preview ) . toHaveCount ( 0 )
647+ await requestComposerFocus ( 3 )
648+ const editor = frame ( ) . getByRole ( 'textbox' , { name : 'Message' , exact : true } )
649+ await expect ( editor ) . toBeFocused ( )
650+ await expect ( shell . locator ( 'body' ) ) . toHaveAttribute ( 'data-composer-focused' , '1' )
651+ await shell . keyboard . type ( 'Keyboard input belongs to the composer.' )
652+ await expect ( editor ) . toHaveValue ( 'Keyboard input belongs to the composer.' )
653+ await screenshot ( 'focus-confirmed-in-composer' )
654+ await editor . fill ( '' )
655+ } finally {
656+ await focusBarrier . evaluate ( ( stop ) => stop ( ) )
657+ await focusObserver . evaluate ( ( stop ) => stop ( ) )
658+ await focusBarrier . dispose ( )
659+ await focusObserver . dispose ( )
660+ }
560661 await capture ( )
561662 await capture ( )
562663 await capture ( )
0 commit comments