Test Automation

Your Cypress Framework Is Missing This One Thing — The Power of Custom Commands

Your Cypress framework is missing custom commands — the one thing that eliminates repetition and makes test suites maintainable. Real code patterns.

4 min read
Your Cypress Framework Is Missing This One Thing — The Power of Custom Commands
Advertisement
What You Will Learn
Why Your Tests Feel Messy
The Cypress Way — Cypress.Commands.add()
Why Custom Commands Matter
Advanced Example — API + UI Hybrid Command

If your Cypress tests feel repetitive, hard to maintain, and cluttered with selectors — you’re not alone.
Most automation engineers eventually realize: their test suite isn’t the problem — their design is.

Let’s talk about the secret ingredient that turns messy automation into beautiful engineering:
👉 Custom Commands.

Why Your Tests Feel Messy

You’ve probably seen code like this:

it('logs in the user', () => {
cy.get('#email').type('user@example.com');
cy.get('#password').type('123456');
cy.get('button[type=submit]').click();
cy.url().should('include', '/dashboard');
});

Now repeat that login step across 20 tests…
Suddenly, you’ve got:

  • Duplicated logic everywhere 😩
  • Broken selectors after small UI changes 💔
  • Painful maintenance cycles 🧯

That’s not scalable testing — it’s copy-paste chaos.

The Cypress Way — Cypress.Commands.add()

Cypress gives you a built-in mechanism to extend itself using custom commands.
It’s like giving your framework a brain.

Example 👇

// cypress/support/commands.js

Cypress.Commands.add('login', (email, password) => {
cy.get('#email').type(email);
cy.get('#password').type(password);
cy.get('button[type=submit]').click();
cy.url().should('include', '/dashboard');
});

Now your test becomes:

it('logs in successfully', () => {
cy.login('user@example.com', '123456');
});

Clean. Reusable. Readable. ✅

Why Custom Commands Matter

Here’s what happens when you start using them seriously:

Without Commands 😩 With Commands 😎 400+ lines of repetitive steps 100 lines of reusable logic UI selectors scattered Centralized and maintainable New QAs struggle to read tests Tests read like user stories High flakiness Consistent interactions

Your tests stop feeling like code — they start reading like documentation.

Advanced Example — API + UI Hybrid Command

Want to skip the UI login step (for speed)? Combine Cypress + API auth 💪

// cypress/support/commands.js

Cypress.Commands.add('apiLogin', (userType = 'user') => {
cy.request('POST', '/api/login', {
email: `${@example.com">userType}@example.com`,
password: '123456',
}).then((response) => {
window.localStorage.setItem('authToken', response.body.token);
});
});

Usage:

beforeEach(() => {
cy.apiLogin('admin');
cy.visit('/dashboard');
});

Now, your tests start flying. No login UI, no waiting, no flakiness.

The Architecture Mindset

Don’t treat commands as one-off helpers.
Design them like a library — a toolkit that defines how your team interacts with the app.

Structure it like this:

cypress/
├── support/
│ ├── commands/
│ │ ├── auth.js
│ │ ├── ui.js
│ │ └── api.js
│ └── index.js

Then, import them globally in support/index.js:

import './commands/auth';
import './commands/ui';
import './commands/api';

Common Use Cases for Custom Commands

CategoryExamplePurpose
Authenticationcy.login(), cy.apiLogin()Simplify repetitive flows
UI Interactionscy.selectDropdown(), cy.fillForm()Abstract complex selectors
Assertionscy.verifyToast(‘Success!’)Consistent Validations
API Helperscy.createUser(), cy.deleteOrder()Data Setup / Teardown

Pro Tips from Senior SDETs

🔥 1. Keep them atomic.
Each command should do one thing well. Don’t make a god-command that logs in, navigates, and validates.

🧩 2. Add intelligent waits inside.
Instead of using cy.wait(3000) in tests, add smart waits (like cy.intercept + cy.wait('@api')) inside commands.

💬 3. Add custom logs for visibility.

Cypress.Commands.add('login', (email, password) => {
Cypress.log({ name: 'login', message: `Logging in as ${email}` });
// your steps...
});

🧠 4. Test your commands like mini-APIs.
Treat each one as a small, reliable unit.

The Payoff

When you scale your automation framework with well-designed custom commands, you unlock:

  • ⚡️ 10x faster authoring speed
  • 💪 Minimal maintenance on selector changes
  • 🧠 Easier onboarding for new testers
  • 🧩 Cleaner, modular architecture

“Great automation isn’t about how many tests you write — it’s about how readable, reusable, and reliable those tests are.”

💬 Final Thoughts

Your Cypress suite shouldn’t just “run tests.”
It should express business intent through elegant code.

If your tests look like a manual script — it’s time to evolve your framework.
Start thinking like an architect, not just a tester.

Build your own Cypress DSL (Domain-Specific Language) with custom commands — and watch your automation transform from fragile scripts to true engineering assets. 🧠💥

Advertisement
Found this helpful? Clap to let Shahnawaz know — you can clap up to 50 times.