# hyprcrd GUI Test Coverage Self-contained in-app test suite. No external dependencies. ## Activation - **URL**: append `?test=1` - **Keyboard**: `Ctrl+Shift+Alt+T` - **Safety**: automatic backup before run, auto-restore after - **Visibility**: panel hides during tests so you can watch interactions, shows results after - **Sync paused**: background sync and autoSync disabled during tests ## Test Files (39 files, ~280 tests) | File | Focus | |---|---| | `shell.test.js` | Header, footer, toolbar, file inputs | | `settings.test.js` | All 7 tabs, open/close, account, behavior, CalDAV, relay, notifications | | `board.test.js` | Card rendering, split preview, card lifecycle | | `toolbar.test.js` | Filter toggles (done/termine/tagged), superview, sort modes | | `buckets.test.js` | Bucket bar rendering, filtering, create/delete | | `bucket-context.test.js` | Bucket right-click menu, rename, color, delete options, move-left disabled | | `context-menu.test.js` | Card right-click, actions, submenus, close | | `card-interactions.test.js` | Tags, due dates, done badges, overdue, favorites, color, bucket, grouping | | `filtering.test.js` | Tag AND logic, hierarchical match, unsorted bucket, hide filters | | `sorting.test.js` | All 5 sort modes, effectiveDate priority | | `state-functions.test.js` | parseTags, getChildren, getGroupCards, recent, favorites, toggleFavorite | | `favorites.test.js` | Favorites bucket filtering, todo progress bar, detail split pane | | `search.test.js` | Open (Ctrl+K, button), input focus, typing, ESC | | `search-logic.test.js` | Tag+text combo search, empty search recent, keyboard nav | | `calendar.test.js` | Open, month title, navigation, today, close | | `calendar-popup.test.js` | Day click, January/December year wrapping | | `rrule.test.js` | RRULE persistence (yearly, weekly+BYDAY, COUNT, UNTIL) | | `datepicker.test.js` | Rendering, 42-cell grid, today/selected highlight, Monday start, navigation, year wrap, click, double-click submit | | `gallery.test.js` | Open, image count, select-none, close | | `help.test.js` | F1 toggle, button, content sections | | `multiselect.test.js` | Ctrl+click select/deselect, multiple, click-outside clear | | `detail.test.js` | Structure, controls, open, title, ESC, close | | `detail-interactions.test.js` | Done toggle, edit from detail, zen mode, backlinks | | `editor.test.js` | Structure, open/close, card create | | `editor-features.test.js` | Color picker, preview, line numbers, save flow, edit existing | | `editor-save.test.js` | Empty title prevention, Ctrl+S, Tab title→body, update existing | | `editor-toolbar.test.js` | Bold, italic, todo, heading, hr buttons, auto-continue list on Enter | | `snippets.test.js` | All snippets (?dat, ?time, ?now, ?week, ?todo, ?hr, ?h1, ?table, ?code), inline calculator | | `image-fullscreen.test.js` | Overlay structure, bindDetailImageFullscreen export | | `markdown.test.js` | Basic rendering, wiki links (resolve, broken, case-insensitive), gallery block, todos, stripMd | | `markdown-edge.test.js` | Images/headings/lists/code/hr/todos/links after blank lines, multi-paragraph spacing | | `undo.test.js` | Color, title, body, due_date revert, delete+recreate, parent_id, bucket, multiple undos, empty stack | | `api.test.js` | Cards CRUD, buckets CRUD, auth & misc endpoints | | `api-edge.test.js` | XSS in title, empty body, null due_date, nonexistent card, empty bucket name, CSRF, positions | | `export.test.js` | JSON ZIP, vault ZIP, round-trip integrity (card count, caldav_uid, tags, due_dates) | | `relay.test.js` | Push/poll API (unconfigured state) | | `notifications.test.js` | Banner element, localStorage, settings selects | | `theme.test.js` | CSS vars, localStorage, applyTheme, themes object | ## Coverage Summary ### Data Layer - [x] parseTags (comma-split, empty, hierarchical) - [x] getChildren / getGroupCards - [x] getRecent / markRecent (add, front, dedup, cap at 10) - [x] getFavorites / toggleFavorite / isFavorite - [x] sortedCards all 5 modes (manual, newest, oldest, alpha, tag) - [x] effectiveDate priority (due_date > title date > created_at) ### Board & Cards - [x] Card rendering (data-id, draggable, color bar) - [x] Split preview (open/close, empty state, card preview, active highlight) - [x] Card create appears, delete disappears, delete clears preview - [x] Todo progress bar segments - [x] Overdue danger border - [x] Done badge - [x] Due date pill ### Toolbar - [x] All filter toggles with active class (done, termine, tagged) - [x] Superview toggle with active class - [x] Sort mode cycling - [x] Superview renders list items ### Buckets - [x] Bucket bar renders tabs, all special buckets (all, current, journal, favorites, unsorted) - [x] Bucket click filters cards - [x] New bucket appears, deleted disappears - [x] Bucket context menu (rename, color, move-left disabled on first) - [x] Empty bucket: single delete option - [x] Bucket with cards: both delete options - [x] Favorites bucket shows only favorited cards ### Filtering - [x] Single tag filter - [x] Multiple tags AND logic - [x] Hierarchical tag parent match - [x] Unsorted bucket excludes dated titles - [x] hideTermine excludes caldav cards - [x] hideTagged excludes tagged cards - [x] hideDone excludes #done cards ### Context Menu - [x] Opens on right-click, closes on click - [x] All actions (open, edit, duplicate, due-date, save-md, push-relay, favorite, color, bucket, tags, delete) - [x] Color submenu presets - [x] Tag submenu with input - [x] Favorite toggle - [x] Color change via menu - [x] Bucket assignment via menu - [x] Viewport-aware positioning (opens upward when near bottom) ### Search - [x] Opens with Ctrl+K and button - [x] Input focused on open - [x] Typing triggers results - [x] Tag-only filter (#tag) - [x] Tag + text combined - [x] Empty search shows recent - [x] Keyboard navigation - [x] ESC closes ### Calendar - [x] Open/close - [x] Month title, navigation (prev, next, today) - [x] January→December year wrap - [x] December→January year wrap - [x] Day click ### Datepicker - [x] Correct month for default value - [x] 42 day cells (6-week grid) - [x] Today highlight, selected highlight - [x] Monday start - [x] Month navigation, Dec→Jan year wrap - [x] Click day selects, double-click submits ### RRULE - [x] FREQ=YEARLY persistence - [x] FREQ=WEEKLY;BYDAY=MO persistence - [x] COUNT persistence - [x] UNTIL persistence ### Gallery - [x] Open/close, image count, select-none ### Help - [x] F1 toggle, button open, content sections ### Multi-Select - [x] Bar hidden by default, all action buttons - [x] Ctrl+click select/deselect - [x] Multiple cards, click-outside clear ### Detail View - [x] Structure, controls, open via click, title, ESC, close - [x] Done toggle saves #done tag - [x] Edit opens editor with card data - [x] Zen mode button exists - [x] Backlinks section exists - [x] Split pane button exists ### Editor - [x] Structure, save buttons, due date, done toggle - [x] Opens (add button, board right-click), closes (cancel, ESC) - [x] Title focused on open - [x] Color presets render and change color - [x] Preview pane and toggle - [x] Line numbers gutter and toggle - [x] Full save flow (title + body → save-close → card exists) - [x] Edit existing loads data, update persists - [x] Empty/whitespace title blocks save - [x] Ctrl+S saves card - [x] Tab moves title → body - [x] Toolbar: bold, italic, todo, heading, hr buttons - [x] Auto-continue bullet list on Enter - [x] Auto-continue todo list on Enter - [x] Empty bullet cleared on Enter ### Snippets & Calculator - [x] All snippets: ?dat, ?time, ?now, ?week, ?todo, ?hr, ?h1, ?table, ?code - [x] Inline calculator: ?3+5→8, 34+56?→34+56=90, multiplication, division ### Markdown - [x] Paragraphs, bold, italic, headings, code blocks - [x] External links with target=_blank - [x] Wiki links: resolve, broken, case-insensitive - [x] Gallery fenced block, empty gallery - [x] formatTodoItems, checked items - [x] stripMd - [x] Images/headings/lists/code/hr/todos/wiki-links after blank lines - [x] Multiple blank lines spacing, images between blank lines ### Undo - [x] Color change revert - [x] Title, body, due_date revert from editor - [x] Delete → recreate with body, color - [x] Delete preserves parent_id - [x] Bucket assignment revert - [x] Multiple sequential undos (stack order) - [x] Empty stack no-op ### API - [x] Cards: GET, GET/meta, POST, PATCH (returns card), DELETE (returns {ok}) - [x] Tag extraction, due_date persistence, bucket assignment - [x] Buckets: GET, POST, PATCH (returns bucket), DELETE - [x] Auth status, relay settings, caldav settings, 404 - [x] XSS in title, empty body, null due_date, nonexistent card - [x] Empty bucket name error, CSRF required, GET no CSRF - [x] Position create and update ### Export/Import - [x] JSON ZIP endpoint (status, content-type, ZIP magic) - [x] Vault export endpoint - [x] Round-trip: card count preserved - [x] Round-trip: caldav_uid preserved - [x] Round-trip: tags and due_dates preserved - [x] parent_id correctly remapped on import ### Relay - [x] Push without config → error - [x] Push without card_id → 400 - [x] Poll without config → 0 pulled ### Notifications - [x] Banner element, settings in localStorage - [x] Lookahead and time selects ### Theme - [x] CSS custom properties (8 vars) - [x] localStorage persistence - [x] applyTheme function, themes object - [x] Card layout CSS vars ## Not Yet Covered - Drag and drop (card reorder, bucket reorder, search-to-board) - Box-select rubber band visual - CalDAV sync flow (requires server) - Relay push/poll with configured relay (requires relay) - File upload (paste, drag into editor) - Image fullscreen zoom/pan interaction - Zen mode resize handles drag - Notification banner dismiss click - Calendar hover card popups - Calendar appointment/journal creation via double-click - Editor divider drag resize - Editor image resize handles - Superview hover popup system - Detail sidebar card navigation - Detail image gallery prev/next navigation ## Bugs Found & Fixed by Tests 1. **Import lost all CalDAV fields** — caldav_uid, tags, due_date, parent_id, relay_uid not preserved on import → CalDAV sync created duplicates 2. **Import lost parent_id mapping** — grouped cards lost their group after export→import (IDs changed) 3. **Undo delete lost parent_id** — undo after deleting a grouped card didn't restore group membership 4. **Undo editor lost due_date** — undo after editing didn't restore previous due_date 5. **_reloadAll didn't reload buckets** — new/deleted buckets not reflected without manual page reload 6. **Blank lines broke images in markdown** — `
\n` before `![img]()` prevented rendering 7. **Context menu clipped at viewport bottom** — fixed position calculation, now opens upward ## Adding Tests 1. Create `yourfeature.test.js` in `public/js/test/` 2. Import runner: `import { describe, it, expect, ... } from './runner.js'` 3. Add import to `tests.js` 4. Update this file Tests don't need manual cleanup — backup is auto-restored after every run. Use `csrf()` for API calls. Use `closeAll()` in `afterEach` for UI state. Sync is paused during test runs (`window._testRunning`).