diff --git a/src/lib/stores/notes.test.ts b/src/lib/stores/notes.test.ts index 637fe0f..22d9e92 100644 --- a/src/lib/stores/notes.test.ts +++ b/src/lib/stores/notes.test.ts @@ -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' }), diff --git a/src/lib/stores/notes.ts b/src/lib/stores/notes.ts index e45b008..31617b3 100644 --- a/src/lib/stores/notes.ts +++ b/src/lib/stores/notes.ts @@ -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(); 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; } diff --git a/tests/e2e/checklist.spec.ts b/tests/e2e/checklist.spec.ts index a402d5e..0127218 100644 --- a/tests/e2e/checklist.spec.ts +++ b/tests/e2e/checklist.spec.ts @@ -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');