You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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.
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
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.
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
👋 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:so this is backend-only: vitest + convex-test.
What's in here
vitest+convex-test+@edge-runtime/vm(dev deps),vitest.config.tswith theedge-runtimeenvironment per the official setup, scoped toconvex/**/*.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 afterensureUser(viat.withIdentity)ensureUser: idempotent upsert, syncs name on changelistUsers: throwsConvexErrorwhen unauthenticated AND when authenticated-but-not-provisioned (first-login window); returns users once provisionedpnpm testbetween lint and build.ConvexTestingHelperline replaced with the real setup; thetestingFunctions.ts/testingMutationcleanup note kept (that part was accurate).Surprises
convexTest(schema)without explicit modules fails under vitest 4 ((intermediate value).glob is not a functioninside convex-test's fallback discovery), soconvex/test.setup.tsprovides theimport.meta.globmodules map as the docs prescribe for non-default layouts../**/!(*.*.*)*.*suses an extglob that silently matches nothing on Vite 6+ (glob matching moved to tinyglobby, no extglob support) —test.setup.tsuses plain negative patterns instead, with a comment so nobody "fixes" it back.Verified
pnpm test— 5 tests passpnpm lint,pnpm build— pass (rebased on latest main incl. Format pass + pin eslint tsconfigRootDir #13 format pass)🤖 Generated with Claude Code
https://claude.ai/code/session_01VrVv49ZydmFUGUVbVTGWeN