Testing
The four test layers, how to run each, and where new tests belong.
Tests run on Vitest, configured as three projects in the root vitest.config.ts, plus Playwright for end-to-end tests of the admin.
| Layer | Command | Files | Needs |
|---|---|---|---|
| Unit | pnpm test:unit | packages/**/*.test.ts, apps/**/*.test.ts | nothing |
| Component | pnpm test:component | **/*.test.tsx (rooted in apps/cms) | Playwright's Chromium |
| Integration | pnpm test:integration | **/*.integration.test.ts | Docker test database |
| End-to-end | pnpm --filter nextjs-cms-app test:e2e | apps/cms/sections/__TESTS__/**/*.spec.ts | Running admin + database |
Unit tests
Fast, no I/O. Most of the core is covered here: field helpers and classes, validators, conditional rules, config merging, CLI helpers, schema generation (with the database mocked).
pnpm test:unit
pnpm test:unit:watch
pnpm vitest run packages/nextjs-cms/src/core/fields/__tests__/slug.test.tsPut tests next to the code: foo.ts → foo.test.ts, or a __tests__/ folder for larger suites.
Component tests
React components run in a real headless Chromium through Vitest browser mode (vitest-browser-react). The project is rooted in apps/cms, and @ resolves to the app. Name files *.test.tsx so the Node unit project never picks them up.
pnpm exec playwright install chromium # once
pnpm test:componentIntegration tests
Run against a real MariaDB started by Docker Compose (testing/docker-compose-test.yml, port 3307, data in tmpfs):
pnpm test:db:up
pnpm test:integration
pnpm test:db:down- Files are named
*.integration.test.ts. - They run serially (
--no-file-parallelism) against one shared database initialized once bytesting/global-test-setup.ts(with a file lock). - Connection defaults:
localhost:3307,root/password, databasenextjs_cms_test; override withTEST_DB_HOST,TEST_DB_PORT,TEST_DB_USER,TEST_DB_PASSWORD,TEST_DB_NAME. - Auth tests also need
ACCESS_TOKEN_SECRETandREFRESH_TOKEN_SECRET. - Test sections live in
packages/nextjs-cms/src/api/__tests__/test_sections(andtest_sections_localized), with a matchingtest.cms.config.ts.
Write an integration test whenever the behavior depends on SQL: submit classes, uniqueness, destination tables, locale rows, delete cascades.
End-to-end tests
Playwright drives the real admin (apps/cms/playwright.config.ts):
- Tests live next to their sections in
apps/cms/sections/__TESTS__/(*.spec.ts), with sections likee2e-all-fields.section.tsthat register every field type. - A setup project signs in once and stores the session in
playwright/.auth/admin.json. - Environment comes from
apps/cms/.env.test(E2E_*variables), andPLAYWRIGHT_BASE_URL(defaulthttp://localhost:3000). - Runs serially with one worker; reports go to
apps/cms/playwright/reports.
cd apps/cms
pnpm test:e2e # headless, tears down test data
pnpm test:e2e:ui # interactive
pnpm test:e2e:report # open the last reportCoverage
pnpm test:unit:coverageThresholds are set in vitest.config.ts (80% lines, functions, statements; 75% branches).
What to test for common changes
| Change | Tests |
|---|---|
| New field option | Field unit test (helper rejects bad input, class behavior), validator test, docs example compiles |
| Column type change | update-sections.test.ts |
| Submit behavior | Integration test in core/submit/__tests__ or api/__tests__/integration |
| Router / procedure | routers/*.test.ts (unit, with mocks) or integration |
| Admin UI input | Component test, and the e2e all-fields section |