Initial commit: nick docs

This commit is contained in:
moojttaba
2026-05-23 20:35:34 +03:30
commit 0da235ae27
90 changed files with 18268 additions and 0 deletions

262
07 - Development/Testing.md Normal file
View File

@@ -0,0 +1,262 @@
---
title: Testing
tags: [development]
---
# Testing
Both repos use **Jest** as the unit/integration runner. The frontend additionally uses **React Testing Library** for component tests and **Playwright** for end-to-end browser tests. This page covers what exists today, how to run it, and how to add new tests.
---
## Backend testing
### Stack
- **Jest 29** + **ts-jest 29** — TypeScript transpilation on the fly
- **supertest 7** — HTTP assertions against the Express app
- **mongodb-memory-server 10** — in-memory MongoDB per test run (no Docker needed)
### Jest configuration
`backend/jest.config.js`:
- Preset: `ts-jest`
- Environment: `node`
- Test glob: `**/__tests__/**/*.test.ts` and `**/?(*.)+(spec|test).ts`
- `setupFilesAfterEach`: `__tests__/setup.ts` — boots `mongodb-memory-server`, connects mongoose, and cleans collections between tests
- `maxWorkers: 1` — tests run serially (DB-state-sensitive)
- `testTimeout: 30000`
### Test suites
`backend/__tests__/` contains:
| File | What it covers |
|------|----------------|
| `basic.test.ts` | Smoke test of the bootstrap |
| `file-service.test.ts` | Upload + Sharp image-processing pipeline |
| `payment-integration.test.ts` | End-to-end pay-in / pay-out across providers |
| `payment-system.test.ts` | Payment service unit tests |
| `shkeeper-webhook.test.ts` | Signature verification + status transition |
| `simple-marketplace.test.ts` | Purchase-request + offer flow |
| `simple-payment.test.ts` | Single-provider payment fast-path |
| `simple-user.test.ts` | Auth + signup + JWT issuance |
| `setup.ts` | Shared Jest setup (DB, env vars, helpers) |
There are also four large aggregate suites referenced in `package.json` (some may live in branches or be reintroduced as the codebase evolves):
- `models.test.ts` — every Mongoose schema, validation, indexes, relationships
- `payment-services.test.ts` — DePay, SHKeeper, Web3, admin operations
- `complete-backend.test.ts` — Auth, marketplace, chat, notification, address, user, file, email, AI
- `shkeeper-backend.test.ts` — Service layer + API endpoints for SHKeeper
### Commands
```bash
cd ~/code/backend
npm run test # run all *.test.ts files once (forceExit on)
npm run test:watch # interactive watch mode
npm run test:coverage # also emit coverage report to ./coverage/
npm run test:all # explicit __tests__/ folder
# Focused suites (each maps to a single file):
npm run test:models # jest __tests__/models.test.ts
npm run test:payment # jest __tests__/payment-services.test.ts
npm run test:complete # jest __tests__/complete-backend.test.ts
npm run test:shkeeper # jest __tests__/shkeeper-backend.test.ts
```
Pass extra Jest flags after `--`:
```bash
npm run test -- --testPathPattern=payment --verbose
```
### Coverage targets
- Statements & lines: **≥ 80 %** on changed files
- Branches: **≥ 70 %** on changed files
- Critical paths (auth, payment, escrow release) — aim for **≥ 90 %**
Coverage is collected from `src/**/*.ts` excluding `.d.ts` and `__tests__/`. View the HTML report at `coverage/lcov-report/index.html` after running `npm run test:coverage`.
### Adding a new backend test
1. Place file under `__tests__/` (or colocated `*.test.ts` next to the source).
2. Import the app and use `supertest`:
```ts
import request from 'supertest';
import { app } from '../src/app';
describe('GET /api/health', () => {
it('returns 200', async () => {
const res = await request(app).get('/health');
expect(res.status).toBe(200);
expect(res.body.success).toBe(true);
});
});
```
3. Use the in-memory DB — connections are wired in `setup.ts`. Each test starts with a clean collection.
4. Mock outbound HTTP (SHKeeper, OpenAI) with `jest.spyOn(axios, 'post')`. Never hit a real provider from tests.
> [!warning] `maxWorkers: 1` makes tests serial. Don't introduce timing-sensitive parallelism — instead, keep individual tests small and deterministic.
---
## Frontend testing
### Stack
- **Jest 29** + **ts-jest 29** + **jsdom 29** — component & util tests
- **@testing-library/react 16** + **@testing-library/jest-dom 6** + **@testing-library/user-event 14**
- **Playwright 1.56** — browser-driven E2E
- **identity-obj-proxy** — stubs CSS module imports
### Jest configuration
`frontend/jest.config.js`:
- Environment: `jsdom`
- Roots: `<rootDir>/src` and `<rootDir>/__tests__`
- Test globs: `**/__tests__/**/*.test.(ts|tsx|js)`, `**/__tests__/**/*.spec.(ts|tsx|js)`, `**/*.(test|spec).(ts|tsx|js)`
- Asset mapping: images & fonts → `__tests__/mocks/fileMock.js`, CSS → `identity-obj-proxy`
- Module aliases: `src/*``<rootDir>/src/*`
- `setupFilesAfterEach`: `jest.setup.js` (sets up RTL matchers, axios mocks, env)
### Test layout — `__tests__/`
Tests are grouped by domain:
```
__tests__/
├── account-test/
├── address-test/
├── auth-test/
├── chat-test/
├── components-test/
├── file-test/
├── integration-test/
├── marketplace-test/
├── notification-test/
├── payment-test/
├── user-test/
├── utils-test/
└── mocks/
```
Each folder contains one or more `*.test.tsx` files. See `__tests__/README.md`, `PROJECT_TEST_CHECKLIST.md`, and `TEST_ORGANIZATION_SUMMARY.md` in the repo for current status.
### Commands
```bash
cd ~/code/frontend
yarn test # full Jest suite
yarn test -- --watch # watch mode
yarn test -- --coverage # coverage report
yarn test -- payment # name-pattern filter
```
### Playwright E2E
`frontend/e2e/` contains four headless-Chromium suites:
| File | Coverage |
|------|----------|
| `auth.spec.ts` | Sign up, login, logout, password reset |
| `marketplace.spec.ts` | Browse, create request, accept offer |
| `shop.spec.ts` | Public shop pages |
| `performance.spec.ts` | Performance budgets (LCP, INP) |
```bash
yarn test:e2e # headless run
yarn test:e2e:ui # open Playwright Inspector
yarn test:e2e:headed # show the browser
yarn test:e2e:debug # step through with devtools
yarn test:perf # only e2e/performance.spec.ts
yarn playwright:install # one-time browser download
```
Playwright assumes the backend + frontend are reachable at the URLs in `playwright.config.ts` (defaults: `http://localhost:8083` and `http://localhost:5001`). Start both stacks first — see [[Local Setup]].
### Coverage targets (frontend)
- Components: **≥ 70 %** statement coverage
- Hooks / utilities: **≥ 90 %**
- Critical flows (login, checkout): covered by both unit and Playwright suites
### Adding a new component test
1. Colocate `MyComponent.test.tsx` next to `MyComponent.tsx`, or place in `__tests__/<domain>-test/`.
2. Render with RTL and assert via accessible queries:
```tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ThemeProvider } from 'src/theme/theme-provider';
import { MyComponent } from './MyComponent';
const renderWithProviders = (ui: React.ReactElement) =>
render(<ThemeProvider>{ui}</ThemeProvider>);
it('submits the form', async () => {
renderWithProviders(<MyComponent />);
await userEvent.type(screen.getByLabelText(/email/i), 'a@b.com');
await userEvent.click(screen.getByRole('button', { name: /submit/i }));
expect(screen.getByText(/thanks/i)).toBeInTheDocument();
});
```
3. Mock `lib/axios` if the component makes API calls:
```ts
import api from 'src/lib/axios';
jest.mock('src/lib/axios');
const mockedApi = api as jest.Mocked<typeof api>;
mockedApi.post.mockResolvedValueOnce({ data: { success: true } });
```
### Adding a Playwright test
1. Add `e2e/<feature>.spec.ts`:
```ts
import { test, expect } from '@playwright/test';
test('user can log in', async ({ page }) => {
await page.goto('/auth/jwt/sign-in');
await page.getByLabel('Email').fill('admin@marketplace.com');
await page.getByLabel('Password').fill('Moji6364');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/\/dashboard/);
});
```
2. Run `yarn test:e2e:headed` to debug.
3. Keep specs idempotent — clean up any test data the spec creates (or rely on the seeded test users).
---
## CI integration
The Gitea Actions workflows (see [[CI-CD Pipeline]]) currently build and push Docker images but do not yet run Jest. If you add test gating, add a `Run tests` step before the `Build` step:
```yaml
- name: Install
run: yarn install --frozen-lockfile
- name: Test
run: yarn test --ci --runInBand
```
---
## Debugging tips
- **Backend test hangs** — add `--detectOpenHandles --forceExit`. Almost always a forgotten `mongoose.disconnect()` or open Redis client. The shared `setup.ts` handles this, but custom suites might not.
- **Frontend test fails on `window.matchMedia`** — `jest.setup.js` polyfills it; if you add a new test runner config, copy that polyfill.
- **Playwright flaky** — use `await expect(...).toBeVisible()` rather than `waitForSelector` and increase per-test timeout in `playwright.config.ts` for slow flows.
- **Coverage low but the test exists** — make sure the file is in `collectCoverageFrom` and not excluded by an `index.ts` filter.