Checked, not claimed.
Every count on this page is read from the repo when the site builds. Add or remove a test and this page changes with it.
- automated tests
- 247
- run against real Postgres
- 27
- end-to-end in a browser
- 14
- full-codebase audits
- 3
58 test files. A parameterized test counts once, however many cases it runs. The audits are listed in the changelog.
On every push
GitHub Actions runs all of this on every push and pull request.
- 01
Typecheck
tsc --noEmit over the whole project, strict mode.
- 02
Lint
ESLint with the Next.js and React hooks rules.
- 03
Unit and integration tests
Vitest, with the money paths running against a real Postgres service, not mocks.
- 04
End-to-end tests
Playwright against the running app, including a seeded demo sign-in.
- 05
Lighthouse budgets
A production build, scored on three key pages against the budgets on this page.
Performance budgets
Lighthouse CI on a production build. Breaking a hard budget fails the run, the rest raise a warning.
- Accessibility score at least 0.9fails the run
- SEO score at least 0.9fails the run
- Performance score at least 0.9warns
- Best practices score at least 0.9warns
- LCP under 2.5swarns
- Blocking time under 200mswarns
- JavaScript under 350 KB per pagewarns
- Layout shift under 0.1fails the run
Accessibility
What's built in today. It isn't a certification, so test your own pages as you add them.
- Text colours meet WCAG AA contrast (4.5:1) on every surface, in light and dark mode.
- A skip link, labelled navigation landmarks and a logical heading order on every page.
- Visible focus rings on buttons, inputs and code blocks, and keyboard-scrollable code.
- Form errors are tied to their fields, so screen readers announce what to fix.
- Looping animations stop when the system asks for reduced motion.
- Menus, dialogs and tabs are Radix primitives, so keyboard handling comes from a tested library.
Read what's actually checked
app/api/contact/route.test.ts7
- sends the message with replyTo set to the visitor
- rejects invalid and oversized submissions
- silently accepts honeypot submissions without sending
- returns 503 in production when email isn't configured
- only logs in development when email isn't configured
- returns 502 when the send fails
- rate limits repeated submissions from one IP
app/api/demo/session/route.test.ts5
- 404s while demo mode is off
- 429s once the per-IP limit is hit
- 503s without a demo password instead of trying to sign in
- signs in as the demo account and passes the session cookie through
- 503s when the demo account isn't seeded
app/api/health/route.test.ts2
- returns 200 when the database answers
- returns 503 without leaking the error when the database is down
app/api/notifications/route.test.ts4
- 401s without a session
- marks everything read when no ids are given
- only ever scopes the update to the caller's own user id
- 400s a malformed body
app/api/teams/[teamId]/billing/checkout/route.test.ts5 · Postgres
- blocks a second checkout when a live subscription already exists with the active provider
- allows checkout when the existing subscription belongs to a different (since-switched) provider
- allows checkout when the prior subscription with the same provider is canceled
- blocks a second concurrent checkout attempt for the same team before any webhook lands
- releases the lock so a retry can succeed after the provider call fails
app/api/teams/[teamId]/invites/route.test.ts3 · Postgres
- returns 201 and creates a pending invite
- survives two concurrent POSTs for the same team+email without a 500 or a duplicate row
- returns 402 once members plus pending invites fill the free plan's seats
app/api/teams/[teamId]/members/route.test.ts3
- won't let an admin demote the owner
- won't let an admin grant admin
- returns early without writing when the role is unchanged
app/api/teams/route.demo.test.ts3
- refuses the shared demo account
- refuses a superadmin impersonating someone
- still lets everyone else create a team
app/app/settings/api-keys/_components/api-keys-settings.test.tsx3
- renders the server-provided keys without fetching on mount
- hides key creation from plain members
- explains the empty state when there's no team
app/app/settings/profile/_components/profile-settings.test.tsx1
- renders the server-provided user straight away, no loading state
app/app/settings/team/_components/team-settings.test.tsx3
- renders the server-provided roster and invites without fetching
- hides pending invites from members who can't invite
- explains the empty state when there's no team
app/sitemap.test.ts3
- lists the homepage, every blog post, and every doc page
- builds clean absolute URLs with no duplicates
- points at the sitemap and keeps private areas out
components/app/page-skeleton.test.tsx1
- announces itself as a loading status
components/auth/form-error.test.tsx3
- leaves a valid field alone
- marks an invalid field and points it at the message
- treats null the same as no error
components/content/copy-code-button.test.tsx2
- copies the raw source and confirms it
- says so when the clipboard refuses
components/seo/json-ld.test.tsx1
- escapes < so a value can't close the script tag early
e2e/app.spec.ts1 · browser
- the demo user can sign in and reach a populated dashboard and team page
e2e/auth.spec.ts2 · browser
- sign-in page renders the password form
- signed-out visitor hitting /app is redirected to sign-in
e2e/content.spec.ts3 · browser
- a docs page renders its content and navigation
- a blog post renders from the blog index
- an unknown URL shows the branded 404 page
e2e/marketing.spec.ts2 · browser
- homepage renders the hero and links to pricing
- pricing page lists all three tiers
e2e/smoke.spec.ts6 · browser
- health check reports the app and database up
- llms.txt indexes the docs and each link serves markdown
- docs code blocks are highlighted and copyable
- the skip link is the first thing a keyboard user reaches
- submitting an empty sign-in form marks the fields invalid
- the quality page lists the real test suite
lib/active-team.test.ts5
- returns the team the cookie points at when the user is a member
- falls back to the first team when there's no cookie
- falls back to the first team when the cookie names a team the user isn't in
- falls back after the selected team is left or deleted
- returns null for a user with no teams
lib/ai/credits.test.ts6 · Postgres
- reserves by decrementing the balance immediately, before any usage event exists
- refuses to reserve past zero and leaves the balance untouched
- lets only one of two concurrent reservations succeed when the balance covers exactly one
- db-level CHECK rejects a direct write that would push balance negative
- records one usage event for a completed generation after a reservation
- refunds a reservation back onto the balance with no usage event left behind
lib/api-keys.test.ts4
- returns a prefixed key whose stored hash matches a later lookup hash
- never repeats a key
- reads a Bearer token or an x-api-key header
- rejects missing, non-Keel, or oversized keys before any lookup
lib/billing/entitlements.test.ts6
- gives a team with no subscription the free limits
- doesn't lock out a paying team whose plan id this build doesn't know
- allows up to the limit and no further
- never runs out on an unlimited plan
- + 2 parameterized tests
lib/billing/plans.test.ts9
- finds a known plan by id
- returns undefined for an unknown plan id
- finds a known credit pack by id
- returns undefined for an unknown pack id
- resolves plan and interval from a LemonSqueezy variant id
- resolves plan and interval from a Polar product id
- doesn't match another provider's ids, unknown ids, or a missing id
- resolves a Stripe inline price by amount + interval
- doesn't match a monthly amount billed yearly, or missing inputs
lib/billing/providers/lemonsqueezy.test.ts5
- keeps a cancelled (grace period) subscription live, cancelAtPeriodEnd carries the cancel
- maps expired to the terminal canceled state
- maps on_trial and passes through shared statuses
- trusts a team_id carrying the checkout's signature
- ignores an unsigned team_id, or one swapped for another team's
lib/billing/providers/polar.test.ts2
- rejects a delivery with a bad signature
- rejects a delivery with no webhook-id to de-dupe on
lib/billing/providers/stripe.test.ts3
- rejects a bad or missing signature
- normalizes a paid credits checkout.session.completed
- normalizes customer.subscription.deleted
lib/billing/status.test.ts8
- treats grace-period states as live and ended/never-started ones as not
- flags a second live subscription from the same provider
- allows updates to the same subscription
- allows resubscribing after the old one ended, or while the new one isn't live yet
- allows a new provider's subscription after a BILLING_PROVIDER switch, and a team with no row
- drops any non-live event about another subscription while the team is live
- lets through live events, updates to the same subscription, and teams with no row
- only drops terminal states once the team's own subscription has ended
lib/billing/sync.test.ts11 · Postgres
- grants credits on a fresh purchase
- no-ops a redelivery of the exact same event id (outer dedupe)
- doesn't double-grant when the same checkout is delivered under two different event ids (inner dedupe)
- only processes one of two concurrent deliveries of the same event id
- keeps the team attached across a renewal sync that carries no teamId
- notifies the team's owners once when a subscription starts, not on renewals
- marks a subscription canceled on subscription.deleted
- clears cancelAtPeriodEnd on subscription.deleted
- keeps live subscription A when an incomplete event for subscription B arrives (live A then incomplete B)
- drops a credit purchase for a team that no longer exists instead of throwing
- claws back refunded credits once, clamped at 0
lib/content/blog.test.ts3
- refuses slugs that could escape the blog directory
- returns null for a slug with no post
- loads a real post
lib/content/docs.test.ts3
- gives every page in the nav a real description
- returns the markdown body without frontmatter
- returns null for a page that doesn't exist
lib/content/highlight.test.ts5
- wraps tokens in themed spans
- escapes the source
- returns null for a language it doesn't load
- resolves common aliases
- highlights every language it lists
lib/content/legal.test.ts3
- compiles for the /license page
- never promises lifetime updates or reads as a draft
- covers every tier
lib/content/llms.test.ts3
- links every docs page to its markdown route
- serves a docs page as markdown with its title
- 404s anything outside the docs nav
lib/content/quality.test.ts4
- reads it() and test() names in any quote style, skipping describe
- counts each it.each block once
- finds this very file and counts its tests
- separates unit, e2e and database-backed specs
lib/content/rss.test.ts4
- escapes text and formats dates as RFC 822
- drops pubDate for an unparseable date instead of printing Invalid Date
- escapes quotes
- serves every post as an RSS item
lib/dal/api-keys.test.ts6
- 401s a request with no key without touching the db
- 401s an unknown or revoked key
- returns the key's team and stamps last_used_at
- 429s once the key's own limit is spent
- skips limiting when Upstash isn't configured
- adds a WWW-Authenticate challenge to 401s only
lib/dal/teams.test.ts3
- 401s without a session and 404s for a non-member
- gives a plain member 403 on billing:write and api_keys:write
- keeps an impersonating superadmin to read-only permissions, even on an owner's account
lib/db/invites-constraint.test.ts2 · Postgres
- lets exactly one of two concurrent pending inserts for the same team+email succeed
- still allows a re-invite once the prior invite is no longer pending
lib/db/seed-data.test.ts3
- spreads usage over the past week, all before now
- adds up with the starting balance to a round number
- uses unique flag keys
lib/demo.test.ts6
- matches the demo email only while demo mode is on
- never matches anyone else
- keeps read access and the AI chat
- blocks anything that changes the team, billing or keys
- + 2 parameterized tests
lib/env-report.test.ts6
- reports everything off for an empty env, with nothing partial
- flags a half-configured group with the keys still missing
- treats a blank value as unset
- checks the keys of whichever billing provider is selected
- follows the AI provider resolution rules
- lists missing keys next to anything not fully on
lib/env.test.ts3
- only needs DATABASE_URL outside production
- treats a blank value as unset
- requires a real auth secret and base URL in production
lib/memory-rate-limit.test.ts2
- allows up to max hits per window, per identifier
- resets once the window has passed
lib/notifications.test.ts8
- inserts one row per distinct recipient
- skips the insert entirely with nobody to notify
- never throws into the caller when the insert fails
- notifies the matching members, tagged with the team
- never throws into the caller when the lookup fails
- links an invite notification to its accept page
- uses the right article for each role
- points billing notifications at billing settings
lib/observability.test.ts5
- keeps the digest and strips the query string
- handles a thrown non-Error
- only logs when no webhook is configured
- posts the report to the webhook without request headers
- swallows a failing webhook
lib/permissions.test.ts5
- grants owners every permission, including billing:write
- denies admins billing:write and team:delete
- restricts members to read-only billing/api_keys and ai:use
- ranks owner > admin > member
- never lets a role outrank itself or a higher role
lib/rate-limit.test.ts4
- prefers Vercel's own forwarded header
- falls back to x-real-ip
- uses the last X-Forwarded-For hop, not the client-supplied first one
- returns 'unknown' when nothing usable is present
lib/safe-redirect.test.ts7
- keeps same-origin paths, including query and hash
- falls back when empty
- rejects /%09/evil.com once the query string is decoded
- rejects encoded newline and backslash variants once decoded
- keeps still-encoded input on-site, it stays a literal path segment
- normalizes dot segments without leaving the origin
- + 1 parameterized test
lib/seo.test.ts5
- adds https:// to a bare domain
- strips trailing slashes and whitespace
- keeps an explicit scheme, including http for local dev
- gives each page its own canonical, og:url and OG image
- supports absolute titles and extra Open Graph fields
lib/team-rules.test.ts11
- lets an owner keep admin and member invites
- lets an admin keep member invites but not admin ones
- drops every invite once the sender is a plain member
- reports a pending invite past its expiry as expired
- keeps a pending invite that hasn't expired
- leaves resolved invites alone
- names a single team
- names several teams
- accepts the invited address, case-insensitively, once verified
- rejects a different address
- rejects the right address while it's unverified
lib/two-factor.test.ts5
- accepts the code however it was pasted, without changing its case
- leaves something that isn't backup-code shaped for the server to reject
- only accepts exactly six digits
- sends the user back to sign in only when the two-factor window has expired
- falls back to a generic message for codes it doesn't know
lib/uploadthing-url.test.ts2
- accepts Uploadthing's per-app and legacy hosts
- rejects other hosts, lookalikes, and non-https
proxy.test.ts5
- blocks a cross-site mutation to Keel's own API
- allows same-origin mutations and requests with no Origin
- allows cross-origin GETs and exempt callers
- sends a signed-in user to a same-origin redirect
- + 1 parameterized test
scripts/env-file.test.ts7
- reads values, strips quotes and treats blank as unset
- doesn't match a key that only ends with the name
- replaces in place and keeps comments
- appends a key that isn't there
- is long enough for production and different every time
- treats the .env.example placeholder as unset
- names the host without the credentials
test/db-guard.test.ts5
- accepts local and docker-compose hosts
- rejects hosted databases and junk
- throws for a remote database unless explicitly allowed
- throws when no database is configured at all
- passes for a local database