@@ -36,7 +36,12 @@ test.describe("Bound thread and binding ledger UX", () => {
3636 await expect ( page . getByRole ( "heading" , { level : 2 , name : title } ) ) . toBeVisible ( ) ;
3737 await page . locator ( ".tabs" ) . getByRole ( "tab" , { name : / D i s c u s s / } ) . click ( ) ;
3838
39- await expect ( page . locator ( ".os-chat-binding-banner-head strong" , { hasText : "Binding ledger" } ) ) . toBeVisible ( ) ;
39+ // First-time Discuss view bootstraps a bound thread server-side and
40+ // then renders the binding banner; allow extra time on top of the
41+ // 5s default for slow concurrent runs.
42+ await expect (
43+ page . locator ( ".os-chat-binding-banner-head strong" , { hasText : "Binding ledger" } ) ,
44+ ) . toBeVisible ( { timeout : 15000 } ) ;
4045 await expect ( page . getByText ( "Task-bound" ) ) . toBeVisible ( ) ;
4146 await expect ( page . getByText ( "Ledger" , { exact : true } ) ) . toBeVisible ( ) ;
4247 await expect ( page . getByText ( / p r o j e c t : / ) ) . toBeVisible ( ) ;
@@ -81,9 +86,17 @@ test.describe("Bound thread and binding ledger UX", () => {
8186
8287 await page . goto ( `/team/${ agent . id } ` ) ;
8388 await expect ( page . getByRole ( "heading" , { level : 1 , name : agent . display_name } ) ) . toBeVisible ( ) ;
89+ // Make sure the Threads tab is selected — the agent profile may
90+ // remember a previously-selected tab from this browsing session
91+ // when re-entering the page (eg. mobile re-uses the cached state).
92+ const threadsTab = page . getByRole ( "tab" , { name : "Threads" , exact : true } ) ;
93+ if ( await threadsTab . isVisible ( ) . catch ( ( ) => false ) ) {
94+ await threadsTab . click ( ) ;
95+ }
8496
8597 const threadCard = page . locator ( ".os-profile-card" , { hasText : threadTitle } ) . first ( ) ;
86- await expect ( threadCard ) . toBeVisible ( ) ;
98+ await threadCard . scrollIntoViewIfNeeded ( ) . catch ( ( ) => undefined ) ;
99+ await expect ( threadCard ) . toBeVisible ( { timeout : 10000 } ) ;
87100 await expect ( threadCard . getByText ( "Task-bound" ) ) . toBeVisible ( ) ;
88101 await expect ( threadCard . getByText ( "Ledger" ) ) . toBeVisible ( ) ;
89102 await threadCard . getByRole ( "button" , { name : "Continue Chat" } ) . click ( ) ;
@@ -110,9 +123,10 @@ test.describe("Bound thread and binding ledger UX", () => {
110123 expect ( taskResp . ok ( ) ) . toBeTruthy ( ) ;
111124 const task = await taskResp . json ( ) ;
112125
126+ const threadTitle = `Global thread ${ Date . now ( ) } ` ;
113127 const threadResp = await request . post ( "/v1/threads" , {
114128 data : {
115- title : `Global thread ${ Date . now ( ) } ` ,
129+ title : threadTitle ,
116130 task_id : task . id ,
117131 agent_id : "coder" ,
118132 } ,
@@ -121,8 +135,14 @@ test.describe("Bound thread and binding ledger UX", () => {
121135 const thread = await threadResp . json ( ) ;
122136
123137 await page . goto ( `/chat?agent=coder&thread=${ thread . id } &task=${ task . id } ` ) ;
124- await expect ( page . locator ( ".os-chat-thread-item" ) . first ( ) . getByText ( "Task-bound" ) ) . toBeVisible ( ) ;
125- await expect ( page . locator ( ".os-chat-thread-item" ) . first ( ) . getByText ( "Ledger" ) ) . toBeVisible ( ) ;
138+ // Other tests in this suite (run with workers=2 against a shared
139+ // server) leave background threads ahead of ours, so locking onto
140+ // the just-created thread by title — instead of `.first()` — is
141+ // more reliable on the chromium-mobile project.
142+ const threadItem = page . locator ( ".os-chat-thread-item" , { hasText : threadTitle } ) . first ( ) ;
143+ await threadItem . scrollIntoViewIfNeeded ( ) . catch ( ( ) => undefined ) ;
144+ await expect ( threadItem . getByText ( "Task-bound" ) ) . toBeVisible ( { timeout : 10000 } ) ;
145+ await expect ( threadItem . getByText ( "Ledger" ) ) . toBeVisible ( ) ;
126146 await expect ( page . locator ( ".os-chat-binding-banner-head strong" , { hasText : "Binding ledger" } ) ) . toBeVisible ( ) ;
127147
128148 await page . goto ( "/chat?agent=coder" ) ;
0 commit comments