Overview of the ignitionstack.pro quality gates. Tests are divided into unit, integration, and end-to-end layers so we can validate UI, business rules, and real browser flows without duplicating effort.
| Type | Tooling | Purpose |
|---|---|---|
| Unit & Integration | vitest + happy-dom + @testing-library/react | Fast feedback for components, hooks, repositories, actions |
| Coverage | @vitest/coverage-v8 | V8 coverage reports (./coverage) |
| Helpers | src/app/test/setup.tsx, src/app/test/utils/* | Global mocks (Next.js, next-intl) and factories |
| End-to-End | @playwright/test + playwright.config.ts | Full browser journeys with fixtures, auth setup, visual regression aids |
The Vitest config (vitest.config.ts) wires absolute imports (@/), loads .env.test, and points to src/app/test/setup.tsx. Playwright uses playwright.config.ts with base URL http://127.0.0.1:3100, per-project auth setup, HTML reports, and the shared output folder playwright-report/.
| Layer | Location | Validates | Typical Command |
|---|---|---|---|
| Unit | src/app/test/unit/**/*.test.ts[x] | Pure functions, hooks, UI primitives | vitest run src/app/test/unit/components --runInBand |
| Integration | src/app/test/integration/**/* | Server actions, repositories, API handlers, webhooks | vitest run src/app/test/integration/actions |
| End-to-End | src/app/test/e2e/{tests,pages,fixtures} | Real browser UX (navigation, auth, a11y) | npm run e2e (Playwright) |
src/app/test/unit/{actions,ai,components,hooks,lib,server,validations}.happy-dom and @testing-library/react through src/app/test/setup.tsx, which mocks next-intl, next/navigation, next/image, and next/link while loading .env.test.src/app/test/utils/test-factories.ts to avoid hand-written fixtures.render(<Component />) from Testing Library and assert using accessible queries (getByRole, findByText).vitest run src/app/test/unit/hooks/use-contact-form.test.ts.import { render, screen } from '@testing-library/react';
import { PricingCard } from '@/app/components/pricing-card';
test('renders CTA label', () => {
render(<PricingCard plan="pro" />);
expect(screen.getByRole('button', { name: /buy now/i })).toBeVisible();
});src/app/test/integration/{actions,api,repositories,server,webhooks}.ProjectRepository, ProductRepository, etc.), server actions, and API routes end-to-end within the app boundary.src/app/test/utils/supabase-mock.ts) plus cache helpers to simulate success/error branches without touching a real DB.test-factories.ts provide rich sample payloads.vitest run src/app/test/integration/repositories/project-repository.test.ts.ActionResult codes like DUPLICATE_SLUG).src/app/test/e2e/tests with Playwright fixtures under src/app/test/e2e/fixtures and page objects inside src/app/test/e2e/pages.auth.setup.ts seeds a storage state (e2e/.auth/user.json) when TEST_USER_EMAIL and TEST_USER_PASSWORD are available so authenticated flows can re-use the same session.../fixtures/test-fixtures to obtain strongly typed helpers (homePage, blogPage, etc.) and follow a BDD-style test.describe('Feature…') structure.npx playwright install --with-deps – install browsers/system deps (run once per machine)npm run dev:e2e – start Next.js locally on 127.0.0.1:3100 (optional when debugging)npm run e2e – headless suite (spawns dev:e2e automatically)npm run e2e:headed – headed mode for debuggingnpm run e2e:ui – Playwright UI explorernpm run e2e:debug – debug with inspectornpm run e2e:report – open the HTML report (playwright-report/)npm run dev:e2e unless PLAYWRIGHT_BASE_URL points to an existing server.test.use({ storageState: 'e2e/.auth/user.json' }); once the auth setup has created the file.npx playwright install --with-deps (once per machine/CI agent)..env.local (or the CI env) contains the same keys the app needs in dev.npm run e2e to execute the suite. Use npm run dev:e2e separately when you want to keep the dev server alive while iterating with npx playwright test --ui.| File | Purpose |
|---|---|
src/app/test/setup.tsx | Loads .env.test, clears mocks, and stubs Next.js globals before every Vitest run |
src/app/test/utils/test-factories.ts | Factory functions for posts, products, projects, insights… |
src/app/test/utils/supabase-mock.ts | Chainable mocks for Supabase from().select().eq() flows |
src/app/test/e2e/pages/* | Page objects (homePage, blogPage, etc.) containing visit + assert helpers |
scripts/test-build.sh | Smoke build executed via npm run build:test before CI e2e runs |
# Vitest layers
npm test # unit + integration
npm run test:watch # watch mode
npm run test:ui # Vitest UI
npm run test:coverage # coverage via v8
# Playwright
npm run dev:e2e # Start the dedicated Next.js server locally
npm run e2e # headless
npm run e2e:headed # headed
npm run e2e:ui # GUI to pick tests
npm run e2e:debug # debugger
npm run e2e:report # show last reportvi.mock to the file or block that really needs it.npm test passes locally (unit + integration)console.error during runsnpm run test:coverage updated if relevantnpm run e2e) pass or are skipped intentionallyKeep this page updated whenever you add utilities, commands, or best practices so the team always has a single source of truth.