Testing
CI runs everything on every pull request, from a clean checkout: lint, type check, generated files, unit and integration tests, a production build, the end-to-end tests, and the Docker image with its smoke test. It runs the tests twice, side by side: once on MongoDB and once on PostgreSQL, where it also checks that the migrations match the config. A green run also proves that a fresh install works on both.
The commands #
| Command | What it runs | Needs |
|---|---|---|
pnpm lint | ESLint | — |
pnpm typecheck | TypeScript, without emitting | — |
pnpm test:unit | Vitest: the unit tests (src/**/*.test.ts, tests/unit) | — |
pnpm test:int | Vitest: the integration tests (tests/int) | The database in .env |
pnpm test:e2e | Playwright (tests/e2e), against a server it starts | Its own database |
pnpm test | All three, one after another | All of the above |
pnpm generate:types, pnpm generate:importmap | Not tests, but CI fails when the committed files differ from what they generate | — |
CI runs the unit and the integration tests on both databases.
Integration tests #
tests/int starts Payload against DATABASE_URL from .env, the same database as pnpm dev. The tests create their own content with random names and remove it afterwards, so a development database survives them. They run one file at a time, because two files writing the same global at once could undo each other.
If tests time out in their setup on a busy machine, wait a minute and run them again before you look for a bug.
End-to-end tests #
Playwright gives the tests a database of their own: E2E_DATABASE_URL, or mongodb://127.0.0.1:27017/tolk-e2e by default. The tests seed and clean up their own content there.
pnpm exec playwright install chromium # once
pnpm test:e2e
Stop
pnpm devfirst. Playwright starts its own server on port 3000, on the e2e database, and never uses one that is already running: with the port taken, it stops before the first test. (Apnpm devthere would read your development database while the tests seed the e2e one.)A fresh database is a new name:
E2E_DATABASE_URL=mongodb://127.0.0.1:27017/tolk-e2e-2 pnpm test:e2e. MongoDB creates it on the first write. Or drop the old one.On PostgreSQL, point
E2E_DATABASE_URLat apostgres://database that only the end-to-end tests use. Against a production build (CI=true), the server runs the migrations as it starts and the tests never push the schema; don't reuse a database the integration tests pushed to (see Migrations).As CI runs them, against a production build:
pnpm build CI=true pnpm test:e2eMaps draw markers only (
MAP_TILES=off), so the tests never wait for a tile server.AI translation is tested without a key, as CI runs: the AI tests check that the controls are gone. The integration tests cover the AI features with the model mocked.
A public demo (
DEMO_MODE) has a spec of its own,tests/e2e/demoMode.e2e.spec.ts, which the normal run skips. Run it alone against a server in demo mode (see Live demo).
Tests follow the module switches #
A test about one module skips while the module is off (describe.skipIf(!moduleEnabled('news')) in Vitest, test.skip(!moduleEnabled('news'), …) in Playwright), and shared tests seed only what the modules that are on need. Write new tests the same way.
The docs #
tests/unit/docs.test.ts checks the documentation:
- every relative link and image in
docs/(and the links intodocs/from the README) resolves; - every page has a title, a description and an order, and is listed in
docs/README.md; - every image in
docs/imagesis used by a page; - nothing outside code in the pages would break an MDX-based docs site (
<before a letter, or braces); - the environment variable table lists exactly the variables in
.env.example; - the editor guide names every guide the admin ships with.
After changing .env.example, run pnpm docs:env to rewrite the table.
Screenshots #
The screenshots in docs/images are taken from the demo site by one command:
pnpm docs:screenshots
- It seeds the demo into a throwaway database (
DOCS_DATABASE_URL, or a database namedtolk-docs-screenshotsbeside a MongoDBDATABASE_URL). A database it seeded before is rebuilt; any other database with content is refused, so it never writes into a real site. - It starts the development server on a free port. AI translation gets a placeholder key, so the AI controls show, and the AI service's address points at a stand-in on your machine that refuses every call. The run fails if the site makes a single call to it.
- It logs in with
DEMO_ADMIN_EMAILandDEMO_ADMIN_PASSWORD, or with an account it makes for the run. - It takes each screen in
scripts/docs/shots.tsat 1440 × 900 and writes it todocs/imagesas WebP. A full run removes images no shot takes any more, and fails if the folder grows past 3 MB. - It drops the server's cached pages (Next.js keeps them in
.next/cache, which your ownpnpm devshares), stops it, and deletes the demo's content and files again.
Options:
--url http://localhost:3000takes the pictures from a site that is already running, seeded with the demo and started with a placeholderANTHROPIC_API_KEY. It needsDEMO_ADMIN_EMAILandDEMO_ADMIN_PASSWORDfor an admin of that site, and cannot check for AI calls.--only admin/translate-menu,site/hometakes only the named shots.--port 3100picks the port of the server it starts.
Stop pnpm dev before a full run: Next.js runs one development server per folder.
To add a screenshot, add a shot to scripts/docs/shots.ts (a name and a function that opens the screen), run the command, and use the image in a page: .