Files

204 lines
6.3 KiB
Markdown

# Testing Patterns
**Analysis Date:** 2026-04-30
## Test Framework
**Runner:**
- Vitest 4.x for unit/integration tests in both packages:
- Frontend config: `frontend/vitest.config.ts`
- Backend config: `backend/vitest.config.ts`
- Config evidence:
- Frontend uses `environment: 'jsdom'` with React setup file `frontend/src/test/setup.ts`.
- Backend uses `environment: 'node'` with setup file `backend/src/test/setup.ts`.
**Assertion Library:**
- Vitest `expect`.
- Frontend extends DOM assertions via `@testing-library/jest-dom` in `frontend/src/test/setup.ts`.
**Run Commands:**
```bash
cd frontend && npm test # Watch/unit tests
cd frontend && npm run test:run # CI-style frontend run
cd frontend && npm run test:coverage # Frontend coverage
cd backend && npm test # Watch/unit tests
cd backend && npm run test:run # CI-style backend run
cd backend && npm run test:coverage # Backend coverage
cd frontend && npm run test:e2e # Stable Playwright suite
cd frontend && npm run test:e2e:all # Cross-browser Playwright suite
```
## Test File Organization
**Location:**
- Backend unit/integration tests are in `backend/src/test/*.test.ts`.
- Frontend unit/component/hook/context tests are in `frontend/src/test/**`.
- Browser E2E tests are in `frontend/e2e/*.spec.ts`.
**Naming:**
- Unit/integration: `*.test.ts` or `*.test.tsx` (for example `backend/src/test/routes-real.test.ts`, `frontend/src/test/components/MedicationDialogs.test.tsx`).
- E2E: `*.spec.ts` (for example `frontend/e2e/medication-edit.spec.ts`).
**Structure:**
```
backend/src/test/
setup.ts
*.test.ts
frontend/src/test/
setup.ts
App.test.tsx
components/*.test.tsx
context/*.test.tsx
hooks/*.test.ts
pages/*.test.tsx
utils/*.test.ts
frontend/e2e/
auth.setup.ts
fixtures/index.ts
*.spec.ts
```
## Test Structure
**Suite Organization:**
```typescript
describe("Feature Area", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("handles expected behavior", async () => {
// arrange
// act
// assert
expect(result).toEqual(expected);
});
});
```
Pattern evidence: `frontend/src/test/components/MobileEditModal.test.tsx`, `backend/src/test/planner.test.ts`.
**Patterns:**
- Setup pattern:
- Frontend centralizes browser mocks in `frontend/src/test/setup.ts` (fetch, localStorage, clipboard, history, i18n).
- Backend provides reusable app/database factories in `backend/src/test/setup.ts` (`buildTestApp`, `createTestUser`, `createTestMedication`).
- Teardown pattern:
- `afterAll` closes Fastify app and DB clients (`backend/src/test/planner.test.ts`, `backend/src/test/integration.test.ts`).
- Assertion pattern:
- Route tests assert both HTTP status and response body (`backend/src/test/routes-real.test.ts`).
- UI tests assert presence and behavior via Testing Library role/test-id queries (`frontend/src/test/components/MedicationDialogs.test.tsx`).
## Mocking
**Framework:**
- Vitest mocks (`vi.mock`, `vi.fn`, `vi.hoisted`, `vi.stubGlobal`).
**Patterns:**
```typescript
const { testClient, testDb } = vi.hoisted(() => {
const client = createClient({ url: ":memory:" });
const db = drizzle(client);
return { testClient: client, testDb: db };
});
vi.mock("../db/client.js", () => ({
db: testDb,
migrationsReady: Promise.resolve(),
}));
```
Pattern evidence: `backend/src/test/integration.test.ts`, `backend/src/test/routes-real.test.ts`.
```typescript
vi.mock("../../components/ConfirmModal", () => ({
ConfirmModal: ({ onConfirm }) => <button onClick={onConfirm}>confirm</button>,
}));
```
Pattern evidence: `frontend/src/test/components/MedicationDialogs.test.tsx`.
**What to Mock:**
- External side effects and infrastructure boundaries: SMTP/nodemailer, fetch network calls, auth/plugin env modules, browser APIs.
- Component dependencies in focused unit tests (replace heavy children with stubs).
**What NOT to Mock:**
- Core business behavior under direct test (route handlers in route tests, hook logic in hook tests, E2E API + UI flow in Playwright).
## Fixtures and Factories
**Test Data:**
```typescript
const userId = await createTestUser(client, { username: "testuser" });
const medId = await createTestMedication(client, { userId, name: "Test Medication" });
```
Pattern evidence: `backend/src/test/setup.ts`, used by `backend/src/test/medications.test.ts`.
```typescript
export const test = base.extend({
page: async ({ page }, use) => {
await applyVideoSafetyMode(page);
await setupAuthMeMock(page);
await use(page);
},
});
```
Pattern evidence: `frontend/e2e/fixtures/index.ts`.
**Location:**
- Backend factories/utilities: `backend/src/test/setup.ts`.
- Frontend E2E shared fixtures and API helpers: `frontend/e2e/fixtures/index.ts`.
## Coverage
**Requirements:**
- Frontend global thresholds in `frontend/vitest.config.ts`: lines/functions/branches/statements = 75.
- Backend global thresholds in `backend/vitest.config.ts`: lines 60, functions 65, branches 50, statements 60.
**View Coverage:**
```bash
cd frontend && npm run test:coverage
cd backend && npm run test:coverage
```
## Test Types
**Unit Tests:**
- Component/hook/utils tests in `frontend/src/test/**`.
- Utility/service route-unit style tests in `backend/src/test/*.test.ts`.
**Integration Tests:**
- Backend route interaction and multi-route behavior tests in files like:
- `backend/src/test/integration.test.ts`
- `backend/src/test/routes-real.test.ts`
**E2E Tests:**
- Playwright used with setup project and browser projects (`frontend/playwright.base.config.ts`).
- Auth/session and API seeding helpers in `frontend/e2e/fixtures/index.ts`.
## Common Patterns
**Async Testing:**
```typescript
await waitFor(() => {
expect(mockFn).toHaveBeenCalledTimes(1);
});
```
Pattern evidence: `frontend/src/test/context/AppContext.test.tsx`.
```typescript
const response = await app.inject({ method: "GET", url: "/settings" });
expect(response.statusCode).toBe(200);
```
Pattern evidence: `backend/src/test/routes-real.test.ts`.
**Error Testing:**
```typescript
const response = await app.inject({ method: "POST", url: "/planner/send-email", payload: { rows: [] } });
expect(response.statusCode).toBe(400);
expect(response.json()).toEqual({ error: "Missing planner data" });
```
Pattern evidence: `backend/src/test/planner.test.ts`.
---
*Testing analysis: 2026-04-30*