Bird
Raised Fist0
Cypresstesting~15 mins

Why custom commands reduce duplication in Cypress - Why It Works This Way

Choose your learning style10 modes available
Overview - Why custom commands reduce duplication
What is it?
Custom commands in Cypress are user-defined functions that extend Cypress's built-in commands. They allow testers to group repeated steps into a single reusable command. This helps write cleaner and shorter test code by avoiding repeating the same actions multiple times. Custom commands make tests easier to read and maintain.
Why it matters
Without custom commands, testers write the same sequences of steps over and over in many tests. This duplication wastes time and makes tests harder to update. If a change is needed, it must be done in many places, increasing errors and slowing down development. Custom commands solve this by centralizing repeated actions, saving effort and reducing bugs.
Where it fits
Before learning custom commands, you should understand basic Cypress commands and how to write simple tests. After mastering custom commands, you can learn about Cypress plugins, advanced test organization, and continuous integration setups. Custom commands fit in the middle of the Cypress learning path as a key technique for scalable test code.
Mental Model
Core Idea
Custom commands bundle repeated test steps into one reusable function to avoid writing the same code multiple times.
Think of it like...
It's like creating a shortcut on your computer desktop for a program you use often, so you don't have to navigate through folders every time.
┌─────────────────────────────┐
│ Test Step 1                 │
├─────────────────────────────┤
│ Test Step 2                 │
├─────────────────────────────┤
│ Test Step 3                 │
├─────────────────────────────┤
│ Repeated Steps (A, B, C)    │
│ ┌───────────────────────┐ │
│ │ Custom Command: ABC   │ │
│ └───────────────────────┘ │
└─────────────────────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Cypress Commands Basics
🤔
Concept: Learn what Cypress commands are and how they perform actions in tests.
Cypress commands are functions like cy.visit(), cy.get(), and cy.click() that perform actions or assertions in tests. Each command tells Cypress what to do, like opening a page or clicking a button. Commands are chained to create test flows.
Result
You can write simple tests that interact with web pages using Cypress commands.
Knowing how Cypress commands work is essential before creating custom commands that build on them.
2
FoundationRecognizing Duplication in Test Steps
🤔
Concept: Identify repeated sequences of commands across multiple tests.
When writing tests, you might find yourself repeating the same steps, like logging in or filling a form, in many places. This repetition is duplication and makes tests longer and harder to maintain.
Result
You can spot duplicated code that could be simplified.
Seeing duplication clearly motivates the need for custom commands to keep tests DRY (Don't Repeat Yourself).
3
IntermediateCreating Simple Custom Commands
🤔Before reading on: do you think custom commands can accept parameters to customize behavior? Commit to your answer.
Concept: Learn how to define a basic custom command in Cypress to reuse repeated steps.
In Cypress, you add custom commands in the cypress/support/commands.js file using Cypress.Commands.add('name', () => { ... }). For example, a login command can wrap the steps to enter username and password and submit the form.
Result
You can call cy.login() in tests instead of repeating login steps each time.
Understanding how to create custom commands unlocks the ability to reduce duplication and improve test clarity.
4
IntermediateUsing Parameters in Custom Commands
🤔Before reading on: do you think passing parameters to custom commands makes them more flexible or more complex? Commit to your answer.
Concept: Custom commands can accept arguments to handle different inputs or scenarios.
You can define custom commands with parameters, like Cypress.Commands.add('login', (user) => { ... }). This lets you reuse the command with different usernames or data, making tests more flexible.
Result
Tests can call cy.login('admin') or cy.login('guest') to test different users without duplicating code.
Knowing how to use parameters in custom commands allows writing versatile and reusable test helpers.
5
AdvancedOrganizing Custom Commands for Large Projects
🤔Before reading on: do you think putting all custom commands in one file is best for big projects? Commit to your answer.
Concept: Learn best practices for structuring custom commands in bigger test suites.
For large projects, organize custom commands into multiple files by feature or purpose, then import them in commands.js. This keeps code manageable and easier to find. Also, document commands clearly for team use.
Result
Your test codebase stays clean and scalable as it grows.
Proper organization of custom commands prevents chaos and supports team collaboration.
6
ExpertAvoiding Pitfalls with Custom Command Side Effects
🤔Before reading on: do you think custom commands always run instantly and independently? Commit to your answer.
Concept: Understand how Cypress command chaining and asynchronous behavior affect custom commands.
Cypress commands are asynchronous and queued. Custom commands must return Cypress chains properly to avoid timing issues. Also, avoid side effects like modifying global state inside commands, which can cause flaky tests.
Result
Your custom commands run reliably and integrate smoothly with Cypress's command queue.
Knowing Cypress's asynchronous model helps prevent subtle bugs and flaky tests caused by improper custom command design.
Under the Hood
Cypress commands, including custom ones, are queued and executed asynchronously in order. When you add a custom command, Cypress wraps your function to integrate it into this queue. This ensures commands run sequentially and wait for each other. Custom commands return Cypress chainables, allowing chaining and synchronization with other commands.
Why designed this way?
Cypress uses a command queue and asynchronous execution to simplify test writing and avoid callback hell. Custom commands fit this model to keep tests readable and reliable. This design avoids race conditions and timing issues common in browser automation.
┌───────────────┐
│ Test Script   │
│ calls cy.login│
└──────┬────────┘
       │
┌──────▼────────┐
│ Custom Command│
│ function runs │
└──────┬────────┘
       │
┌──────▼────────┐
│ Cypress Queue │
│ manages order │
└──────┬────────┘
       │
┌──────▼────────┐
│ Browser runs  │
│ commands one  │
│ by one        │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do custom commands automatically run immediately when called, or are they queued? Commit to your answer.
Common Belief:Custom commands run instantly as soon as they are called in the test.
Tap to reveal reality
Reality:Custom commands are queued and run asynchronously in order with other Cypress commands.
Why it matters:Believing commands run instantly can lead to writing tests that assume immediate effects, causing flaky or failing tests.
Quick: Do you think custom commands can only be used for UI interactions? Commit to your answer.
Common Belief:Custom commands are only for clicking buttons or typing text in the UI.
Tap to reveal reality
Reality:Custom commands can wrap any reusable logic, including API calls, data setup, or assertions.
Why it matters:Limiting custom commands to UI actions reduces their usefulness and leads to more duplicated code.
Quick: Do you think putting all custom commands in one file is always best? Commit to your answer.
Common Belief:All custom commands should be in a single file for simplicity.
Tap to reveal reality
Reality:For large projects, splitting commands into multiple files by feature improves maintainability.
Why it matters:Keeping all commands in one file can make code hard to navigate and maintain as the project grows.
Quick: Do you think custom commands can modify global variables safely? Commit to your answer.
Common Belief:Custom commands can freely change global variables or state without issues.
Tap to reveal reality
Reality:Modifying global state inside custom commands can cause unpredictable test behavior and flakiness.
Why it matters:Ignoring this leads to tests that pass or fail randomly, wasting debugging time.
Expert Zone
1
Custom commands must return Cypress chainables to maintain proper command chaining and synchronization.
2
Using custom commands to abstract complex logic can hide important test details, so balance reuse with test clarity.
3
Custom commands can be overwritten or extended, allowing flexible customization but requiring careful version control.
When NOT to use
Avoid custom commands for one-off or very simple steps that don't repeat. Instead, write inline commands for clarity. For complex test data setup, consider using Cypress tasks or external scripts instead of custom commands.
Production Patterns
In real projects, teams create libraries of custom commands for common workflows like login, navigation, or form filling. They organize commands by feature folders and document usage. Continuous integration runs tests using these commands to ensure consistency and reduce maintenance.
Connections
Functions and DRY Principle
Custom commands are a practical application of the DRY (Don't Repeat Yourself) principle using functions.
Understanding how functions reduce code duplication in programming helps grasp why custom commands improve test code.
Software Design Patterns - Abstraction
Custom commands abstract repeated details behind a simple interface, similar to abstraction in software design.
Knowing abstraction helps appreciate how custom commands hide complexity and improve test readability.
Manufacturing Assembly Lines
Like assembly lines standardize repeated steps for efficiency, custom commands standardize test steps for speed and reliability.
Seeing custom commands as standard work units clarifies their role in making testing efficient and consistent.
Common Pitfalls
#1Writing custom commands that do not return Cypress chainables, breaking command chaining.
Wrong approach:Cypress.Commands.add('login', () => { cy.get('#user').type('admin') cy.get('#pass').type('1234') cy.get('#submit').click() });
Correct approach:Cypress.Commands.add('login', () => { return cy.get('#user').type('admin') .get('#pass').type('1234') .get('#submit').click(); });
Root cause:Not returning the Cypress chain causes Cypress to lose track of command completion, leading to timing issues.
#2Duplicating login steps in every test instead of using a custom command.
Wrong approach:cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); // repeated in many tests
Correct approach:cy.login(); // custom command encapsulates login steps
Root cause:Not recognizing repeated code leads to duplication, making tests harder to maintain.
#3Modifying global variables inside custom commands causing flaky tests.
Wrong approach:let loggedIn = false; Cypress.Commands.add('login', () => { cy.get('#user').type('admin'); loggedIn = true; });
Correct approach:Cypress.Commands.add('login', () => { return cy.get('#user').type('admin'); });
Root cause:Changing global state inside commands breaks test isolation and causes unpredictable results.
Key Takeaways
Custom commands in Cypress help reduce repeated test code by bundling common steps into reusable functions.
They improve test readability, maintainability, and reduce errors caused by duplicated code.
Custom commands must return Cypress chainables to work correctly with Cypress's asynchronous command queue.
Using parameters in custom commands makes them flexible for different test scenarios.
Proper organization and avoiding side effects in custom commands are key for reliable, scalable test suites.

Practice

(1/5)
1. Why do custom commands in Cypress help reduce duplication in test code?
easy
A. They replace the need for assertions in tests.
B. They automatically find bugs in your code.
C. They let you write common actions once and reuse them in many tests.
D. They make tests run faster by skipping steps.

Solution

  1. Step 1: Understand what duplication means in tests

    Duplication means writing the same code multiple times, which makes tests harder to maintain.
  2. Step 2: Role of custom commands in Cypress

    Custom commands let you write a common action once, like logging in, and reuse it everywhere, reducing repeated code.
  3. Final Answer:

    They let you write common actions once and reuse them in many tests. -> Option C
  4. Quick Check:

    Reuse common actions = less duplication [OK]
Hint: Custom commands = write once, use many times [OK]
Common Mistakes:
  • Thinking custom commands speed up test execution
  • Believing custom commands remove the need for assertions
  • Assuming custom commands automatically fix bugs
2. Which of the following is the correct way to define a custom command in Cypress?
easy
A. cy.addCommand('login', () => { cy.visit('/login') })
B. cy.Commands.create('login', () => { cy.visit('/login') })
C. Cypress.createCommand('login', () => { cy.visit('/login') })
D. Cypress.Commands.add('login', () => { cy.visit('/login') })

Solution

  1. Step 1: Recall Cypress syntax for custom commands

    The correct method to add a custom command is Cypress.Commands.add.
  2. Step 2: Check each option's syntax

    Only Cypress.Commands.add('login', () => { cy.visit('/login') }) uses Cypress.Commands.add correctly with the command name and function.
  3. Final Answer:

    Cypress.Commands.add('login', () => { cy.visit('/login') }) -> Option D
  4. Quick Check:

    Correct method is Cypress.Commands.add [OK]
Hint: Custom commands use Cypress.Commands.add() [OK]
Common Mistakes:
  • Using cy.Commands instead of Cypress.Commands
  • Using createCommand or addCommand which don't exist
  • Mixing up method names and object names
3. Given this custom command definition:
 Cypress.Commands.add('login', (user) => { cy.get('#username').type(user.name); cy.get('#password').type(user.pass); cy.get('#submit').click(); }); 

What will happen when you run this test code?
 cy.login({name: 'alice', pass: '1234'}); cy.url().should('include', '/dashboard'); 
medium
A. The test types username and password, clicks submit, then checks URL includes '/dashboard'.
B. The test will fail because custom commands cannot take arguments.
C. The test will skip typing password and only type username.
D. The test will throw a syntax error due to missing return statement.

Solution

  1. Step 1: Understand the custom command behavior

    The 'login' command types the username and password from the passed object and clicks submit.
  2. Step 2: Analyze the test code execution

    Calling cy.login with user data runs the command, then the test asserts the URL includes '/dashboard'.
  3. Final Answer:

    The test types username and password, clicks submit, then checks URL includes '/dashboard'. -> Option A
  4. Quick Check:

    Custom command with args runs actions then assertion passes [OK]
Hint: Custom commands can take arguments and run steps [OK]
Common Mistakes:
  • Thinking custom commands can't accept parameters
  • Assuming missing return causes syntax error
  • Believing some steps are skipped automatically
4. You wrote this custom command:
 Cypress.Commands.add('clickButton', () => { cy.get('button.submit').click(); }); 

But your tests fail with "Cannot read property 'click' of undefined". What is the likely problem?
medium
A. You forgot to call cy.visit() before using the command.
B. The selector 'button.submit' does not match any element on the page.
C. Custom commands cannot use cy.get inside them.
D. The command name 'clickButton' is reserved and cannot be used.

Solution

  1. Step 1: Understand the error message

    "Cannot read property 'click' of undefined" means cy.get did not find the element, so it returned undefined.
  2. Step 2: Check possible causes

    If the selector does not match any element, cy.get returns nothing, causing the error when calling click.
  3. Final Answer:

    The selector 'button.submit' does not match any element on the page. -> Option B
  4. Quick Check:

    Selector missing element = click fails [OK]
Hint: Check if selector matches elements before clicking [OK]
Common Mistakes:
  • Assuming cy.get can't be used in custom commands
  • Forgetting to visit the page (may cause no elements)
  • Thinking command names are reserved keywords
5. You want to create a custom command fillForm that fills multiple fields on a page. Which approach best reduces duplication and improves test readability?
hard
A. Create fillForm to accept an object with field names and values, then fill each field inside the command.
B. Write separate commands for each field and call them one by one in tests.
C. Copy and paste the same cy.get().type() lines in every test needing the form filled.
D. Use cy.exec() to run external scripts that fill the form.

Solution

  1. Step 1: Consider duplication and readability

    Copy-pasting code (Copy and paste the same cy.get().type() lines in every test needing the form filled.) causes duplication and harder maintenance.
  2. Step 2: Evaluate options for custom commands

    Creating one command that accepts an object and fills all fields (Create fillForm to accept an object with field names and values, then fill each field inside the command.) centralizes logic and improves readability.
  3. Step 3: Analyze other options

    Separate commands (Write separate commands for each field and call them one by one in tests.) increase calls and complexity; cy.exec (Use cy.exec() to run external scripts that fill the form.) is not for UI actions.
  4. Final Answer:

    Create fillForm to accept an object with field names and values, then fill each field inside the command. -> Option A
  5. Quick Check:

    One command with params reduces duplication best [OK]
Hint: Use one paramized command for multiple fields [OK]
Common Mistakes:
  • Writing many small commands instead of one flexible one
  • Copy-pasting code in tests instead of reusing commands
  • Using cy.exec for UI interactions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard