@@ -2112,109 +2112,109 @@ test("quotes plain timeline text into the composer, with or without a comment",
21122112 await expect ( chips ) . toHaveCount ( 0 )
21132113} )
21142114
2115- for ( const scenario of [
2116- { working : false , behavior : "queue" } ,
2117- { working : false , behavior : "steer" } ,
2118- { working : true , behavior : "queue" } ,
2119- { working : true , behavior : "steer" } ,
2120- ] as const ) {
2121- test ( `quote popup sends independently: ${ scenario . working ? "working" : "idle" } , ${ scenario . behavior } default` , async ( {
2122- page,
2123- } ) => {
2124- const sent : string [ ] = [ ]
2125-
2126- await setupTimeline ( page , {
2127- settings : { followUpBehavior : scenario . behavior } ,
2128- sessionStatus : { [ sessionID ] : { type : scenario . working ? "busy" : "idle" } } ,
2129- messages : [ userMessage ( ) , assistantMessage ( [ textPart ( "prt_direct_quote" , "Keep this quoted passage." ) ] ) ] ,
2130- findFiles : ( ) => [ "src/api.ts" ] ,
2131- onPrompt : ( input ) => {
2132- sent . push ( String ( input . body . delivery ) )
2133- } ,
2134- } )
2135-
2136- const answer = page . locator (
2137- `[data-timeline-part-id="${ renderedPartID ( "prt_direct_quote" ) } "] [data-slot="text-part-body"]` ,
2138- )
2115+ test ( "quote popup sends independently without consuming the draft or other quotes" , async ( { page } ) => {
2116+ const sent : string [ ] = [ ]
21392117
2140- await expect ( answer ) . toHaveText ( "Keep this quoted passage." )
2141- const editor = page . locator ( '[data-component="composer-editor"]' )
2142-
2143- await editor . fill ( "Keep my separate draft" )
2118+ await setupTimeline ( page , {
2119+ messages : [ userMessage ( ) , assistantMessage ( [ textPart ( "prt_direct_quote" , "Keep this quoted passage." ) ] ) ] ,
2120+ onPrompt : ( input ) => void sent . push ( String ( input . body . delivery ) ) ,
2121+ } )
21442122
2145- const select = ( ) =>
2146- answer . evaluate ( ( element ) => {
2147- const range = document . createRange ( )
2123+ const answer = page . locator (
2124+ `[data-timeline-part-id=" ${ renderedPartID ( "prt_direct_quote" ) } "] [data-slot="text-part-body"]` ,
2125+ )
21482126
2149- range . selectNodeContents ( element )
2150- window . getSelection ( ) ?. removeAllRanges ( )
2151- window . getSelection ( ) ?. addRange ( range )
2152- } )
2127+ const editor = page . locator ( '[data-component="composer-editor"]' )
21532128
2154- const quote = page
2155- . getByRole ( "toolbar" , { name : "Quote selection" } )
2156- . getByRole ( "button" , { name : "Quote" , exact : true } )
2129+ const quote = page
2130+ . getByRole ( "toolbar" , { name : "Quote selection" } )
2131+ . getByRole ( "button" , { name : "Quote" , exact : true } )
21572132
2158- await select ( )
2159- await quote . click ( { modifiers : [ "Alt" ] } )
2160- await select ( )
2161- await quote . click ( )
2162- const popup = page . locator ( '[data-component="composer-quote-comment"]' )
2133+ await expect ( answer ) . toHaveText ( "Keep this quoted passage." )
2134+ await editor . fill ( "Keep my separate draft" )
2135+ await selectQuoteText ( answer )
2136+ await quote . click ( { modifiers : [ "Alt" ] } )
2137+ await expect ( editor ) . toBeFocused ( )
2138+ await selectQuoteText ( answer )
2139+ await quote . click ( )
2140+ const popup = page . locator ( '[data-component="composer-quote-comment"]' )
21632141
2164- const comment = popup . locator ( "textarea" )
2142+ const comment = popup . locator ( "textarea" )
21652143
2166- const action = popup . locator ( '[data-slot="line-comment-v2-submit"]' )
2144+ const action = popup . getByRole ( "button" )
21672145
2168- const modifier = await page . evaluate ( ( ) => ( / ( M a c | i P o d | i P h o n e | i P a d ) / . test ( navigator . platform ) ? "Meta" : "Control" ) )
2146+ const modifier = await page . evaluate ( ( ) => ( / ( M a c | i P o d | i P h o n e | i P a d ) / . test ( navigator . platform ) ? "Meta" : "Control" ) )
21692147
2170- const delivery = ! scenario . working || scenario . behavior === "queue" ? "steer" : "queue"
2148+ await expect ( comment ) . toBeFocused ( )
2149+ await comment . fill ( "Explain this please" )
2150+ await action . focus ( )
2151+ await page . keyboard . down ( modifier )
2152+ await expect ( action ) . toHaveAccessibleName ( "Send quote" )
2153+ await page . keyboard . press ( "Enter" )
2154+ await page . keyboard . up ( modifier )
2155+ await expect ( popup ) . toHaveCount ( 0 )
2156+ await expect . poll ( ( ) => sent ) . toEqual ( [ "steer" ] )
2157+ await expect ( editor ) . toHaveText ( "Keep my separate draft" )
2158+ const remaining = page . locator ( '[data-component="composer-attachments"] [data-component="attachment-card"]' )
21712159
2172- const actionLabel = ! scenario . working ? "Send quote" : delivery === "queue" ? "Queue quote" : "Steer with quote"
2160+ await expect ( remaining ) . toHaveCount ( 1 )
2161+ await expect ( remaining ) . toContainText ( "Keep this quoted passage." )
2162+ await expect ( remaining ) . not . toContainText ( "Explain this please" )
2163+ } )
21732164
2174- const mentioning = scenario . working && scenario . behavior === "steer"
2165+ test ( "a pending quote send hides mentions and keeps the comment read-only" , async ( { page } ) => {
2166+ const sent : string [ ] = [ ]
21752167
2176- await expect ( comment ) . toBeFocused ( )
2177- await comment . fill ( mentioning ? "Explain @src/a" : "Explain this please" )
2168+ await setupTimeline ( page , {
2169+ settings : { followUpBehavior : "steer" } ,
2170+ sessionStatus : { [ sessionID ] : { type : "busy" } } ,
2171+ messages : [ userMessage ( ) , assistantMessage ( [ textPart ( "prt_quote_mentions" , "Keep this quoted passage." ) ] ) ] ,
2172+ findFiles : ( ) => [ "src/api.ts" ] ,
2173+ onPrompt : ( input ) => void sent . push ( String ( input . body . delivery ) ) ,
2174+ } )
21782175
2179- if ( mentioning ) await expect ( popup . locator ( '[data-slot="line-comment-v2-mention-item"]' ) ) . toHaveCount ( 1 )
2180- await expect ( action ) . toHaveCount ( 1 )
2181- await action . hover ( )
2182- await expect ( page . getByRole ( "tooltip" ) . filter ( { hasText : actionLabel } ) ) . toBeVisible ( )
2183- const bounds = await action . boundingBox ( )
2176+ const answer = page . locator (
2177+ `[data-timeline-part-id="${ renderedPartID ( "prt_quote_mentions" ) } "] [data-slot="text-part-body"]` ,
2178+ )
21842179
2185- await page . keyboard . down ( modifier )
2186- await expect ( action ) . toHaveAccessibleName ( actionLabel )
2187- expect ( await action . boundingBox ( ) ) . toEqual ( bounds )
2188- await page . keyboard . up ( modifier )
2189- await expect ( action ) . toHaveAccessibleName ( "Add comment" )
2180+ await expect ( answer ) . toHaveText ( "Keep this quoted passage." )
2181+ await expect ( page . locator ( '[data-component="composer-editor"]' ) ) . toBeFocused ( )
2182+ await selectQuoteText ( answer )
2183+ await page
2184+ . getByRole ( "toolbar" , { name : "Quote selection" } )
2185+ . getByRole ( "button" , { name : "Quote" , exact : true } )
2186+ . click ( )
2187+ const popup = page . locator ( '[data-component="composer-quote-comment"]' )
21902188
2191- const admission = await holdRoute ( page , new RegExp ( `/api/session/${ sessionID } /prompt(\\?|$)` ) , {
2192- method : "POST" ,
2193- } )
2189+ const comment = popup . locator ( "textarea" )
21942190
2195- if ( mentioning ) await action . click ( { modifiers : [ modifier ] } )
2191+ const modifier = await page . evaluate ( ( ) => ( / ( M a c | i P o d | i P h o n e | i P a d ) / . test ( navigator . platform ) ? "Meta" : "Control" ) )
21962192
2197- if ( ! mentioning )
2198- await ( ! scenario . working && scenario . behavior === "queue" ? action : comment ) . press ( `${ modifier } +Enter` )
2199- await admission . arrived
2200- await expect ( action ) . toBeDisabled ( )
2201- await expect ( comment ) . toHaveAttribute ( "readonly" , "" )
2202- await expect ( popup . locator ( '[data-component="loader-v2"]' ) ) . toBeVisible ( )
2193+ await comment . fill ( "Explain @src/a" )
2194+ await expect ( popup . locator ( '[data-slot="line-comment-v2-mention-item"]' ) ) . toHaveCount ( 1 )
2195+ const admission = await holdRoute ( page , new RegExp ( `/api/session/${ sessionID } /prompt(\\?|$)` ) , { method : "POST" } )
2196+
2197+ await popup . locator ( '[data-slot="line-comment-v2-submit"]' ) . click ( { modifiers : [ modifier ] } )
2198+ await admission . arrived
2199+ await expect ( popup . getByRole ( "button" ) ) . toBeDisabled ( )
2200+ await expect ( comment ) . toHaveAttribute ( "readonly" , "" )
2201+ await expect ( popup . locator ( '[data-component="loader-v2"]' ) ) . toBeVisible ( )
2202+ await expect ( popup . locator ( '[data-slot="line-comment-v2-mention-item"]' ) ) . toHaveCount ( 0 )
2203+ await comment . press ( "Tab" )
2204+ await expect ( comment ) . toHaveValue ( "Explain @src/a" )
2205+ expect ( admission . requests ) . toHaveLength ( 1 )
2206+ admission . release ( )
2207+ await expect ( popup ) . toHaveCount ( 0 )
2208+ await expect . poll ( ( ) => sent ) . toEqual ( [ "queue" ] )
2209+ } )
22032210
2204- if ( mentioning ) {
2205- await expect ( popup . locator ( '[data-slot="line-comment-v2-mention-item"]' ) ) . toHaveCount ( 0 )
2206- await comment . press ( "Tab" )
2207- await expect ( comment ) . toHaveValue ( "Explain @src/a" )
2208- }
2211+ function selectQuoteText ( target : Locator ) {
2212+ return target . evaluate ( ( element ) => {
2213+ const range = document . createRange ( )
22092214
2210- expect ( admission . requests ) . toHaveLength ( 1 )
2211- admission . release ( )
2212- await expect ( popup ) . toHaveCount ( 0 )
2213- await expect . poll ( ( ) => sent ) . toEqual ( [ delivery ] )
2214- await expect ( editor ) . toHaveText ( "Keep my separate draft" )
2215- await expect (
2216- page . locator ( '[data-component="composer-attachments"] [data-component="attachment-card"]' ) ,
2217- ) . toHaveCount ( 1 )
2215+ range . selectNodeContents ( element )
2216+ window . getSelection ( ) ?. removeAllRanges ( )
2217+ window . getSelection ( ) ?. addRange ( range )
22182218 } )
22192219}
22202220
@@ -2233,13 +2233,7 @@ test("a failed direct quote send keeps the popup and comment for retry", async (
22332233 )
22342234
22352235 await expect ( answer ) . toHaveText ( "Keep this quoted passage." )
2236- await answer . evaluate ( ( element ) => {
2237- const range = document . createRange ( )
2238-
2239- range . selectNodeContents ( element )
2240- window . getSelection ( ) ?. removeAllRanges ( )
2241- window . getSelection ( ) ?. addRange ( range )
2242- } )
2236+ await selectQuoteText ( answer )
22432237 await page
22442238 . getByRole ( "toolbar" , { name : "Quote selection" } )
22452239 . getByRole ( "button" , { name : "Quote" , exact : true } )
0 commit comments