@@ -176,28 +176,31 @@ test.describe('desktop tools against a live Sim', () => {
176176
177177 const composer = ( page : Page ) => page . getByRole ( 'textbox' ) . last ( )
178178
179+ /** The dev app's error overlay, if it is up, with the errors the window reported. */
180+ async function devOverlayError ( page : Page ) : Promise < string | undefined > {
181+ const overlay = page . locator ( 'nextjs-portal [data-nextjs-dialog]' )
182+ if ( ( await overlay . count ( ) ) === 0 ) return undefined
183+ return `Next.js error overlay: ${ await overlay . first ( ) . innerText ( ) } \n${ pageErrors . join ( '\n' ) } `
184+ }
185+
179186 /**
180187 * Clicks `target`, failing at once with the dev app's error instead of waiting out a click the
181188 * Next.js error overlay intercepts.
182189 */
183190 async function click ( page : Page , target : Locator , timeout = 15_000 ) : Promise < void > {
184- const overlay = page . locator ( 'nextjs-portal [data-nextjs-dialog]' )
185- const blocked = async ( ) =>
186- ( await overlay . count ( ) ) > 0
187- ? `Next.js error overlay: ${ await overlay . first ( ) . innerText ( ) } \n${ pageErrors . join ( '\n' ) } `
188- : undefined
189- const before = await blocked ( )
191+ const before = await devOverlayError ( page )
190192 if ( before ) throw new Error ( before )
191193 try {
192194 await target . click ( { timeout } )
193195 } catch ( error ) {
194- throw new Error ( ( await blocked ( ) ) ?? String ( error ) )
196+ throw new Error ( ( await devOverlayError ( page ) ) ?? String ( error ) )
195197 }
196198 }
197199
198200 /**
199201 * Sends `message` and waits until the turn reached Sim. A page still hydrating can drop the
200- * typed text or the click, so the message is typed and sent again only while no turn went out.
202+ * typed text (the Send button only shows for a non-empty message) or the click, so the message
203+ * is typed and sent again only while no turn went out.
201204 */
202205 async function send ( page : Page , message : string , timeout = 60_000 ) : Promise < void > {
203206 const since = Date . now ( )
@@ -207,13 +210,20 @@ test.describe('desktop tools against a live Sim', () => {
207210 . some ( ( entry ) => entry . method === 'POST' && entry . path === '/api/mothership/chat' )
208211 const deadline = Date . now ( ) + timeout
209212 while ( ! sent ( ) ) {
213+ const overlay = await devOverlayError ( page )
214+ if ( overlay ) throw new Error ( overlay )
210215 if ( Date . now ( ) > deadline ) throw new Error ( `The message was never sent: ${ message } ` )
211216 if ( ( await composer ( page ) . inputValue ( ) ) !== message ) await composer ( page ) . fill ( message )
212- await click ( page , page . getByRole ( 'button' , { name : 'Send message' } ) )
213- await expect
214- . poll ( sent , { timeout : 10_000 } )
215- . toBe ( true )
216- . catch ( ( ) => { } )
217+ const clicked = await page
218+ . getByRole ( 'button' , { name : 'Send message' } )
219+ . click ( { timeout : 5_000 } )
220+ . then ( ( ) => true )
221+ . catch ( ( ) => false )
222+ if ( clicked )
223+ await expect
224+ . poll ( sent , { timeout : 10_000 } )
225+ . toBe ( true )
226+ . catch ( ( ) => { } )
217227 }
218228 }
219229
@@ -224,7 +234,7 @@ test.describe('desktop tools against a live Sim', () => {
224234 title : string ,
225235 timeout = 30_000
226236 ) : Promise < void > {
227- await click ( page , page . getByRole ( 'link' , { name : title } ) . first ( ) )
237+ await click ( page , page . getByRole ( 'link' , { name : title } ) . first ( ) , timeout )
228238 await expect ( page ) . toHaveURL ( new RegExp ( `${ user . chats [ title ] } $` ) , { timeout } )
229239 }
230240
0 commit comments