Prufy notes
The app ยท 6 min

How it's tested

864 tests, arranged so the logic that matters most is the easiest to test exhaustively.

864 testsBy package
core
dns
db
web
PackageTestsCovers
core520Normalization, all 56 transitions, every failure reason, copy rules, which changes send an alert
dns119Recorded real responses, zone walking, fixtures, URL signing
db87Constraints, indexes, queries, sessions, rate limits, real concurrency
web138Whole flows through the API, sessions, alerts, setup links, docs matching code

The layers

Each layer needs more than the one below it. Most tests sit at the bottom, because that's where the decisions are.

Live smokebun run dns:probe, run by handThe real internet
Whole APICreate, fail, fix, verify through handlersPostgres and fixtures
Real databaseConstraints and racesPostgres
Fixture DNSEach failure reason end to endA JSON world
Recorded dataParsing saved real responsesJSON files
Compile timeAn illegal transition doesn't compileThe type checker
Pure logicclassify given hand-built observationsNothing at all

How a test earns trust

  • Independent expectations. The state machine test uses a table copied out by hand. If it imported the code's own table, a wrong table would pass.
  • Recorded data. The DoH parser is tested against real saved responses, which is how the Google and Cloudflare difference got caught.
  • Proving a test can fail. Removing SKIP LOCKED makes its test fail. A test that can't fail proves nothing.
  • Failing loudly. If Postgres is down, tests fail with instructions. A skipped test looks exactly like a passing one.
  • Drift tests. One test fails if the state machine doc stops matching the code, or CI and Docker use different Postgres images.

Testing things that send, without sending

apps/web/lib/server/alerts-and-shares.test.ts builds the API with a container whose mailer pushes each message onto an array, and whose push can be told to answer sent, gone or failed. So a test can verify a domain and then read back exactly one email and one push, or make the mailer fail and check the domain still verified. Sessions are made the same way the app makes them: a real token, with its hash stored by createAccountWithSession.

Predict it first
A test wants an owner and a rival account. Where do they come from now that seeded accounts are gone?

What isn't covered

GapWhy
Automated live-DNS testsThey depend on the outside world, so joycabinet.com was verified by hand instead.
A found record on VercelVerified on live DNS from a laptop. On Vercel, a claim has only reached not found so far.
Applying at a real providerNo provider has the template.
UI component testsNone. The pages were checked by hand in a browser.
The shaderNo automated tests. It's validated with vgpu check and looked at as PNGs from render-globe.mjs.
The service workerNone. public/sw.js is plain JavaScript outside the test setup.
Real email and push deliveryThe tests use recorders. Nothing has been received from Resend or a push service yet.
The rename migrationNo automated test. The journal says it was run against a database holding an old row.