mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-12 20:06:57 +02:00
fix: preserve local-only notes during loadNotes merge
mergeNotesByVersion only iterated incoming notes, dropping any local-only notes (e.g. just created but not yet in the server/IDB response). This caused note cards to disappear briefly after creation when loadNotes raced with createNote. Also rename E2E test note title to avoid name collision with existing "Groceries" test. https://claude.ai/code/session_01TdPpATUkmdY7DhBkmqrvWs
This commit is contained in:
@@ -67,6 +67,17 @@ describe('mergeNotesByVersion', () => {
|
||||
expect(result[0].id).toBe('n2');
|
||||
});
|
||||
|
||||
it('preserves local-only notes not present in the incoming data', () => {
|
||||
const localOnly = makeNote({ id: 'n1', version: 1, content: 'just created' });
|
||||
const serverNote = makeNote({ id: 'n2', version: 1, content: 'from server' });
|
||||
|
||||
const result = mergeNotesByVersion([localOnly], [serverNote]);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result.find((n) => n.id === 'n1')?.content).toBe('just created');
|
||||
expect(result.find((n) => n.id === 'n2')?.content).toBe('from server');
|
||||
});
|
||||
|
||||
it('preserves multiple notes correctly during a race condition', () => {
|
||||
const localNotes = [
|
||||
makeNote({ id: 'n1', version: 5, content: '- [x] Just saved' }),
|
||||
|
||||
@@ -60,11 +60,19 @@ function isNetworkError(err: unknown): boolean {
|
||||
*/
|
||||
export function mergeNotesByVersion(current: Note[], incoming: Note[]): Note[] {
|
||||
const currentMap = new Map(current.map((n) => [n.id, n]));
|
||||
const incomingIds = new Set<string>();
|
||||
const merged = incoming.map((incomingNote) => {
|
||||
incomingIds.add(incomingNote.id);
|
||||
const local = currentMap.get(incomingNote.id);
|
||||
if (local && local.version > incomingNote.version) return local;
|
||||
return incomingNote;
|
||||
});
|
||||
// Preserve local-only notes (e.g. just created, not yet in server/IDB response)
|
||||
for (const local of current) {
|
||||
if (!incomingIds.has(local.id)) {
|
||||
merged.push(local);
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +62,10 @@ test.describe('Checklist', () => {
|
||||
|
||||
test('Scenario: Multiple checked items persist after closing and reopening', async ({ authenticatedPage: page }) => {
|
||||
// Given a checklist note with three items exists
|
||||
await createChecklistNote(page, 'Groceries', ['Milk', 'Eggs', 'Bread']);
|
||||
await createChecklistNote(page, 'Weekly Shop', ['Milk', 'Eggs', 'Bread']);
|
||||
|
||||
// When the user reopens and checks two items
|
||||
await noteCard(page, 'Groceries').click();
|
||||
await noteCard(page, 'Weekly Shop').click();
|
||||
await page.getByTestId('checklist-checkbox').nth(0).click(); // Milk → done
|
||||
await page.getByTestId('checklist-checkbox').nth(0).click(); // Eggs (now first) → done
|
||||
|
||||
@@ -74,7 +74,7 @@ test.describe('Checklist', () => {
|
||||
await page.getByTestId('close-editor-btn').click();
|
||||
|
||||
// And the checked state persists after reopening
|
||||
await noteCard(page, 'Groceries').click();
|
||||
await noteCard(page, 'Weekly Shop').click();
|
||||
await expect(page.getByTestId('checklist-toggle-done')).toContainText('2 done');
|
||||
await expect(page.getByTestId('checklist-input')).toHaveCount(1); // Only Bread remains active
|
||||
await expect(page.getByTestId('checklist-input').first()).toHaveValue('Bread');
|
||||
|
||||
Reference in New Issue
Block a user