Why we shifted from UTs to CTs
We initially relied on Jest and Enzyme for unit tests. While effective for isolated validation, this approach introduced three key friction points:
- Integration blind spots: Unit tests validate isolated parts, but confidence drops once those parts interact on a page.
- High boilerplate: Complex pages (5–10 components) required extensive, brittle mocks for each component.
- Environment fidelity: UTs often ran in jsdom-like environments. Cypress CT runs in a real browser, which better reflects production behavior.
Moving to Cypress Component Testing lets us test pages as cohesive units while rendering in an actual browser. We saw roughly 50–60% less test code with higher confidence because we tested interactions and integrated behavior rather than isolated pieces.
Component testing workflow and architecture
Our goals for Component Testing were determinism, speed, and realism. To achieve this, we standardized on:
- MSW (Mock Service Worker) to intercept network calls and return controlled responses.
- Page-level mounting to render whole pages (or complex composites) so inter-component behavior is exercised.
- Scenario matrices to codify multiple API response combinations (empty, error, partial, large) and assert the resultant UI.
These tests run as part of CI for every merge request, serving as a quality gate. Merges are blocked unless CTs pass, ensuring consistent >85% coverage across features and driving UI quality earlier in the development cycle.
Why we still needed E2E UI automation
CTs give excellent coverage, but some failures only surface in real environments: configuration quirks, auth/integration edges, and multi-system workflows. We added a thin, reliable E2E layer to validate the primary, business-critical paths end-to-end.
When designing our E2E strategy, we recognized two important factors:
- Certain essential steps, like provisioning a backup proxy or creating a VM, occur outside the browser.
- Crucially, our existing rich API automation in PyTest was perfectly suited to manage these out-of-browser operations.
To bridge the gap, we built a hybrid workflow connecting Cypress with our existing Python-based automation.
End-to-end hybrid workflow: Cypress + automation server + PyTest
We implemented a small FastAPI automation server that exposes HTTP endpoints. Cypress calls these endpoints to trigger existing PyTest automation functions, receives context back (IDs, credentials, connection info), and proceeds with UI steps.