Testing
What the suite covers, what a database test needs before it will run, and the gates a change has to pass. The contract suite and the browser run for the launchpad have their own page.
The suite
Vitest, configured in vitest.config.mts (note the extension), over 179 files under tests/. The default environment is node; a component or hook file opts into jsdom with a // @vitest-environment jsdom docblock on its first line. Vitest globals are off, so a file imports what it uses. Tests and their setup hooks both get 20 seconds, because in the database backed suites the setup is the expensive half.
tests/achievements: the badge service and the streak arithmetic behind it.tests/agent: the run loop, the file and data tools, the Anthropic client and its error mapping, the run registry, key verification, run summaries, and a full sign in to run path.tests/api: the Content Security Policy report route.tests/app: the sitemap.tests/assets: the media store, image sniffing and resizing, a project's asset library.tests/auth: JWT signing and verification, the cookie, SIWE against a real ethers wallet, the chain list,requireUser.tests/billing: the price table, the ledger operations and the account service.tests/checkpoints: capture, restore and pruning.tests/components: 46 files rendering the interface under jsdom.tests/contracts: the shared contracts, including that every error code has a sentence and every reserved username is refused.tests/data: the project database layer. SQL compilation, identifier quoting, migrations, isolation between two schemas, keys, CORS, limits, passwords, end user tokens, provisioning and the pool.tests/explore: the feed and remix.tests/forum: the service and its queries.tests/github: auth, the client, the import planner, import, push and the job handlers, against recorded fixtures.tests/helpers: not tests but the harnesses the tests use, plus one test of the per worker URI rule.tests/hooks: the React hooks, including the agent run hook and autosave.tests/jobs: the queue service and the worker: claims, leases, retries, cancellation.tests/launch: chain reads against fixtures, the candle builder, the trade store against a real MongoDB, holders, referrals and the launch service.tests/lib:api-client, the crypto round trip, the database connector, environment validation,http, the logger,next.config,proxyand its policy header, the rate limiter, instrumentation and the utilities.tests/messages: the transcript service, and a property test over the rebuild.tests/models: the schemas, their indexes and the migration script's rewrites.tests/profiles: the profile service.tests/projects: templates, naming and slugs, entry detection, the generated client module, the zip export and the service.tests/publish: the publish gate and the publish service.tests/routes: 16 files calling the route handlers with realNextRequests, one per area of the API.tests/scripts: the credits script and the Postgres bootstrap.tests/search: the search service.tests/sse: the server stream, and a fuzz test over the client parser.tests/storage: the provider seam, Lighthouse, and its wire format against a real HTTP server rather than a stubbedfetch.tests/usage: the spend ledger query the daily budget reads.
What a database test needs
The Mongo backed files connect to MONGODB_URI_TEST, which defaults to mongodb://localhost:27017/creora_test, and clear their collections in beforeEach. Because vitest runs files concurrently in worker processes, tests/setup.ts appends _<VITEST_POOL_ID> to the database name, so worker 1 gets creora_test_1 and cannot wipe worker 2's rows mid test. The URI must name a database or the harness throws rather than falling back to a shared one.
The project database files need PostgreSQL, and both of its roles carry a password, so there is no guessable default. They read DATABASE_URL_APP_TEST and DATABASE_URL_OWNER_TEST. The harness reads exactly those two names out of .env.local, and then .env, and never the file as a whole. Loading a whole file would put every variable in it into the workers, including a developer's real ANTHROPIC_API_KEY, which would mean the suite ran against a live billable key and the no_api_key paths could never be exercised. tests/lib/env.test.ts asserts from inside a worker that it is not there. For the same reason the config blanks ANTHROPIC_API_KEY, ANTHROPIC_WORKSPACE_ID, DATABASE_URL_APP and DATABASE_URL_OWNER, so no test can reach the cluster somebody develops against.
Without the two Postgres names the project database suites skip themselves and print the sentence saying why, so a skip is never mistaken for a pass. Their isolation is not per database like Mongo's: a Postgres role is cluster wide, so every test mints a fresh random project id and cleans up exactly the schemas and roles it created. npm run pg:bootstrap creates the two roles and the test database; it is idempotent.
The launchpad
The launchpad has a layer the rest of the app does not: a Foundry suite over the Solidity, run against a real Uniswap v4 PoolManager and PositionManager deployed fresh for every test, and a browser run driven by Playwright against a local anvil chain with a wallet injected into the page. That run signs in, launches a token with a picture, trades through the referral router, buys the curve out so it graduates, trades in the pool, claims the creator's reward and collects fees, checking every step against the app's own API. npm run contracts:test is the first, npm run launchpad:local then npm run e2e:launchpad the second. Both are described in the launchpad's testing page.
The gates
npm run check
Four gates in one command, in this order so a failure names the one that broke:
npm run lint:eslint . --max-warnings 0. A warning fails.npm run typecheck:tsc --noEmit, strict.npm run test:vitest run.npm run build:next build, which also proves that the environment validates, because rendering the pages importssrc/lib/env.ts.
CI
.github/workflows/ci.yml runs on every push to main, every pull request, and on demand. Three jobs.
- check, on Node 22 with a 30 minute cap. Two service containers:
mongo:7on 27017 andpostgres:17on 5432, both with health checks the job waits on. It runsnpm ci, thennpm run pg:bootstrapso the project database suites have their roles, thennpm run check. Its environment carries throwaway, non secret values forMONGODB_URI,JWT_SECRET,NEXT_PUBLIC_APP_URLandNEXT_PUBLIC_REOWN_PROJECT_ID, because the build step validates them, plus the twoDATABASE_URL_*_TESTstrings, which are the same ones the bootstrap script writes. - contracts, with the Foundry toolchain and no services. It installs the pinned Solidity dependencies with
scripts/contracts-deps.sh, runsforge build --sizes, which fails on any contract over the size limit, and thenforge test. - launchpad, the browser run, with a 40 minute cap and a
mongo:7service. It installs Node 22, Foundry, Playwright's Chromium and the Solidity dependencies, starts a local chain with Uniswap v4 and the launchpad on it, takes the printed addresses into the build environment, builds, starts the app on port 3001, waits for the launchpad endpoint to answer, and runsnpm run e2e:launchpad. Screenshots and the app log are uploaded whether it passed or not.