141 lines
8.3 KiB
Markdown
141 lines
8.3 KiB
Markdown
# Testing
|
|
|
|
**Last updated:** 2026-05-14
|
|
**Scope:** Turborepo monorepo at `/Users/arthur.belleville/Documents/perso/projects/xtablo-source`
|
|
|
|
## Frameworks
|
|
|
|
- **Vitest** is the only JS/TS test runner across every app and package (no Jest)
|
|
- **React Testing Library** (`@testing-library/react`) for component tests; `@testing-library/jest-dom` matchers loaded via setup files
|
|
- **happy-dom / jsdom** for DOM emulation in frontend tests (`apps/main/vite.config.ts` configures `environment: "jsdom"`)
|
|
- **Vitest with mocked Supabase** for `apps/api` — node environment, real Hono router exercised, Supabase client stubbed (`apps/api/src/__tests__/setup.ts` + `globalSetup.ts`)
|
|
- **pgTAP** SQL tests under `supabase/tests/database/*.test.sql` for schema/RLS/trigger correctness (run via the Supabase CLI, separate from Vitest)
|
|
|
|
## Test Commands
|
|
|
|
From the repo root (all dispatched by Turborepo via `turbo.json`):
|
|
|
|
```bash
|
|
pnpm test # Run every package's `test` task
|
|
pnpm test:watch # Watch mode across the workspace
|
|
pnpm test:api # Run only @xtablo/api (turbo --filter)
|
|
cd apps/main && pnpm test # Run a single package directly
|
|
cd apps/api && pnpm test:watch
|
|
```
|
|
|
|
Per-package script conventions (see e.g. `apps/api/package.json`):
|
|
- `"test": "NODE_ENV=test vitest run"`
|
|
- `"test:watch": "NODE_ENV=test vitest"`
|
|
- Frontend apps similarly use `vitest run` / `vitest` (no `NODE_ENV=test` prefix required)
|
|
|
|
## Test File Location
|
|
|
|
Tests are **co-located** with the source they exercise:
|
|
|
|
- React components: `Foo.tsx` + `Foo.test.tsx` in the same folder
|
|
- e.g. `apps/main/src/components/CustomModal.test.tsx`, `apps/main/src/components/NavigationBar.test.tsx`
|
|
- Hooks / contexts: `useFoo.ts` + `useFoo.test.ts(x)`
|
|
- e.g. `apps/main/src/contexts/UpgradeBlockContext.test.tsx`
|
|
- API: tests under `apps/api/src/__tests__/<area>/<area>.test.ts` (grouped by router/concern), plus co-located helper tests like `apps/api/src/helpers/orgIcons.test.ts`
|
|
- Expo app sometimes uses `__tests__/` folders: `xtablo-expo/components/__tests__/BillingPaywall.test.tsx`
|
|
|
|
## Vitest Configs
|
|
|
|
Two distinct flavors live in the repo:
|
|
|
|
1. **Frontend (Vite + Vitest)** — config embedded inside `vite.config.ts`. Example, `apps/main/vite.config.ts`:
|
|
```ts
|
|
test: {
|
|
globals: true,
|
|
environment: "jsdom",
|
|
setupFiles: "./src/setupTests.ts",
|
|
}
|
|
```
|
|
The Cloudflare plugin is skipped when `process.env.VITEST === "true"`. `VITE_SUPABASE_URL` / `VITE_SUPABASE_ANON_KEY` are stubbed via `define` when running under Vitest.
|
|
|
|
Other apps with the same pattern:
|
|
- `apps/admin/vite.config.ts` + `apps/admin/src/setupTests.ts`
|
|
- `apps/external/vite.config.ts` + `apps/external/src/setupTests.ts`
|
|
- `apps/clients/vite.config.ts` + `apps/clients/src/setupTests.ts`
|
|
|
|
2. **API (standalone Vitest)** — dedicated `apps/api/vitest.config.ts`:
|
|
```ts
|
|
test: {
|
|
globals: true,
|
|
environment: "node",
|
|
setupFiles: ["./src/__tests__/setup.ts"],
|
|
globalSetup: ["./src/__tests__/globalSetup.ts"],
|
|
testTimeout: 30000,
|
|
hookTimeout: 60000,
|
|
include: ["src/__tests__/**/*.test.ts", "src/**/*.test.ts"],
|
|
pool: "forks",
|
|
fileParallelism: false,
|
|
}
|
|
```
|
|
`fileParallelism: false` is deliberate — tests share initialized middleware state and can't safely run concurrently across files.
|
|
|
|
## Setup Files
|
|
|
|
- `apps/main/src/setupTests.ts` — imports `@testing-library/jest-dom`, registers an `afterEach(cleanup)`, mocks `ResizeObserver`, `Element.prototype.scrollIntoView`, `Element.prototype.scrollTo`, and `window.matchMedia`. Also imports `./i18n.test` to bootstrap i18next for tests.
|
|
- `apps/admin/src/setupTests.ts`, `apps/external/src/setupTests.ts`, `apps/clients/src/setupTests.ts` — analogous per-app setup
|
|
- `apps/api/src/__tests__/setup.ts` — minimal per-test-file setup (DB init handled by `globalSetup.ts`)
|
|
- `apps/api/src/__tests__/globalSetup.ts` — boots the test middleware manager via `createConfig()` reading `.env.test`
|
|
|
|
## Mocking Patterns
|
|
|
|
- **Frontend component tests** import the component and render it with a `renderWithProviders` helper (see `apps/main/src/utils/testHelpers.tsx` and `apps/clients/src/test/testHelpers.test.tsx`) that wires QueryClient, router, i18n, and Zustand stores.
|
|
- **React Query mocking**: integration tests mock the hook return values directly with `vi.mock(...)` and inject `{ data, isLoading, error }` shapes.
|
|
- **Supabase client**: API tests stub `supabase.from(...)` chains via `vi.fn()` — fixtures live in `apps/api/src/__tests__/fixtures/`.
|
|
- **Auth**: API middleware tests bypass real Supabase auth by overriding the Bearer-token validator and asserting on 401 paths (see `docs/MIDDLEWARE_TESTS.md`).
|
|
- **Toast / window APIs**: stubbed globally in `setupTests.ts` so individual tests don't have to.
|
|
- **i18n**: each frontend test setup imports `./i18n.test` so `useTranslation()` works without network.
|
|
|
|
## API Test Patterns
|
|
|
|
Documented in `docs/API_TESTS.md` and `docs/MIDDLEWARE_TESTS.md`. Key conventions:
|
|
|
|
- Tests live under `apps/api/src/__tests__/<area>/<area>.test.ts` (e.g. `notes/notes.test.ts`, `tasks/tasks.test.ts`)
|
|
- Each router has at minimum a smoke test that verifies the endpoint is reachable and returns the right shape
|
|
- Middleware is tested independently in `apps/api/src/__tests__/middlewares/middlewares.test.ts` — auth header validation, Supabase client injection, R2/Stream/email middleware behavior
|
|
- Test mode is detected via `NODE_ENV=test` in `createConfig()` so secrets load from `.env.test` instead of Google Secret Manager — no GCP credentials required to run the suite
|
|
- Fixtures (sample DB rows, sample Stripe payloads) live in `apps/api/src/__tests__/fixtures/`
|
|
- Helpers (token mocking, app builders) live in `apps/api/src/__tests__/helpers/`
|
|
- The `__tests__/README.md` documents the suite layout in-tree
|
|
|
|
Snapshot from `docs/MIDDLEWARE_TESTS.md`: 116 passing tests across the API suite at last documented run (2025-11-10), with explicit coverage for the Supabase, Auth, Stream, R2, and email middlewares.
|
|
|
|
## Coverage
|
|
|
|
- **No coverage threshold is enforced** in CI today — `vitest.config.ts` files do not declare `coverage` blocks and `package.json` has no `test:coverage` script at the root.
|
|
- Coverage can still be produced ad-hoc with `vitest run --coverage` in any individual package, but it's not part of the normal workflow.
|
|
- The repo relies on (a) Biome lint errors blocking CI, (b) `pnpm typecheck` (`tsc -b`) blocking CI, and (c) `pnpm test` blocking CI — coverage % is currently advisory only.
|
|
|
|
## Existing Test Inventory
|
|
|
|
Total Vitest/RTL test files (`*.test.ts(x)`, excluding `node_modules`, `dist`): **147**
|
|
|
|
Breakdown by area (approximate):
|
|
- `apps/main/src/**/*.test.tsx` — ~64 (components, contexts, providers, hooks)
|
|
- `apps/api/src/**/*.test.ts` — ~31 (routers, middlewares, helpers)
|
|
- `apps/admin/src/**/*.test.tsx` — pages, components, lib (e.g. `AnalyticsStudioPage.test.tsx`, `PrivilegedGate.test.tsx`)
|
|
- `apps/clients/src/**/*.test.ts(x)` — env + Vite config sanity checks plus page tests
|
|
- `apps/external/src/viteConfig.test.ts`, `apps/main/src/viteConfig.test.ts` — Vite build config smoke tests
|
|
- `xtablo-expo/**/*.test.ts(x)` — React Native (Expo) tests (e.g. `auth.test.ts`, `BillingPaywall.test.tsx`)
|
|
- `supabase/tests/database/*.test.sql` — 13 pgTAP files covering schema, RLS, triggers, indexes, Stripe + Apple billing functions
|
|
|
|
Representative examples worth reading first:
|
|
- `apps/main/src/components/CustomModal.test.tsx` — minimal RTL test
|
|
- `apps/main/src/components/NavigationBar.test.tsx` — uses `renderWithProviders`
|
|
- `apps/main/src/providers/UserStoreProvider.test.tsx` — Zustand + React Query store test
|
|
- `apps/main/src/contexts/UpgradeBlockContext.test.tsx` — context provider test
|
|
- `apps/api/src/helpers/orgIcons.test.ts` — pure-helper unit test
|
|
- `apps/api/src/__tests__/middlewares/middlewares.test.ts` — middleware integration suite
|
|
- `supabase/tests/database/02_rls_policies_core.test.sql` — pgTAP RLS coverage
|
|
|
|
## Reference Documents
|
|
|
|
- `docs/API_TESTS.md` — API router test catalog, env setup, known limitations
|
|
- `docs/MIDDLEWARE_TESTS.md` — middleware-by-middleware coverage notes
|
|
- `docs/ENV_TEST_SETUP.md` — `.env.test` structure
|
|
- `docs/TEST_FIXES.md`, `docs/TEST_ROUTER_REFACTOR.md` — historical notes on test infrastructure changes
|
|
- `docs/TESTING_WITH_FAKE_ACCOUNTS.md` — temporary-account flow for manual + integration testing
|