@@ -151,21 +151,28 @@ test.describe("Sidebar search", () => {
151151 await page . goto ( `/${ workspaceSlug } ` ) ;
152152 await waitForSidebarReady ( page ) ;
153153
154- // Search for the page
154+ // Search for the page. Use expect.toPass to retry the entire search
155+ // flow — Supabase read-replicas may have a short replication lag after
156+ // the title save, causing the first search attempt to return no results.
155157 const searchInput = page . getByRole ( "combobox" , { name : / s e a r c h p a g e s / i } ) ;
156158 await expect ( searchInput ) . toBeVisible ( { timeout : 5_000 } ) ;
157- await searchInput . click ( ) ;
158- await searchInput . fill ( navUniqueWord ) ;
159159
160- // Wait for results
161- const resultsList = page . locator ( "#search-results" ) ;
162- await expect ( resultsList ) . toBeVisible ( { timeout : 5_000 } ) ;
160+ await expect ( async ( ) => {
161+ await searchInput . click ( ) ;
162+ await searchInput . fill ( navUniqueWord ) ;
163163
164- const resultOption = resultsList . locator ( '[role="option"]' ) . first ( ) ;
165- await expect ( resultOption ) . toBeVisible ( { timeout : 5_000 } ) ;
166- await expect ( resultOption ) . toContainText ( "Navigate" ) ;
164+ // Wait for debounce (300ms) + network response
165+ const resultsList = page . locator ( "#search-results" ) ;
166+ await expect ( resultsList ) . toBeVisible ( { timeout : 5_000 } ) ;
167+
168+ const resultOption = resultsList . locator ( '[role="option"]' ) . first ( ) ;
169+ await expect ( resultOption ) . toBeVisible ( { timeout : 5_000 } ) ;
170+ await expect ( resultOption ) . toContainText ( "Navigate" ) ;
171+ } ) . toPass ( { timeout : 15_000 , intervals : [ 2_000 , 3_000 , 5_000 ] } ) ;
167172
168- // Click the result
173+ // Click the result (outside toPass — we only need to retry the search)
174+ const resultsList = page . locator ( "#search-results" ) ;
175+ const resultOption = resultsList . locator ( '[role="option"]' ) . first ( ) ;
169176 await resultOption . click ( ) ;
170177
171178 // Should navigate to the page URL containing the page ID
@@ -216,20 +223,30 @@ test.describe("Sidebar search", () => {
216223 const scopeTitle = `Scoped ${ scopeWord } Page` ;
217224 await createPageWithTitle ( page , scopeTitle ) ;
218225
219- // Search for the page — it should appear since it's in the current workspace
226+ // Search for the page. Use expect.toPass to retry the entire search
227+ // flow — Supabase read-replicas may lag after the title save.
220228 const searchInput = page . getByRole ( "combobox" , { name : / s e a r c h p a g e s / i } ) ;
221229 await expect ( searchInput ) . toBeVisible ( { timeout : 5_000 } ) ;
222- await searchInput . click ( ) ;
223- await searchInput . fill ( scopeWord ) ;
224230
225- const resultsList = page . locator ( "#search-results" ) ;
226- await expect ( resultsList ) . toBeVisible ( { timeout : 5_000 } ) ;
231+ await expect ( async ( ) => {
232+ await searchInput . click ( ) ;
233+ await searchInput . fill ( scopeWord ) ;
227234
228- // Verify the search API was called with a workspace_id parameter
229- // by checking that results appear (the API requires workspace_id)
235+ // Wait for debounce (300ms) + network response
236+ const resultsList = page . locator ( "#search-results" ) ;
237+ await expect ( resultsList ) . toBeVisible ( { timeout : 5_000 } ) ;
238+
239+ // Verify the search API was called with a workspace_id parameter
240+ // by checking that results appear (the API requires workspace_id)
241+ const resultOptions = resultsList . locator ( '[role="option"]' ) ;
242+ await expect ( resultOptions . first ( ) ) . toBeVisible ( { timeout : 5_000 } ) ;
243+ await expect ( resultOptions . first ( ) ) . toContainText ( "Scoped" ) ;
244+ } ) . toPass ( { timeout : 15_000 , intervals : [ 2_000 , 3_000 , 5_000 ] } ) ;
245+
246+ // Verify all results are scoped to the current workspace (outside toPass
247+ // since the search results are now confirmed visible above).
248+ const resultsList = page . locator ( "#search-results" ) ;
230249 const resultOptions = resultsList . locator ( '[role="option"]' ) ;
231- await expect ( resultOptions . first ( ) ) . toBeVisible ( { timeout : 5_000 } ) ;
232- await expect ( resultOptions . first ( ) ) . toContainText ( "Scoped" ) ;
233250
234251 // The search component resolves workspace_id from the URL's workspaceSlug
235252 // and passes it to /api/search?workspace_id=. If workspace scoping were
0 commit comments