Skip to content

Testing Strategy

Gatherloop POS is tested at three levels, each catching a different class of bug, and each made possible by the layer boundaries described in Clean Architecture.

1. Usecase unit tests — business logic in isolation

Every usecase's state machine (getInitialStategetNextStateonStateChange) is tested against a mock repository, with no server, no database, and no UI rendered at all — just actions in, state out.

This is where the bulk of business-rule coverage lives — a discount calculation, a wallet balance deduction, a budget recomputation — because it's the cheapest layer to test and the one that changes most often.

2. Handler / integration tests — full rendering with mock data

One layer up, handler tests render the full presentation stack — controller → handler → screen → components — with React Testing Library, backed by the same mock repositories as the usecase tests. These catch bugs unit tests can't: a prop mapped incorrectly, a loading state never wired to a spinner, a confirmation modal that doesn't actually call the delete action.

Together, these two levels mean every CRUD screen's loading, error, empty, and success states — and every API handler's request parsing and response shape — are covered without ever needing a running system.

3. End-to-end tests — real browser, real API, real database

What neither of the above can catch: a field renamed on the Go side that silently breaks the TypeScript transformer, an SSR auth redirect, a print dialog, or a transaction that's supposed to actually deduct a wallet balance in the database. Playwright tests in apps/web-e2e drive a real Chromium browser against a real Next.js server, a real Go API, and a real database.

E2E coverage is deliberately narrow — it targets cross-page, cross-entity, money-handling flows that the layers above can't reach, and skips what's already well covered by handler tests:

FlowFileWhy E2E
Authenticationauth.spec.tsReal cookies and getServerSideProps redirects
Product CRUDproducts.spec.tsFull SSR data-fetch pipeline; a dependency for the transaction flow
Wallets & transferswallets.spec.tsReal money movement between two records at once
Transactionstransactions.spec.tsThe core POS flow: products → coupon → payment → wallet, spanning multiple entities
Expenses & budgetsexpenses.spec.tsCross-entity relationship between expense, budget, and wallet

Simple, self-contained entities — categories, materials, suppliers, coupon creation — are intentionally not E2E tested; handler tests already cover their CRUD states fully, and the incremental value of a full browser round-trip is low. Test data for each spec is created and torn down through direct API calls in beforeAll/afterAll rather than through the UI, keeping runs fast and independent of each other. The full rationale lives in E2E_TEST_PLAN.md at the repo root.

The shape of the pyramid

        ▲   E2E (Playwright)         5 flows — cross-cutting, money-critical
       ▲▲▲  Handler / HTTP tests     ~65 files — full render / full request per screen & endpoint
      ▲▲▲▲▲ Usecase tests            ~90 files — every business rule, isolated

Most bugs are cheapest to catch at the bottom, where a test needs no server, no browser, and runs in milliseconds — so that's where most of the tests live. E2E stays small and focused on what only a real, fully-wired system can prove.

Built with VitePress. Content lives in docs-site/ — see the README for how to run it locally.