Building a Cypress Automation Suite: How It Works and What It Covers

Shipping a feature is one thing — knowing it still works three weeks later after five other features have been added is another. That's exactly what a Cypress automation suite is built for. It's not just a collection of tests; it's a safety net that runs automatically, covers your entire app from login to the last button on the last page, and tells you the moment something breaks. In this article, I'll walk you through how I structure a Cypress suite, what it covers, and why it's the first thing I set up on every project I take on.

the implementation

What is a Cypress Automation Suite?

A single Cypress test checks one thing — a button click, a form submission, a page load. A Cypress automation suite is the full collection of those tests, organized so they cover your entire application systematically.

Think of it like a checklist that runs itself. Every time a developer pushes new code, the suite opens a real browser, walks through your app from start to finish, and reports back: everything passed, or here's exactly what broke and where.

How the Suite is Structured

A well-built suite isn't a pile of test files. It follows a clear structure so tests are easy to find, easy to run, and easy to maintain.

Folder structure — one file per page Every page or feature in the app gets its own spec file. Nothing is mixed together.

javascript
1cypress/
2 e2e/
3 inventory/
4 inventory-items.cy.js
5 inventory-reports.cy.js
6 trading/
7 trading-journal.cy.js
8 portfolio.cy.js
9 running/
10 activities.cy.js
11 race-goals.cy.js
12 auth/
13 login.cy.js
14 user-settings.cy.js
15 fixtures/
16 app-constants.json ← shared IDs, endpoints, test data
17 app-constants.yaml ← human-readable source of truth
18 support/
19 commands.js ← reusable custom commands
20 e2e.js ← global setup
20 lines

This layout means when a bug shows up on the Portfolio page, you open portfolio.cy.js and you're exactly where you need to be.

Stable selectors — tests that survive UI changes

One of the biggest reasons Cypress suites break is fragile selectors. Targeting elements by CSS class or position means one styling update can break ten tests.

Instead, every interactive element in the app gets a dedicated id attribute:

javascript
1<button id="saveItem_inventoryPage">Save Item</button>
2<input id="itemName_inventoryPage" placeholder="Item name" />
2 lines

The naming convention follows camelCase_pageName — so the ID tells you exactly what the element is and which page it belongs to. Tests target these IDs directly and never break because of a design change.

What Each Test File Covers

Every spec file follows the same internal structure. This makes the test suite predictable — any developer can open any file and immediately understand what's being tested.

javascript
1describe("Inventory Items Page") {
2 before() → log in, seed test data
3 describe("Page load") {
4 ✓ shows the items list
5 ✓ shows correct column headers
6 ✓ shows empty state when no items exist
7 }
8 describe("Create item") {
9 ✓ opens the form when Add button is clicked
10 ✓ creates a new item with valid data
11 ✓ shows success message after save
12 ✓ new item appears in the list
13 ✓ shows error when name is empty
14 ✓ shows error when quantity is negative
15 }
16 describe("Edit item") {
17 ✓ opens edit form with existing data pre-filled
18 ✓ saves updated values correctly
19 ✓ shows error when saving with empty required field
20 }
21 describe("Delete item") {
22 ✓ shows confirmation dialog before deleting
23 ✓ removes item from list after confirm
24 ✓ does not delete when user cancels
25 }
26 describe("API error handling") {
27 ✓ shows error message when load fails
28 ✓ shows retry button on network failure
29 ✓ form shows error when save request fails
30 }
31 after() → clean up test data
32}
32 lines

Every feature is covered from three angles: what works (happy path), what shouldn't work (validation), and what happens when things go wrong (error handling).

What the Suite Covers

What the Suite Covers

Functional coverage

AreaWhat's tested
Page loadData loads correctly, correct layout renders, empty state appears when there's no data
FormsRequired field validation, character limits, correct data saved to the database
Create / Edit / DeleteFull CRUD operations with success and failure scenarios
NavigationLinks go to the right pages, breadcrumbs work, back navigation is correct
Filters & SearchFiltering returns the right results, search is case-insensitive, empty search shows all results
SortingColumns sort ascending and descending correctly
PaginationCorrect number of items per page, next/previous navigation works

API coverage

Every API call the UI makes is verified — not just that it succeeds, but that it returns the right data and the UI displays it correctly.

javascript
1cy.intercept('GET', '/api/items').as('getItems')
2cy.visit('/inventory')
3cy.wait('@getItems').its('response.statusCode').should('eq', 200)
3 lines

When an API call fails, the test also verifies the UI handles it gracefully — showing an error message instead of a blank screen or a crash.

Auth and access coverage

ScenarioTested
Logged-out user is redirected to login
Login with valid credentials
Login with wrong password shows error
Session persists across page refresh
Logout clears session and redirects

How Tests Are Kept Reliable

A test suite that passes today but randomly fails tomorrow is worse than no suite at all. Here's how I keep tests consistent:

Tests clean up after themselves. Any data created during a test is deleted in the after() hook. The database is always in the same state when the next test runs.

Tests don't depend on each other. Each test can run in isolation. If test #4 fails, test #5 still runs correctly — it doesn't depend on what test #4 did.

Tests always run headed (visible browser). I run every test with a real, visible browser:

npx cypress run --headed --browser chrome --spec "cypress/e2e/inventory/**"

You can watch every click and every assertion happen in real time. No hidden steps, no black-box results.

New IDs are registered immediately. Every time a new element is added to the app, its ID is added to app-constants.json before the test is written. The constants file is always the authority.

What the Coverage Report Looks Like

After every test run, three reports are updated: 1. Feature coverage report — which pages and features have tests, and which don't yet 2. Pass/fail history — when the suite last ran, how many tests passed, and what failed 3. Spec file registry — maps every spec file to the feature it covers This gives both the developer and the client a clear view of how much of the app is protected at any point in time.

javascript
1before(() => {
2 cy.task("log", "=== Starting Cypress Test Suite ===");
3});
4
5afterEach(function () {
6 const title = this.currentTest?.title || "Unknown test";
7 const state = this.currentTest?.state || "unknown";
8 cy.task("log", `Test "${title}": ${state}`);
9});
9 lines

What You Get as a Client

When I deliver a feature, the Cypress suite comes with it — not as an afterthought, but as part of the definition of done. A ticket isn't closed until tests are written, run, and 100% passing.

You get:

  • Full CRUD coverage for every data operation in your app
  • API error scenarios tested — your users never see a blank screen
  • Auth flows verified — no unauthorized access slips through
  • A test suite you can run yourself — one command, real browser, real results
  • Tests that stay green — because they're built to be maintainable from day one

The goal isn't just covering lines of code. It's giving you confidence that when your app is in your users' hands, it works — and when it doesn't, you find out first.

A Cypress automation suite is more than just tests — it's a structured safety net that covers every corner of your app, from page load to API errors to authentication flows. When built right, it's organized by feature, driven by stable selectors, and designed to stay green as your codebase grows. Every ticket I deliver comes with a suite that's already passing, so you ship with confidence knowing that if something breaks tomorrow, you'll be the first to know — not your users.

the testing stack

Every tool chosen with purpose — from feature to assertion.

Cypress

Cypress

Modern end-to-end testing with real-time browser execution and automatic waiting

JavaScript

JavaScript

Used across the full stack — frontend application, test specs, and automation layer

Jenkins

Jenkins

runs the load tests automatically as part of the CI/CD pipeline

Available for work

|

I'd love to hear about it — let's see if we're a good fit.

cahyaputraugira95@gmail.com