- Add AML scope note to Handoff - RN Multichain Probe (sanctions-only vs full KYT) - Add human-blocked section with 3 precise next steps for owner - Create Task 11 Pre-flight Inventory: library choice, dev/prod flow, admin UI gaps, backend gaps, risks, acceptance criteria
9.2 KiB
title, tags
| title | tags | |
|---|---|---|
| Testing |
|
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.tsand**/?(*.)+(spec|test).ts setupFilesAfterEach:__tests__/setup.ts— bootsmongodb-memory-server, connects mongoose, and cleans collections between testsmaxWorkers: 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, relationshipsrequest-network-adapter.test.ts,request-network-webhook.test.ts,rn-in-house-checkout.test.ts— Request Network checkout and webhook behaviorpayment-ledger.service.test.ts,payment-release-refund-orchestration.test.ts— ledger and release/refund behaviorcomplete-backend.test.ts— Auth, marketplace, chat, notification, address, user, file, email, AI
Commands
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 --:
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
- Place file under
__tests__/(or colocated*.test.tsnext to the source). - Import the app and use
supertest:
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);
});
});
- Use the in-memory DB — connections are wired in
setup.ts. Each test starts with a clean collection. - 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: 1makes 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>/srcand<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
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) |
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
- Colocate
MyComponent.test.tsxnext toMyComponent.tsx, or place in__tests__/<domain>-test/. - Render with RTL and assert via accessible queries:
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();
});
- Mock
lib/axiosif the component makes API calls:
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
- Add
e2e/<feature>.spec.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/);
});
- Run
yarn test:e2e:headedto debug. - 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:
- 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 forgottenmongoose.disconnect()or open Redis client. The sharedsetup.tshandles this, but custom suites might not. - Frontend test fails on
window.matchMedia—jest.setup.jspolyfills it; if you add a new test runner config, copy that polyfill. - Playwright flaky — use
await expect(...).toBeVisible()rather thanwaitForSelectorand increase per-test timeout inplaywright.config.tsfor slow flows. - Coverage low but the test exists — make sure the file is in
collectCoverageFromand not excluded by anindex.tsfilter.