Skip to content

Backend testing setup: vitest + convex-test - #17

Merged
hibukki merged 4 commits into
mainfrom
testing-setup
Jul 24, 2026
Merged

hibukki merged 4 commits into
mainfrom
testing-setup

Conversation

@hibukki

@hibukki hibukki commented Jul 24, 2026

Copy link
Copy Markdown
Owner

👋 Claude here

The template shipped zero test infrastructure, yet CLAUDE.md told agents to use ConvexTestingHelper — instructions pointing at nothing. This PR adds a real, minimal backend testing setup. Scope note:

I don't want UI/playwright tests

so this is backend-only: vitest + convex-test.

What's in here

  • vitest + convex-test + @edge-runtime/vm (dev deps), vitest.config.ts with the edge-runtime environment per the official setup, scoped to convex/**/*.test.ts. Scripts: pnpm test (run once), pnpm test:watch.
  • convex/users.test.ts — the copyable example, covering the auth/provisioning semantics from Auth semantics: backend crashes on unauthorized, frontend gates via AuthenticatedAndProvisioned #11:
    • getCurrentUser: null unauthenticated, the row after ensureUser (via t.withIdentity)
    • ensureUser: idempotent upsert, syncs name on change
    • listUsers: throws ConvexError when unauthenticated AND when authenticated-but-not-provisioned (first-login window); returns users once provisioned
  • CI: pnpm test between lint and build.
  • CLAUDE.md: the stale ConvexTestingHelper line replaced with the real setup; the testingFunctions.ts/testingMutation cleanup note kept (that part was accurate).

Surprises

  1. convexTest(schema) without explicit modules fails under vitest 4 ((intermediate value).glob is not a function inside convex-test's fallback discovery), so convex/test.setup.ts provides the import.meta.glob modules map as the docs prescribe for non-default layouts.
  2. The docs' glob pattern ./**/!(*.*.*)*.*s uses an extglob that silently matches nothing on Vite 6+ (glob matching moved to tinyglobby, no extglob support) — test.setup.ts uses plain negative patterns instead, with a comment so nobody "fixes" it back.

Verified

🤖 Generated with Claude Code

https://claude.ai/code/session_01VrVv49ZydmFUGUVbVTGWeN

@hibukki
hibukki merged commit 30abacf into main Jul 24, 2026
2 checks passed
@claude

claude Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review: Backend testing setup (vitest + convex-test)

Overview
Adds the backend testing infrastructure that CLAUDE.md referenced but the template never shipped: vitest + convex-test (edge-runtime environment), a convex/users.test.ts example suite covering the auth/provisioning flow, a pnpm test step wired into CI (between lint and build), and doc fixes replacing the stale ConvexTestingHelper mention. Scope is intentionally backend-only, matching the stated "no UI/playwright tests" constraint.

Code quality and conventions

  • Matches CLAUDE.md documented order (lint, test, build) both in CI and in the "Before pushing" checklist.
  • convex/test.setup.ts explains why it exists (convex-test automatic module discovery breaks under vitest 4) and why it avoids the docs extglob pattern (tinyglobby silently matches nothing on Vite 6+), with an inline comment warning against reverting it back. Good adherence to the "document non-obvious implementation choices" guideline in CLAUDE.md - this is exactly the kind of workaround that would otherwise get silently "fixed" back into a broken state by a future contributor or agent.
  • Test names are descriptive and each test maps to a real behavioral contract (getCurrentUser null vs populated, ensureUser idempotency plus name-sync-on-change, listUsers throwing for both unauthenticated and authenticated-but-unprovisioned callers). The unauthenticated-vs-unprovisioned distinction is a subtle race window (getCurrentUserOrNull in convex/users.ts) that is easy to miss, so it is good that it is explicitly exercised.
  • Consistent use of ConvexError assertions, matching the project rule to throw ConvexError for user-facing errors.
  • eslint.config.js and tsconfig.node.json updates for vitest.config.ts mirror the existing treatment of vite.config.ts, keeping the pattern consistent.

Minor suggestions (non-blocking)

  • convex/testingFunctions.ts (deleteTestUser) has no test coverage. Probably fine to skip since it is a thin cleanup helper, but worth a one-line mention in the PR description if intentional.
  • The literal "clerk|sarah" identity subject is repeated across four tests. A small local helper (e.g. a withIdentity(name) function) would remove the duplication, but at this scale it is a readability call, not a real issue.
  • The test.setup.ts glob only picks up top-level _generated/*.js files - fine today since generated output is flat, but if Convex ever nests generated files (e.g. per-component subfolders) this pattern would need to become a ** glob. Not worth pre-emptively generalizing now, just something to watch if convexTest module discovery errors resurface later.

Risks / correctness

  • No functional risk: all changes are additive (new dev deps, new test/config files, one CI line, doc text). Nothing in convex/users.ts or other production code paths is touched.
  • The two documented gotchas (vitest 4 module discovery, extglob silently matching nothing) are exactly the kind of failure mode that is hard to debug from a red CI run alone - capturing them in comments plus the PR description is valuable for future maintainers.

Security and performance

  • No security concerns - all additions are dev dependencies and test-only code; no secrets, no production code paths affected.
  • Performance impact is limited to CI time (one more pnpm test step); the edge-runtime environment is the correct choice for approximating the Convex runtime per the official docs.

Test coverage

  • Coverage of the touched surface (convex/users.ts) is thorough for a "copyable example": it covers the null path, the happy path, upsert idempotency, name-change sync, and both failure modes of listUsers. This is a solid template to copy for future backend tests in the repo.

Overall: a clean, well-scoped PR that fixes a real gap (docs pointing at nonexistent test tooling) with sensible defaults and good in-code documentation of the two non-obvious workarounds. Nothing blocking.

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