Unit tests:
- shares-service: create, idempotent create, revoke, get, batch fetch
- ip-rate-limit: under/over limit, IP independence, window reset
E2E tests:
- Create public share link via UI
- Public page renders without auth
- Revoke share returns 404
- Trashed note share returns 404
- Globe icon on shared card
- Copy link to clipboard
Also fix sharing-indicator test-id in existing sharing.spec.ts
and add shared_notes table to test-helpers and db/index.ts init.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Concurrent edits to shared notes (e.g., one user checks a shopping list
item while another adds an item) were lost because the sync system used
whole-document Last-Write-Wins. This replaces it with a 3-way line-level
content merge using node-diff3, so changes to different lines are
preserved from both users.
Key changes:
- Add node-diff3 for 3-way line-level content merging
- Remove the timestamp gate in processSyncPush that rejected entire
offline sync pushes when another user had updated the note
- Add content merge to both the sync push path and the PATCH endpoint,
using version snapshots as the merge base
- Send baseVersion from the client so the server can find the correct
common ancestor for 3-way merge
- Protect pending local fields during client pull merge by reading
the sync queue and preserving queued-but-unpushed changes
- Add comprehensive tests for content merge, server sync, and CRDT merge
https://claude.ai/code/session_01FNpVBBjM6vKzfR8y9NM9Ci
Playwright's setOffline(false) doesn't reliably emit the browser's
'online' DOM event in headless/CI environments. Manually dispatch it
as a safety net so the sync client always triggers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three sources of flakiness fixed:
1. **Preferences sync race** — page.goto() triggers a full reload which
re-runs initPreferences() + syncPreferencesFromServer(). On slow CI,
the async server sync can return stale data from parallel test workers
that share the same user's server-side preferences. Fixed with
gotoWithStablePrefs() which blocks the one GET /api/preferences sync
request, so initPreferences() falls back to localStorage (always correct).
2. **localStorage not reset** — resetPreferences() only reset the server.
After a full page reload, loadFromLocalStorage() could return stale
values from previous test runs. Now resets both server and localStorage.
3. **API key name collision** — parallel test runs created keys with the
same name ("Settings Test Key"), causing Playwright strict-mode
violations when multiple elements matched. Fixed with Date.now()
unique suffixes.
Verified: 167/167 settings tests pass (20x repeat), 173/173 full suite (5x).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add docs/TESTING.md with 10 BDD testing best practices
- Add createNote() helper to fixtures to DRY up state setup
- Add createChecklistNote() helper in checklist tests
- Rename scenario titles to describe outcomes, not actions
- Replace imperative Given steps with createNote() helper
- Fix fragile conditional in tag filtering test (silent pass)
- Remove implementation details from Gherkin comments
- Improve Given/When/Then rhythm consistency across all tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each preference test now resets to default preferences via API at the
start, ensuring parallel tests don't pollute each other's state.
Also await PUT response before reload in persist test to prevent
race condition.
Settings tests set defaultNoteMode to 'markdown' without resetting,
causing parallel sharing test to timeout when TiptapEditor wasn't
rendered (textarea shown instead). Two fixes:
- Reset preferences in settings tests after changing them
- Create note via API in sharing test (tests sharing, not note creation)
Move Profile page to /settings/profile and add a 302 redirect from
/settings to /settings/preferences so the first settings tab is
Preferences, not Profile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove duplicate bold formatting test from notes-crud.spec.ts
- Trim formatting.spec.ts from 9 to 5 tests (remove italic, inline code,
toolbar bold, toolbar visibility — same mechanism as bold shortcut)
- Remove hardcoded waitForTimeout(500) from search.spec.ts (Playwright
assertions already retry with built-in timeouts)
- Restructure sharing.spec.ts: 9 serial tests → 5 parallel self-contained
tests using collabPage fixture and API-based setup
- Add collabPage fixture to helpers/fixtures.ts for sharing tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add V8 coverage for unit tests via @vitest/coverage-v8 and Istanbul
instrumentation for E2E tests via vite-plugin-istanbul. Coverage data
is collected from browser pages after each Playwright test and merged
with nyc. CI uploads both coverage reports as GitHub Actions artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove tests for sort selector UI (removed). Replace with a single
test verifying most recently updated note appears first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getChangesSince was returning the owner's pinned/archived/sortOrder
for shared notes instead of the collaborator's per-user values from
noteUserState. Also filtered trashed notes from collaborator sync.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Serial test suite covering: owner shares note, collaborator sees it,
collaborator edits content, independent pin state, leave action shown
for non-owners, collaborator leaves and note disappears.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add missing userId arg to syncNoteTags() calls in notes-service
- Add seedUser option to createTestDb() for test setup
- Add explicit type annotations to MCP server.tool() callbacks (zod v4)
- Fix ambiguous getByText selector in settings e2e test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use .first() for pin-btn and tag filter assertions to handle cases
where multiple matching elements exist in the DOM.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update unit test helpers with full multi-user schema, fix auth tests to
include email field, and improve e2e tests with specific card targeting
and force clicks for hover-revealed buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix session expiry check (seconds vs milliseconds mismatch in raw SQL),
conditionally render app chrome only for authenticated users, use full
page reload after login/setup for proper session propagation, remove
HTML minlength to allow JS validation, fix store to remove notes on
trash/archive, and make auth tests race-condition safe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update e2e fixtures to use email+password for setup and login.
Update auth tests to fill email field. Add multi-user test for
admin creating a new user via API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Images are hidden from card thumbnails by default. Users explicitly
feature images via a star toggle in the upload panel, and only featured
images appear in the card header strip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking a thumbnail in the editor, closed-panel view, or note card
opens a full-screen overlay with the full-size image. Closes on Escape,
background click, or X button. Escape is scoped so it won't close the
editor underneath.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of disabling the image button for unsaved notes, clicking it
now auto-saves the note first (with title "Untitled" if empty), then
opens the upload panel. This removes friction from the upload flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use static test-image.png fixture instead of dynamic beforeAll creation
- Add thumbnail_path column to auto-create SQL in db/index.ts
- Hover on thumbnail before clicking remove button (group-hover:block CSS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers: upload → thumbnail in editor, persistence across close/reopen,
thumbnail on NoteCard, image removal, disabled toggle for unsaved notes.
Uses programmatically generated 1x1 PNG for test uploads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests were clicking the done toggle expecting to expand it, but since
fed0fc1 changed doneExpanded to true by default, the click was
collapsing it instead — causing visibility assertions to fail.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Completed items now consistently appear below unchecked items in both
the editor and the note card preview. Replaces the flaky two-state
hide/show toggle with a simple expand/collapse for the done section.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add sort mode selector (Updated/Created/Custom) with localStorage persistence
- Sort notes client-side via derived stores based on selected mode
- Enable drag-to-reorder in Custom mode via svelte-dnd-action on NoteGrid
- Add POST /api/notes/reorder endpoint for bulk sortOrder updates
- E2E tests for sorting by updated/created and persistence across reload
Closes#12
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add drag-to-reorder via svelte-dnd-action with grip handles
- Add "hide completed" toggle with collapsible done section
- Each checklist item gets a unique ID for stable drag operations
- E2E test for hide/show completed items
Closes#11
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add noteCard() helper to target specific cards by title instead of
generic getByTestId('note-card') which fails with multiple matches
- Scope action button clicks (trash, pin, archive) within their card
- Scope tag-chip filter clicks to the tag-filter container
- Wait for networkidle after auth to ensure full hydration
- Remove "empty notes list" test incompatible with shared DB
- Use toHaveCount(0) instead of not.toBeVisible for search empty state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Load notes from IndexedDB first for instant display, then sync from
server in background. All mutations now persist to IDB when online,
keeping the cache always current. Eliminates empty state flash on load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract toast store to standalone module so notes store can show toasts
- Add try/catch to all note mutations with optimistic updates + IDB queue on network error
- Wire up startSync/stopSync in layout to enable online/offline event listeners
- Reload notes from server after successful sync push to prevent data loss
- Connect SyncIndicator to real sync status with Lucide cloud icons
- Add 300ms minimum display time for status transitions
- Add e2e tests for offline create, edit, trash, and sync-on-reconnect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the default dark/white theme with a warm parchment aesthetic
using CSS custom properties, retro pixel overlay, and JetBrains Mono
monospace font across all components. Bump version to 0.1.7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all user-facing "note(s)" with "crumb(s)" — sidebar, search
placeholder, editor placeholders, empty states. Use Lucide icons
(StickyNote, Archive, Trash2, Tag) in sidebar for consistency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ThemeToggle component, theme store, dark: Tailwind variants,
and dark color values from NOTE_COLORS. Simplify color logic to use
a single bg property. Delete dark mode e2e tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace plain text toolbar labels with Lucide SVG icons. Group heading,
list, and alignment options into dropdown menus to reduce toolbar width.
Replace window.prompt link insertion with an inline popover (input, apply,
open, remove). Add underline and text-align TipTap extensions. Remove
task list from TipTap editor (broken styling). Fix task list bullet
rendering in note card preview. Increase editor min-height for markdown
mode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TipTap WYSIWYG editor (headless @tiptap/core) with StarterKit,
TaskList, TaskItem, Link, Placeholder, and tiptap-markdown extensions
- Always-visible formatting toolbar with undo/redo, H1-H3, bold, italic,
strikethrough, inline code, code block, blockquote, bullet/ordered/task
lists, horizontal rule, and link
- Raw markdown toggle for power users
- Render rich text (HTML) on note cards instead of stripped plain text
- Update all e2e tests for TipTap contenteditable editor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use a unique title "Grocery Errands" instead of "Shopping List" which
collided with the checklist test suite in the shared test database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>