Also replaces a vacuous expect(true).toBe(true) with a real behavioral
assertion that both block texts remain rendered after rerender.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
waitForSource() helper polls for the EventSource constructor effect
to register the mock; assertion blocks use vi.waitFor on the progress
bar / heading / button changes after each SSE event dispatch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 15 setTimeout sleeps with vi.waitFor on the actual signal
(fetch URL recorded, banner appears, status text rendered) and
switches the default fetch mock from mockResolvedValue to
mockImplementation so each call yields a fresh Response — no more
"body stream already read" unhandled rejections.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 16 setTimeout(350ms / 30ms / 50ms) sleeps with vi.waitFor on
the actual signal — popup listbox appearance/disappearance, option
aria-selected state — so the test no longer races the 200ms internal
debounce against the real clock under CI load.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the vacuous expect(true).toBe(true) sleep test with a real
flyout-open assertion (role=dialog appears after trigger click) and
turns the Escape-keydown smoke test into a full open→Escape→closed
behavioral test. Routes the Escape event through document (matches
the svelte:document binding) instead of window.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 2 setTimeout-based wait() helpers with vi.useFakeTimers() +
vi.advanceTimersByTimeAsync() so the polling-loop tests no longer
race against the real clock under CI load — they instead deterministically
advance the setInterval by the exact poll interval and let microtasks
flush. Also converts the destroy() .not.toThrow smoke into a direct
expect(job.destroy()).toBeUndefined() check.
Per Sara: polling-loop tests are the legitimate case for fake timers
(time progression matters) — exactly the pattern she requested.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 3 setTimeout sleeps with vi.waitFor on document.activeElement
during keyboard nav, and converts 2 .not.toThrow smoke tests on the
prev/next buttons into no-op assertions: with a single file in the
strip the active chip stays selected and onSelect is not invoked.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 3 setTimeout sleeps with vi.waitFor on listbox / aria-expanded
state and converts 2 .not.toThrow smoke tests + 1 vacuous expect(true)
into assertions about the input remaining usable after fetch errors
and Escape on a closed dropdown being a no-op.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 8 setTimeout sleeps with vi.waitFor on the actual signal
(textarea value, fetch URL recorded, onCountChange call) and converts
3 .not.toThrow smoke tests into behavioural assertions:
- "no onCountChange wired" → asserts initial comment text still renders
- "network error during reload" → asserts empty-hint state is shown
- "non-OK reload" → asserts empty-hint state is shown
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 5 setTimeout sleeps with vi.waitFor on the actual class
transition, and converts 6 .not.toThrow smoke tests into assertions
that the validation guard surfaces the expected error message (or
absence thereof). Tightens the dragging-state regex to bg-accent-bg
so it cannot match the idle hover:border-primary substring.
Runtime: faster + deterministic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 6 setTimeout sleeps with vi.waitFor and expect.element
auto-wait, and converts 9 .not.toThrow smoke tests into assertions
on the rendered PDF nav controls (Zurück/Weiter/Vergrößern/Verkleinern)
and the conditional outdated-annotation notice / annotation visibility
toggle. transcribeMode test now mocks the annotations fetch so the
toggle button is actually rendered (annotationCount > 0 guard).
Runtime: 33s → 4.5s.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 3 setTimeout sleeps with click + auto-wait / vi.waitFor on
the bulk-edit-all flow, and converts 14 .not.toThrow smoke tests into
behavioral assertions:
- Advanced-filter labels (Schlagworte/Absender/Empfänger/Von/Bis) for
every hasAdvancedFilters() branch (senderId, from, to, tags)
- Collapsed advanced section when all filters are at falsy defaults
- Search input value reflected via two-way binding
- BulkSelectionBar surfaces count when store has entries
- bulk-edit-all populates selection store on success
Runtime: 48s → 3.8s. Addresses Sara's blockers on PR #505.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces 13 setTimeout sleeps with vi.waitFor and expect.element
auto-wait, and converts 17 .not.toThrow smoke tests into behavioral
assertions that verify what each scenario actually exposes:
- topbar mount + svelte:head title for prop pass-through cases
- Edit anchor surfaced when canWrite=true
- Details drawer open + sender displayName visible for sender data
- panel-close testid for transcribe-mode entry
- OCR progress heading 'OCR läuft' for RUNNING + jobId
- OCR spinner absent for 500 / DONE / PENDING-without-jobId / network-error
Runtime: 34s → 3.5s, no sleeps. Addresses Sara's "118 setTimeout" and
"74 .not.toThrow" blockers on PR #505.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fixes Sara's .spec.ts outlier concern on PR #505 — every other new
test file in the coverage push uses .svelte.test.ts.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The test:coverage step runs the full suite under Istanbul; running
`npm test` first executes every test twice for no extra signal.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pulls the transcription-block state (load, save, delete, reviewToggle,
markAllReviewed, createFromDraw, toggleTrainingLabel, deleteAnnotation
+ derived blockNumbers / hasBlocks / lastEditedAt / annotationReloadKey)
out of documents/[id]/+page.svelte into a reusable factory in
lib/document/transcription/useTranscriptionBlocks.svelte.ts.
The page now reads transcription.blocks / .blockNumbers / .hasBlocks /
.lastEditedAt / .annotationReloadKey reactively and delegates writes
to transcription.{load, save, delete, reviewToggle, markAllReviewed,
createFromDraw, toggleTrainingLabel, deleteAnnotation,
findByAnnotationId, bumpAnnotationReloadKey}. The confirm-then-delete
dialog stays in the page; the hook only handles the data ops.
24 unit tests cover initial state, load (success / non-OK / network /
empty-id), derived state (blockNumbers in sortOrder, lastEditedAt
recent-pick, lastEditedAt-null fallback), delete (success bumps key /
non-OK throws), reviewToggle (success updates / non-OK no-op), markAll
(success / non-OK), createFromDraw (success / non-OK / network all
return correct shape), toggleTrainingLabel (200 / 500), deleteAnnotation
(linked-block path / orphan-annotation path / orphan-fail throw),
findByAnnotationId match + miss, bumpAnnotationReloadKey.
Also bumps the polling-loop test waits in useOcrJob.svelte.test.ts to
150-200ms (from 60-80ms) so the suite is reliable when run in parallel.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pulls the trigger/poll/check-status state out of documents/[id]/+page.svelte
into a pure factory in lib/ocr/useOcrJob.svelte.ts that takes documentId,
fetchImpl, and onJobFinished callback as injected dependencies.
The page now delegates to ocrJob.triggerOcr / ocrJob.checkStatus /
ocrJob.destroy and reads ocrJob.running / .progressMessage / .errorMessage /
.skippedPages reactively.
Test discipline reset: 22 unit tests cover initial state, triggerOcr 200/
4xx-with-code/4xx-without-code/5xx/network-error paths, useExistingAnnotations
flag round-trip, checkStatus PENDING/RUNNING/DONE/no-jobId/empty-id/5xx/network
paths, polling progressMessage / skippedPages updates, DONE/FAILED → onJobFinished
callback, polling-error swallow, and destroy mid-poll cleanup.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
renderCurrentPage early-returns when canvasEl/textLayerEl null,
init() idempotent on second call, zoomIn after floor, goToPage(1)
no-op.
5 new tests covering ~6 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Whitespace-only quotedText not seeded, no onCountChange not provided,
fetch network error during reload, non-OK reload response, own
comment with edit/delete affordances.
5 new tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
authorName email fallback when no first/last names, undefined-author
empty result, publishedAt missing, body empty no-excerpt, single
person filter render-without-throw.
5 new tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
use:enhance vs callback form variant rendering, self-relation
error, submit disabled on missing related person, submit disabled
on yearError.
5 new tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ArrowUp wrap-around, Escape close, Enter without selection no-op,
keydown without dropdown no-throw, Enter with active selection
selects, excludeIds filter works, parentId fallback as subtitle.
7 new tests covering ~12 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds selected-node primary fill, birth/death year combinations,
node click and Enter/Space/other-key handling, dashed/solid spouse
line, single-parent connector, focus ring on focus + blur, aria
labels and aria-expanded reflection, accent stripe on selected node.
13 new tests covering ~30 branches in the node-render path.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Status color paths (exhausted/expired/revoked), new-invite form
toggle, loadError banner.
5 new tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Color dot hidden at depth>0 and when color is null, document count
badge omitted at 0, toggle click mutates collapseMap.
4 new tests covering ~6 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds single-word name (one-initial) and leading-space edge cases
for the initials function.
2 new tests covering ~4 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds banner-hidden defaults (success/error), empty groups list,
groups field undefined fallback to [].
4 new tests covering ~6 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds unsaved-warning hidden by default, oninput dirty marker, form
error banner hidden when form is undefined.
3 new tests covering ~6 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds two tests that pass all filter props as truthy and as falsy
defaults, covering the seed-from-data-or-default branches.
2 new tests covering ~14 branches (all data.X || '' chains).
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds receiver-focus triggers correspondents fetch, advanced-filter
chevron rotation in both states.
3 new tests covering ~6 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds fake-timer tests for morning (h<12), day (12<=h<18), and
evening (h>=18) branches plus the empty-firstName fallback.
4 new tests covering the greeting time-of-day branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sender/receivers populated, filePath set, full user object,
Escape vs other keys keydown handler, deep-link comment query.
6 new tests targeting ~14 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds backfill-versions and backfill-file-hashes click handlers,
verifies initial fetch hits import-status and thumbnail-status.
3 new tests targeting ~10 branches in the page component.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty state when url is empty (no controls, placeholder shown),
loaded state with controls, annotationsDimmed branch, transcribeMode
flag, documentFileHash filtering branch.
6 tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-correspondents derived from received-document senders, self-skip
branch when sender == current person, GeschichtenCard rendered when
geschichten array is non-empty, 5-entry cap on co-correspondents.
4 new tests covering ~10 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two persontypeaheads + two date inputs, swap button visible/invisible
based on both persons set, sort label DESC vs ASC, chevron rotation,
onapplyFilters / ontoggleSort / onswapPersons callbacks fire.
11 tests covering ~20 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds direct-relationship sorting, yearRange formatting (both years,
only fromYear), inferred-relationships disclosure rendering, 5-item
cap on derived relationships.
5 new tests targeting ~15 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds password show/hide toggle (independent for both fields), pwHint
visible after typing, pwValid green hint for 8+ chars, pwMismatch
red hint, pwMatch green hint, form.error rendering, notifyOnMention
checkbox toggle.
7 new tests targeting ~25 branches in the register flow.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Textarea props (placeholder, rows, disabled), popup not shown
initially, popup opens on @ + query, empty results from API,
HTTP error → empty popup, Enter submits when popup closed,
Shift+Enter does not submit, Escape closes popup, Arrow{Up,Down}
navigation, Enter with no results.
12 tests covering ~30 branches in MentionEditor.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds drag-over and drag-leave styling, drop with no files, multiple
invalid files, mixed valid+invalid files, non-Enter keydown ignore,
window-level dragenter/dragleave with and without 'Files' types,
counter underflow guard.
16 tests, +9 covered branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds keyboard navigation (Arrow{Up,Down,Left,Right}, shiftKey step,
non-arrow no-op, edge clamping at all four sides), pointer drag
flows (move-area + each of the 8 handles), early-return branches
for non-primary pointers and pointer events without active drag.
28 tests, +20 covered branches over previous 7-test version.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three variants (first-run, filter-empty, inbox-zero), title vs body
visibility, data-variant attribute, accent vs ink-3 icon coloring.
5 tests, ~15 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Radiogroup with label, all five filter pills, aria-checked for active
filter, tabindex matrix (0 active vs -1 inactive), onChange callback
when clicked.
5 tests, ~15 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty state (default + term-specific), error banner, year groups
default sort, sender-group sort, undated/unknown-sender labels, total
count display. Mocks $app/navigation since the empty-state CTA calls
goto.
8 tests covering ~30 of DocumentList's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty placeholder, all four status pill branches (QUEUED/DONE/FAILED/
RUNNING), error-detail disclosure on FAILED, Personalisiert vs Basis
type label, COLLAPSED_COUNT visible runs, person columns visibility
toggle, em-dash CER fallback.
11 tests covering ~25 of TrainingHistory's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty list early return, heading + per-doc row rendering, title link
href, date visibility tied to updatedAt, stats footnote presence
toggled by stats.totalDocuments.
7 tests covering ~16 of the dashboard section's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty list early return, populated section, write-action link gated on
canWrite, visible-cap of 3, footer show-all link visibility based on
overflow, author name vs email fallback.
9 tests covering ~25 of GeschichtenCard's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hidden when totalPages <= 1, prev/next disabled state matrix at
boundaries, link form when in range, aria-current for active page,
mobile page label, left ellipsis / right ellipsis branches based on
window position, custom ariaLabel.
11 tests covering ~30 of Pagination's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Avatar with initials vs question-mark fallback, for-you marker
visibility, data-variant matrix (simple/for-you/rollup/comment),
count badge for rollup, comment preview rendering with fallback,
document title link, default vs comment-deep-link href, time-range
label for rollup with happenedAtUntil.
11 tests covering ~40 of ChronikRow's high-uncovered branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Title rendering with originalFilename fallback, sender vs unknown
placeholder, tag buttons per document tag, bulk-select checkbox gated
on canWrite, archive chips visibility, snippet/summary visibility,
em-dash for missing date.
11 tests covering ~30 of the row's branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Toggle button, form open on click, all relationship type options,
year-error alert when toYear < fromYear, no-error path when equal,
cancel button closes form, onSubmit prop wiring.
7 tests covering ~20 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prev/next nav buttons, chip count per file, aria-current matrix for
active id, error-state data attribute, onSelect callback, onRemove
callback, sr-only announcer for active title.
7 tests covering ~25 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop hint + accepted types render, default no-progress state, invalid
MIME-type rejection, valid PDF acceptance, no-files early return,
click + Enter open the file input, multi-file accept whitelist
attributes.
8 tests covering ~25 of DropZone's 46 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Heading with tag name, name input hydration, color picker visible only
for top-level tags, color swatch grid (10 entries), aria-pressed for
active color, success banner branch, error banner branch, merge-success
banner branch.
8 tests covering ~30 branches in the tag-edit page.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mounts the page, renders the orchestrator, exposes the hidden skip-form,
and renders the three submit-action buttons (skip, save, save+review).
4 tests covering the orchestration entry path of enrich/[id].
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Renders the document edit page with mocked confirm service. Verifies
DocumentEditLayout mounts, both hidden submit-target forms (review and
delete) exist, and the delete button is present in the action bar.
3 tests covering the orchestration entry path of documents/[id]/edit.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mounts the aktivitaeten page with mocks for the notification SSE
singleton (init/destroy/markRead/markAllRead) and $app/state. Verifies
heading renders, error state renders main element, empty state renders
main, and a non-default filter renders without crashing.
4 tests covering the orchestration entry path.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mounts the page with mocked $app/state, $app/navigation, and confirm
service. Verifies the top bar renders, the viewer container exists, and
the last-visited localStorage write happens onMount.
3 tests covering the orchestration entry path of the 558-line
documents/[id]/+page.svelte.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
admin/ocr index: heading, sender-models heading, global-history link,
defensive defaults for missing trainingInfo fields.
admin/ocr/[personId]: person name from personNames lookup, Unknown
fallback when not found, back-link href, missing-personNames defensive
handling.
8 tests across two pages.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three admin/index pages (groups/tags/users) — each renders a single
"Wähle X aus der Liste" prompt for the desktop split-view layout.
AuthHeader: brand link href + wordmark.
PersonsEmptyState: empty heading + explanation text.
6 tests across five small files.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Listbox label, empty-state placeholder, create-new escape hatch with
noopener target, populated list, default aria-selected on first item,
life-date range visibility, position fallback when clientRect is null,
positioning from clientRect.
8 tests covering ~25 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tag link href, document-count visibility branch, color-dot at depth 0
vs deeper, aria-current matrix, children list rendering, collapse-map
hides children, expand/collapse toggle for nodes with children.
9 tests covering ~30 branches in the recursive tree-node component.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backfill cards rendered, both backfill buttons enabled by default,
no success banner before any action. Smoke-level coverage of the
admin maintenance page.
5 tests covering basic render branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Year divider rendering, distinct-year branch, no-duplicate consecutive
years, no-divider for documents without documentDate, canWrite-gated
new-document link with senderId-only and senderId+receiverId href
variants.
7 tests covering ~20 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All-sections render when full permissions, users/invites hidden when
!canManageUsers, groups hidden when !canManagePermissions, tags hidden
when !canManageTags, system/ocr hidden when !canRunMaintenance,
flyout closed by default.
6 tests covering ~30 branches in the permission matrix.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hero state when no senderId set, results card when senderId set,
SinglePersonHintBar gating on senderId × !receiverId, empty-results
message branch.
5 tests covering ~15 branches in the orchestrator.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
One bar per filled bucket, singular vs plural aria-label, aria-pressed
matrix, drag-window visibility tied to isDragging, onbarclick callback,
minimum-height handling for zero-count buckets.
8 tests covering ~25 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dialog with bell label, empty state vs populated list, mark-all-read
visibility branch, REPLY vs MENTION text, unread-dot rendering, all
three callback wirings (onMarkRead, onMarkAllRead, onClose).
10 tests covering the notification dropdown surface.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
register page (350 lines): hero render when no codeError, NO_INVITE_CODE
vs other-codeError card branches, form hidden when codeError set,
back-to-login link, form section rendering, prefill hydration of
firstName/lastName/email, prefill-hint visibility branch, hidden
code input with code-null fallback.
admin/users/new: heading, three card sections, group checkboxes
rendered, form-error banner branch, cancel link, submit button.
17 tests across two pages.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Brand link, four primary nav links, admin link gated on isAdmin,
hamburger menu open/close state via aria-expanded. Mocks $app/state
so the page URL drives the active-route highlighting.
6 tests, ~30 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Title, all four section headings, secure Wikipedia link rel
attributes, five rule cards rendered, four klaerung chips rendered.
7 tests covering the static help page.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Heading with email, three card sections (profile/groups/password),
success vs error form banners, group preselection from editUser.groups,
cancel link, delete button. Mocks the confirm service.
7 tests, ~25 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TimelineControls: empty render when neither flag is set, reset button
gated on isZoomed, clear button gated on hasSelection, both-on, both
callback wirings.
TimelineXAxis: empty filled → no ticks, populated → ticks render,
omit-year branch when all buckets share a year, show-year branch
across multiple years, length-4 bucket-string fallback.
11 tests across two timeline primitives.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UserPasswordSection: input rendering, type=password attribute,
required-prop propagation in both directions.
CorrespondenzFilterControls: dual date label rendering, both DateInput
ids, value hydration from fromDate/toDate, change-event smoke check.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four tests: discard link href, save button label, form attribute
wiring, formaction. Small focused component.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
enrich/done: heading, body, both CTA links.
documents/bulk-edit: empty-store onMount redirect to /documents,
loading spinner during in-flight fetch, error banner on backend error
code, error banner on fetch rejection. Mocks fetch via vi.spyOn so the
async branches are exercised without a real backend.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BackButton: visible vs aria-only label branches, custom class
application, history.back() click handler.
OverflowPillButton: +N pill render, aria-expanded matrix
(closed default → open after click), per-person link rendering with
correct href, Escape closes the dropdown.
Both are reused widely; their coverage closes the line and function gap
left after the DocumentTopBar split inflated the denominator.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sixteen tests covering the four-column drawer: details column always
renders, persons column branches (no-persons placeholder vs sender
vs receivers), receiver overflow + show-all toggle, tags column
branches (placeholder vs anchor list with /?tag href encoding),
geschichten column visibility (hidden by default, shown for
canBlogWrite, attach link gated on canBlogWrite + documentId, list
rendering, show-all overflow), inferred-relationship pill on the
single-receiver branch.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
admin/groups/new: heading, both permission group renderings (4 standard
+ 4 administrative checkboxes), form-error banner branch, cancel link
href, submit button form-attribute wiring, name input requiredness.
Mocks $app/navigation so beforeNavigate doesn't crash the test runner.
enrich/+: heading, empty placeholder vs populated count + start CTA,
start CTA href derived from documents[0].id, per-row title rendering,
bulk-select checkbox gated on canWrite.
16 tests across two files.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
users/[id]: full-name derivation across all four branches
(both/firstName-only/lastName-only/email fallback), avatar initials
matrix, email/contact row visibility tied to data presence.
admin/ocr/global: heading + back link, runs prop pass-through,
defensive default for missing history fields.
geschichten/[id]: title rendering, author full-name vs email fallback
vs null, publishedAt suffix conditional, persons and documents sections
gated on array length, edit/delete actions gated on canBlogWrite. Mocks
the confirm service since it requires a ConfirmDialog mounted in layout.
26 tests across three files.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PersonEditForm: PERSON vs INSTITUTION/GROUP visibility matrix (firstName,
title, alias, birth/deathYear toggle), lastName label switch, prop
hydration of all populated fields, fallback to PERSON for unknown type,
empty-string handling for null fields. 10 tests, ~30 branches.
SegmentationTrainingCard: trainingInfo null vs populated, block count
display, button disabled-state matrix (training × tooFewBlocks ×
serviceDown), too-few-blocks and service-down hints, success message
after a mocked fetch, training history heading. 10 tests, ~25 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Third Phase 5 split. The desktop action buttons — transcribe,
transcribe-stop, edit link, download link — become their own component
with a focused props interface (documentId, canWrite, isPdf,
transcribeMode bindable, filePath, originalFilename, fileUrl).
TDD: 8 tests covering empty render, transcribe button gating
(canWrite × isPdf × transcribeMode), stop-transcribe rendering, edit
link with documentId href, download link with filePath gating, all
hidden when in transcribe mode. After the test was red the component
was created.
DocumentTopBar dropped from 303 lines to 166. The orchestrator now
just composes BackButton, DocumentTopBarTitle, PersonChipRow,
OverflowPillButton, the details toggle, DocumentTopBarActions,
DocumentMobileMenu, and DocumentMetadataDrawer — each visual region
named in one or two words.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Second step of the Phase 5 split. The kebab dropdown — including
clickOutside handling and its own mobileMenuOpen state — becomes its
own component named after its visual region. The mobile snippet
duplication inside DocumentTopBar is removed; the component owns its
mobile-specific markup.
TDD: DocumentMobileMenu.svelte.test.ts (7 tests) was red first. The
component then made it green (kebab trigger, dropdown open/close on
click, transcribe button gated on canWrite × isPdf × !transcribeMode,
download link gated on filePath). DocumentTopBar wraps the new
component in a md:hidden div so responsive behaviour is unchanged.
Existing 18-test DocumentTopBar suite still passes.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
First step of the Phase 5 split plan from issue #496. The 14-line title
+ date block becomes its own component named after the visual region.
TDD red/green: DocumentTopBarTitle.svelte.test.ts written first
(7 tests covering title, originalFilename fallback, empty-string
fallback, short-date rendering, no-date branch, title attribute
sourcing). After the test was red the component was created.
DocumentTopBar.svelte updated to use it; the existing 18-test suite
still passes.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eighteen tests covering the user-observable matrix without yet splitting
the component (Phase 5 of the plan): title vs originalFilename fallback,
short-date rendering and absence, transcribe-button gating
(canWrite × isPdf × transcribeMode), edit-link gating, download-link
gating on filePath, kebab-menu visibility on (canWrite & isPdf) || filePath,
details drawer toggle, mobile menu open/close.
The 83 raw branches in the source map mostly to combinations of the
above flags — each test isolates one branch. Per Sara's guidance the
test names read as sentences and verify what the user sees, not internal
state.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each status (active / exhausted / revoked / expired) maps to a distinct
visual treatment via statusColor() — one focused test per branch
asserts the correct background class on a tbody element so the test
verifies user-observable behaviour rather than the internal switch.
Also covers: empty placeholder, loadError banner, filter chip
selection state, new-invite form toggle on button click, createError
message visibility inside the open form, created-invite success card
with shareable URL, revoke button gating to active invites only,
unlimited-uses display, no-expiry display.
16 tests, ~50 branches covered.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
empty state vs. populated, zoom controls visibility tied to node count,
URL ?focus= preselection (matching id selects, missing id does not),
zoom-out clamping safety. $app/state mocked at module boundary so the
test can drive page.url and page.data.canWrite without a SvelteKit
runtime.
Six tests focused on user-observable behaviour — one logical behaviour
per test (Sara's guidance).
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DocumentViewer: loading / error / no-scan / image rendering branches.
filePath conditionally drives the direct-download link in the error
state; fileUrl + non-PDF contentType drives the <img> render.
PersonalInfoForm: default render, prop hydration including the German
date conversion path, success/error banner branches, form action wiring.
profile/+page: notification-checkbox enabled/disabled depending on
hasEmail, no-email hint visibility, prefsSuccess/prefsError banners,
fallback when notificationPrefs is null.
20 tests across three files.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PersonDocumentList: empty/populated, year-range derivation across
no-date/single-year/multi-year inputs, sort toggle visibility (>1 doc),
sort-direction round trip, preview-limit + show-more expansion,
title→originalFilename fallback, no-date and no-location branches.
persons/new: PERSON vs INSTITUTION/GROUP visibility matrix
(firstName/alias/life-year fields toggle), lastName label switching
between Vorname/Nachname/Name, form-error banner, prior-form hydration,
cancel link href, fallback to PERSON for unknown personType.
24 tests across two files, hitting the 32+28 = 60 branches at the top
of the issue's leverage list.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CorrespondentSuggestionsDropdown: empty list still renders the static
heading and 'Alle Korrespondenten' row, populated rows when not loading,
loading hides correspondent rows, initials fallback (lastName-only when
firstName is null), click + keyboard selection, Escape closes.
PersonCard: full matrix of conditional UI — title visibility for PERSON
vs non-PERSON, avatar initials path (firstName+lastName vs lastName-only
fallback), PersonTypeBadge presence for non-PERSON types, alias, life
dates, notes, and the canWrite=true/false branches that gate the edit
link (Nora's authorization-rendering rule).
21 tests covering ~50 branches.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PersonTypeBadge: one test per switch arm (INSTITUTION, GROUP, UNKNOWN)
plus the two no-render branches (unrecognised type, empty type).
ExpandableText: clamp detection, toggle visibility logic, expand →
collapse round-trip, default maxLines fallback.
PersonChipRow: sender-only, sender+arrow, abbreviated naming, max-two
visible receivers, +N overflow pill presence/absence, receivers-only
case (no sender → no arrow).
19 tests across three files. Each file uses afterEach(cleanup) and
queries via getByRole/getByText so tests stay decoupled from CSS.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
+error.svelte: vi.mock('$app/state') drives the page state so each test
can assert one of the three rendering branches — populated error message,
distinct status code, and the 'Internal Error' fallback when page.error
is null.
forgot-password/+page.svelte: prop-driven tests for the four states —
default form, success banner, error message inside the form, and the
back-to-login link href.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PasswordChangeForm: tests the null/success/error/mismatch banner branches
plus the form action wiring.
FileSectionNew: tests the no-file/file-selected toggle, onfileParsed
callback invocation with the parsed metadata, the early-return when no
file is in the change event, and the suggestedTitle fallback path.
Eleven tests across two files. Both follow the UploadZone template (props,
File API synthetic input, vi.fn() callback spies).
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers the abbreviated/full name branches, the firstName-null fallback
path, link href derivation from person id, initials rendering, and the
deterministic avatar palette colour. Six tests, six branches hit.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds DocumentStatusChip.svelte.test.ts asserting one branch per
DocumentStatus value (PLACEHOLDER, UPLOADED, TRANSCRIBED, REVIEWED,
ARCHIVED) plus the title/aria-label exposure. Each test queries the
element via getByTitle so the component's accessibility surface is
verified at the same time as its branch logic.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UploadZone is the canonical browser-test template referenced from issue #496
implementation guidance. Adding afterEach(cleanup) makes it match the
TranscriptionPanelHeader pattern and prevents cross-test DOM leakage as more
tests are added in this branch.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per Felix's review on issue #496, tests should query observable behaviour via
ARIA roles, not test-only data-testid attributes. Replaces every
'document.querySelector([data-testid=...])' with 'page.getByRole(...)'.
The disabled-button click test uses force: true so Playwright bypasses its
enabled-check — the behaviour under test is precisely that the click is
ignored.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes scaffolding pages from initial Paraglide setup that were never
navigated to in production. Shrinks the measured coverage surface and
removes dead code from the production bundle. CLAUDE.md route tables
updated to drop the demo/ entry.
Refs #496.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>