The boilerplate includes a comprehensive test suite with three layers: Vitest (unit tests), Playwright (E2E, accessibility, responsive), and Lighthouse CI (performance auditing).
Test Commands
npm run test # Vitest unit tests
npm run test:watch # Vitest watch mode
npm run test:a11y # WCAG 2.2 AA accessibility tests (Playwright + axe-core)
npm run test:responsive # Responsive design tests (320px, 768px, 1280px)
npm run lighthouse:mobile # Lighthouse CI audit
npm run lint:ci # ESLint errors only (current CI gate)
npm run lint:strict # ESLint with zero warnings (target gate)
npm run lint:debt # Historical warning debt report
npm run audit:guardrails # Project-specific anti-regression checks
npm run audit:api-patterns # API security wrapper coverage
npm run audit:rls # Static RLS coverage
npm run audit:load # Configurable API load smoke test
npm run test:staging # Real staging readiness probes
npm run db:types:check # Supabase schema/type coverageUnit Tests (Vitest)
Tests in __tests__/ configured with vitest.config.ts (node environment).
| Test File | What’s Tested |
|---|---|
i18n/config.test.ts |
Locale utilities: getLanguageCode, getIntlLocale, normalizeLocale, getOgLocale |
i18n/key-parity.test.ts |
Validates FR/EN translation files have identical key sets |
security/sanitize.test.ts |
HTML escaping, email/URL/slug sanitization, SQL injection detection, XSS prevention, attack pattern detection |
security/rate-limit-ip.test.ts |
IPv6 /64 network-prefix collapse in normalizeRateLimitIdentifier — closes the per-host-bit rotation bypass on dynamic IPv6 ranges; verifies composite user:<uuid>:<ipv6> keys preserve the prefix and collapse only the IP |
billing/trial.test.ts |
Trial config plumbing through resolvePlan() — verifies pricingConfig.plans.pro.trialDays is env-driven and bounded (0–730), that Free and Business plans do not have a trial, and that trialDays propagates from config to the resolved plan |
workspace/slug.test.ts |
generateWorkspaceSlug() contract — produces lowercase RFC 4122 UUID v4, stays inside [a-z0-9-], is collision-free across 5,000-row batches, and workspaceConfig.slug.maxGenerationAttempts sits in the documented bounded-retry range |
email/templates-render.test.ts |
Render invariants for the shared monochrome email shell (lib/email/layout.ts) and all 7 builders — DOCTYPE present, preheader emitted, dark-mode @media rule, Outlook VML buttons, XSS escaping intact, no gradient regression, no unrendered ${'{}'} template leaks |
E2E Tests (Playwright)
Tests in tests/ configured with playwright.config.ts (Chromium, 30s timeout, parallel on CI).
| Test File | What’s Tested |
|---|---|
a11y/axe-scan.spec.ts |
WCAG 2.2 AA accessibility on: landing, pricing, login, contact, terms pages (using axe-core) |
responsive/viewport-320.spec.ts |
Mobile: no horizontal overflow, text readability, touch targets (44px min) |
responsive/viewport-768.spec.ts |
Tablet: card layout, forms, image scaling |
responsive/viewport-1280.spec.ts |
Desktop: navigation, content width, footer, pricing layout |
Lighthouse CI
lighthouserc.js uses the desktop preset and audits key pages (/fr-FR, /fr-FR/pricing, /fr-FR/login). The only provided script, npm run lighthouse:mobile, overrides that with mobile emulation. The score thresholds below are asserted as warn — they surface in the report but do not fail CI; tighten them to error in lighthouserc.js if you want a hard gate.
| Metric | Target Score (warn) |
|---|---|
| Accessibility | 90% |
| Performance | 85% |
| Best Practices | 90% |
| SEO | 90% |
Quality Audit Commands
npm run audit:security # npm audit (vulnerability scan)
npm run audit:secrets # secretlint (secret detection in code)
npm run audit:guardrails # project guardrails: direct credits writes, env leakage, schema mirrors
npm run audit:api-patterns # API security wrappers and route-pattern exceptions
npm run audit:rls # full-schema RLS enabled/policy coverage
npm run audit:load # HTTP load smoke test against a configured external target
npm run db:types:check # generated Supabase types cover full schema tables/views
npm run audit:deps # knip (unused dependencies/exports)
npm run audit:circular # dependency-cruiser (circular imports)
npm run audit:bundle # Bundle size analysis (webpack build; analyzer does not emit reports under Turbopack)GitHub CI
.github/workflows/ci.yml runs on pull requests and pushes to main. It gates typecheck, lint:ci, lint:strict, project guardrails, API-pattern coverage, RLS coverage, Supabase type coverage, unit tests, secret scan, production build, Playwright accessibility, and responsive checks. Historical warning visibility lives in npm run lint:debt; that report is intentionally separate from the zero-warning gate.
Staging and External Checks
npm run test:staging targets a real deployed environment through STAGING_BASE_URL (or NEXT_PUBLIC_APP_URL) and real provider credentials. It probes /api/health, Stripe webhook endpoint and required events, Supabase Postgres schema, cron extensions, storage buckets, enabled jobs, GDPR deletion proof columns, Upstash Redis, and the configured Brevo/Mailjet account. Safe job execution is optional and requires STAGING_RUN_SAFE_JOB=true plus STAGING_SAFE_JOB_NAME.
npm run audit:load is a lightweight external API load smoke test. Configure LOAD_TEST_BASE_URL, LOAD_TEST_DURATION_SECONDS, LOAD_TEST_CONCURRENCY, LOAD_TEST_P95_MS, and optionally LOAD_TEST_ENDPOINTS JSON to cover authenticated or critical API paths. It complements, but does not replace, a third-party security/performance review.
Unit tests: add in __tests__/ matching **/*.test.ts.
E2E tests: add in tests/ as Playwright specs.
Accessibility: add new pages to tests/a11y/axe-scan.spec.ts.