--- 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 - `request-network-adapter.test.ts`, `request-network-webhook.test.ts`, `rn-in-house-checkout.test.ts` — Request Network checkout and webhook behavior - `payment-ledger.service.test.ts`, `payment-release-refund-orchestration.test.ts` — ledger and release/refund behavior - `complete-backend.test.ts` — Auth, marketplace, chat, notification, address, user, file, email, AI ### 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: npm run test:models # jest __tests__/models.test.ts npm run test:complete # jest __tests__/complete-backend.test.ts npm run test -- --testPathPattern=request-network npm run test -- --testPathPattern=payment-ledger ``` 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 (Request Network, OpenAI, AML providers) with `jest.spyOn(axios, 'post')` or a dedicated adapter mock. 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: `/src` and `/__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/*` → `/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__/-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({ui}); it('submits the form', async () => { renderWithProviders(); 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; mockedApi.post.mockResolvedValueOnce({ data: { success: true } }); ``` ### Adding a Playwright test 1. Add `e2e/.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.