Skip to content

Commit 5f1228d

Browse files
fix: wrap search E2E tests with toPass retry for read-replica lag (#199)
Co-authored-by: Ona <no-reply@ona.com>
1 parent b6a8f60 commit 5f1228d

1 file changed

Lines changed: 36 additions & 19 deletions

File tree

e2e/search.spec.ts

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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: /search pages/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: /search pages/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

Comments
 (0)