Testing Mission-Critical Financial Interfaces with Jest, RTL, and Playwright
How we reached 85% coverage on WealthHat's financial UI and built confidence in releases — unit tests, integration tests, and E2E flows that actually catch regressions.
Why fintech UI testing is different
A typo in a blog post is embarrassing. A typo in a transfer confirmation screen is a incident.
Financial interfaces demand predictable behavior, audit-friendly flows, and regression safety when teams ship weekly. At WealthHat, I implemented automated test suites with Jest and React Testing Library (RTL) that reached ~85% code coverage on mission-critical advisory modules.
At Timbu, Playwright caught 15 major cross-browser issues before they reached production on high-traffic payment flows.
This is how we structured testing without slowing delivery.
The testing pyramid for frontend fintech
| Layer | Tool | Purpose |
|---|---|---|
| Unit / component | Jest + RTL | Business logic, form validation, component contracts |
| Integration | RTL + MSW | Multi-component flows, API mocking |
| E2E | Playwright | Critical user journeys, cross-browser |
We did not aim for 100% E2E — that is slow and flaky. We aimed for high confidence on money paths.
RTL: test behavior, not implementation
Bad test:
expect(wrapper.find(".submit-btn").length).toBe(1);
Good test:
await userEvent.click(screen.getByRole("button", { name: /confirm transfer/i }));
expect(await screen.findByText(/transfer scheduled/i)).toBeInTheDocument();
Users interact with labels and roles, not CSS classes. RTL forces you to write accessible markup — a side benefit that improved WCAG compliance across modules.
Mock APIs realistically with MSW
Financial UIs depend on edge cases: partial failures, stale balances, permission errors. Mock Service Worker let us simulate these in tests and Storybook:
http.get("/api/portfolio/:id", ({ params }) => {
if (params.id === "locked") {
return HttpResponse.json({ error: "ACCOUNT_LOCKED" }, { status: 403 });
}
return HttpResponse.json(mockPortfolio);
});
Tests for error states prevented silent failures when backend contracts changed.
Playwright for critical paths
We maintained a small suite of E2E specs:
- Advisor login → client search → open portfolio
- Create financial goal → save → verify persistence
- Export report → confirm download trigger
Playwright's trace viewer shortened debugging when CI failed. Running against Chromium + WebKit caught layout issues RTL missed.
At TIIDELab, Jest automation saved 10+ hours per release cycle by catching UI regressions before QA handoff.
Coverage with intent
85% coverage was a team agreement, not a vanity metric. We excluded:
- Third-party wrappers with no logic
- Pure layout components with no behavior
We required coverage on:
- Currency and percentage formatters
- Validation schemas (Zod)
- Permission-gated actions
- Optimistic update rollback logic
CI integration
Tests ran on every pull request via GitHub Actions:
- name: Unit & integration tests
run: npm run test -- --coverage --ci
- name: E2E (critical)
run: npx playwright test --project=chromium
Failed E2E uploaded traces as artifacts. Reviewers could diagnose without reproducing locally.
Key takeaways
- Prioritize money paths in E2E; cover logic heavily with RTL
- MSW makes financial edge cases testable
- Coverage targets should exclude noise — measure meaningful branches
- Playwright traces turn flaky-test debugging from hours into minutes