@@ -87,6 +87,19 @@ const chatResponses: {
8787} [ ] = [ ]
8888const uploadRequests : { event : string ; stage : string ; method : string ; status ?: number } [ ] = [ ]
8989const draftRemovalReceipts : { scope : string ; phase : string ; matches : number } [ ] = [ ]
90+ const submissionFocusReceipts : {
91+ scope : string
92+ events : {
93+ event : string
94+ activeTag : string | null
95+ activeLabel : string | null
96+ inputFocused : boolean
97+ inputConnected : boolean
98+ documentFocused : boolean
99+ inert : boolean
100+ oldInert : string | null
101+ } [ ]
102+ } [ ] = [ ]
90103const responseDiagnostics : Promise < void > [ ] = [ ]
91104const chatTurns = new Map < string , number > ( )
92105const chatAttempts : {
@@ -2030,25 +2043,70 @@ try {
20302043 await input ( ) . fill ( draft )
20312044 count = received . length
20322045 phase = 'denied-send'
2033- await frame ( )
2034- . getByRole ( 'button' , { name : org ? 'Send' : 'Send message' , exact : true } )
2035- . click ( )
2036- await expect (
2037- shell . getByRole ( 'button' , { name : 'Request site access' , exact : true } )
2038- ) . toBeEnabled ( )
2039- await expect ( input ( ) ) . toHaveValue ( draft )
2040- await expect
2041- . poll ( ( ) => input ( ) . evaluate ( ( element ) => Boolean ( element . closest ( '[inert]' ) ) ) )
2042- . toBe ( false )
2043- assert . equal ( received . length , count )
2044- assert (
2045- await frame ( ) . evaluate ( ( ) => document . hasFocus ( ) ) ,
2046- 'The denied mouse send must keep the chat document focused'
2047- )
2048- await expect ( input ( ) ) . toBeFocused ( )
2049- await shell . keyboard . type ( ' Continue typing after the denied capture.' )
2050- await expect ( input ( ) ) . toHaveValue ( `${ draft } Continue typing after the denied capture.` )
2051- assert . equal ( received . length , count )
2046+ const focusTrace = await input ( ) . evaluateHandle ( ( element ) => {
2047+ const events : ( typeof submissionFocusReceipts ) [ number ] [ 'events' ] = [ ]
2048+ const record = ( event : string , oldInert : string | null = null ) => {
2049+ if ( events . length >= 64 ) return
2050+ events . push ( {
2051+ event,
2052+ activeTag : document . activeElement ?. tagName ?? null ,
2053+ activeLabel : document . activeElement ?. getAttribute ( 'aria-label' ) ?? null ,
2054+ inputFocused : document . activeElement === element ,
2055+ inputConnected : element . isConnected ,
2056+ documentFocused : document . hasFocus ( ) ,
2057+ inert : Boolean ( element . closest ( '[inert]' ) ) ,
2058+ oldInert,
2059+ } )
2060+ }
2061+ const observeEvent = ( event : Event ) => record ( event . type )
2062+ const types = [ 'pointerdown' , 'click' , 'focus' , 'blur' ] as const
2063+ for ( const type of types ) window . addEventListener ( type , observeEvent , true )
2064+ const observer = new MutationObserver ( ( records ) => {
2065+ for ( const mutation of records ) record ( 'inert-mutation' , mutation . oldValue )
2066+ } )
2067+ observer . observe ( document . body , {
2068+ attributes : true ,
2069+ subtree : true ,
2070+ attributeFilter : [ 'inert' ] ,
2071+ attributeOldValue : true ,
2072+ } )
2073+ record ( 'before-mouse-send' )
2074+ return {
2075+ finish ( ) {
2076+ record ( 'after-mouse-send' )
2077+ observer . disconnect ( )
2078+ for ( const type of types ) window . removeEventListener ( type , observeEvent , true )
2079+ return events
2080+ } ,
2081+ }
2082+ } )
2083+ try {
2084+ await frame ( )
2085+ . getByRole ( 'button' , { name : org ? 'Send' : 'Send message' , exact : true } )
2086+ . click ( )
2087+ await expect (
2088+ shell . getByRole ( 'button' , { name : 'Request site access' , exact : true } )
2089+ ) . toBeEnabled ( )
2090+ await expect ( input ( ) ) . toHaveValue ( draft )
2091+ await expect
2092+ . poll ( ( ) => input ( ) . evaluate ( ( element ) => Boolean ( element . closest ( '[inert]' ) ) ) )
2093+ . toBe ( false )
2094+ assert . equal ( received . length , count )
2095+ assert (
2096+ await frame ( ) . evaluate ( ( ) => document . hasFocus ( ) ) ,
2097+ 'The denied mouse send must keep the chat document focused'
2098+ )
2099+ await expect ( input ( ) ) . toBeFocused ( )
2100+ await shell . keyboard . type ( ' Continue typing after the denied capture.' )
2101+ await expect ( input ( ) ) . toHaveValue ( `${ draft } Continue typing after the denied capture.` )
2102+ assert . equal ( received . length , count )
2103+ } finally {
2104+ submissionFocusReceipts . push ( {
2105+ scope : org ? 'organization' : 'workspace' ,
2106+ events : await focusTrace . evaluate ( ( trace ) => trace . finish ( ) ) ,
2107+ } )
2108+ await focusTrace . dispose ( )
2109+ }
20522110 await screenshot ( `reference-${ org ? 'organization' : 'workspace' } -denied` )
20532111 const accessNotice = await shell
20542112 . getByRole ( 'status' )
@@ -3029,6 +3087,7 @@ try {
30293087 dropReceipts,
30303088 uploadRequests,
30313089 draftRemovalReceipts,
3090+ submissionFocusReceipts,
30323091 } ,
30333092 null ,
30343093 2
0 commit comments