forked from mirror/crumbs-original
fix: preserve search results when background sync runs
Keep canonical notes separate from active search results so periodic reloads no longer replace the filtered view. Cancel superseded requests and ignore stale responses to prevent older queries from overwriting newer results. Reconcile results with canonical notes so updates propagate and removed or trashed notes disappear. Add unit and end-to-end coverage for reconciliation, background sync, and out-of-order search responses. Co-authored-by: Google Gemini <gemini@google.com>
This commit is contained in:
committed by
Fred Cabassut
co-authored by
Google Gemini
parent
32c39b0000
commit
b802f17504
@@ -31,4 +31,56 @@ test.describe('Search', () => {
|
||||
// Then no notes are displayed
|
||||
await expect(page.getByTestId('note-card')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('Scenario: Background sync preserves active search results', async ({ authenticatedPage: page }) => {
|
||||
await createNote(page, 'Sync Search Target 3812925');
|
||||
await createNote(page, 'Sync Search Other 3812925');
|
||||
|
||||
await page.getByTestId('search-input').fill('Sync Search Target 3812925');
|
||||
await expect(page.getByText('Sync Search Target 3812925')).toBeVisible();
|
||||
await expect(page.getByText('Sync Search Other 3812925')).not.toBeVisible();
|
||||
|
||||
const notesReloaded = page.waitForResponse(
|
||||
(response) => response.url().includes('/api/notes?filter=all') && response.ok()
|
||||
);
|
||||
await page.getByTestId('sync-indicator').click();
|
||||
await notesReloaded;
|
||||
|
||||
await expect(page.getByText('Sync Search Target 3812925')).toBeVisible();
|
||||
await expect(page.getByText('Sync Search Other 3812925')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('Scenario: A stale response cannot replace newer search results', async ({ authenticatedPage: page }) => {
|
||||
await createNote(page, 'Race Slow 3812925');
|
||||
await createNote(page, 'Race Fast 3812925');
|
||||
|
||||
const slowResponse = await page.request.get('/api/search?q=Race%20Slow%203812925');
|
||||
const fastResponse = await page.request.get('/api/search?q=Race%20Fast%203812925');
|
||||
const slowResults = await slowResponse.json();
|
||||
const fastResults = await fastResponse.json();
|
||||
|
||||
await page.route('**/api/search?*', async (route) => {
|
||||
const requestQuery = new URL(route.request().url()).searchParams.get('q');
|
||||
if (requestQuery === 'Race Slow 3812925') {
|
||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||
await route.fulfill({ json: slowResults });
|
||||
return;
|
||||
}
|
||||
await route.fulfill({ json: fastResults });
|
||||
});
|
||||
|
||||
const searchInput = page.getByTestId('search-input');
|
||||
const slowRequestStarted = page.waitForRequest(
|
||||
(request) => new URL(request.url()).searchParams.get('q') === 'Race Slow 3812925'
|
||||
);
|
||||
await searchInput.fill('Race Slow 3812925');
|
||||
await slowRequestStarted;
|
||||
await searchInput.fill('Race Fast 3812925');
|
||||
|
||||
await expect(page.getByText('Race Fast 3812925')).toBeVisible();
|
||||
await expect(page.getByText('Race Slow 3812925')).not.toBeVisible();
|
||||
await page.waitForTimeout(300);
|
||||
await expect(page.getByText('Race Fast 3812925')).toBeVisible();
|
||||
await expect(page.getByText('Race Slow 3812925')).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user