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>