Skip to content

test(api): cover PATCH /api/v1/preferences and the cookie overlay - #343

Merged
untraceablez merged 1 commit into
mainfrom
test/api-preferences-patch
Aug 17, 2026
Merged

test(api): cover PATCH /api/v1/preferences and the cookie overlay#343
untraceablez merged 1 commit into
mainfrom
test/api-preferences-patch

Conversation

@untraceablez

Copy link
Copy Markdown
Collaborator

Why

Found while checking coverage on #342: PATCH /api/v1/preferences had no test at all — its three lines were the only uncovered code in routes/api.py.

That matters more than the coverage number. It's the endpoint an external client writes preferences through, and the price_source / currency / hist_currency values it carries are what decide whether two apps agree on what a collection is worth. ADR 0002 just made those a cross-app contract rather than a display preference.

What's covered

On the endpoint:

  • Writes persist and are visible through the browser /prefs router — same singleton.
  • Partial application (exclude_unset) — fields not sent keep prior values.
  • Normalization of bad input: unknown currency and price source fall back to defaults, view collapses to grid, and page_size / card_size / foil_speed / spin_speed clamp to their ranges. Garbage never persists.
  • An explicit null doesn't wipe a stored value — it means "not set", which is easy to get wrong in a PATCH.
  • Unknown fields ignored.
  • The read-only guard (403, reads still fine).
  • The token gate — which is the documented reason /prefs exists as a separate browser-facing router. There was a test asserting GET /api/v1/preferences is gated; now PATCH is too.

Below the endpoint:

  • _clamp's non-numeric fallback, reachable from the service/CLI layer since the API's typed model rejects those first.
  • The cookie overlay in resolve — a device's own choices winning until a row is saved — including off-menu page sizes and junk values being ignored.

Result

preferences.py and routes/api.py are both back to 100%. Repo-wide uncovered drops from 16 lines to 5.

Tests only — no behavior change. ruff check src tests clean; full suite 1176 passed.

The remaining 5 are a different shape and left alone here: the except SQLAlchemyError fallback in the prefs middleware (main.py), and the prefs is not None branches in routes/card.py and routes/search.py. Those last two are worth a look on their own — they imply the test client never exercises the middleware-populated prefs path, so those routes are always tested via their raw-cookie fallback. That's a testing gap, not just a coverage gap.

🤖 Generated with Claude Code

`PATCH /api/v1/preferences` had no test at all — it was the only uncovered
code left in routes/api.py. That matters more than a coverage number: it is
the endpoint an external client writes preferences through, and the
price-source/currency values it carries decide whether two apps agree on
what a collection is worth.

Covers, on the endpoint: partial application (exclude_unset), normalization
of bad input (unknown currency/price-source fall back, view collapses to
grid, page_size/card_size/foil_speed/spin_speed clamp), an explicit null
not wiping a stored value, unknown fields ignored, the read-only guard, and
the token gate — which is the documented reason /prefs exists as a separate
browser-facing router.

Also covers `_clamp`'s non-numeric fallback (reachable from the service /
CLI layer, since the API's typed model rejects those first) and the cookie
overlay in `resolve`, including off-menu page sizes and junk values.

preferences.py and routes/api.py are both back to 100%; repo-wide uncovered
drops from 16 lines to 5.

Tests only — no behavior change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@untraceablez
untraceablez merged commit 1934794 into main Aug 17, 2026
9 checks passed
@untraceablez
untraceablez deleted the test/api-preferences-patch branch August 17, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant