Bird
Raised Fist0
Cypresstesting~15 mins

Dual commands in Cypress - Deep Dive

Choose your learning style10 modes available
Overview - Dual commands
What is it?
Dual commands in Cypress are a way to combine two actions into one command chain. They allow you to perform an action and then immediately assert or continue with another action seamlessly. This helps write cleaner and more readable test code by chaining commands that work together.
Why it matters
Without dual commands, test code can become repetitive and harder to read because you would write separate commands for actions and assertions. Dual commands solve this by making tests concise and easier to maintain, reducing errors and improving test clarity. This leads to faster debugging and more reliable tests.
Where it fits
Before learning dual commands, you should understand basic Cypress commands and how command chaining works. After mastering dual commands, you can explore custom commands and advanced Cypress features like retries and network stubbing to build robust test suites.
Mental Model
Core Idea
Dual commands let you perform an action and immediately follow it with another related action or assertion in one smooth chain.
Think of it like...
It's like using a remote control that not only turns on the TV but also sets the volume right after, all with one button press.
┌───────────────┐     ┌───────────────┐
│  Action Cmd   │────▶│  Follow-up    │
│ (e.g., click) │     │ (e.g., assert)│
└───────────────┘     └───────────────┘
         │                    │
         └─────────Chain──────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Cypress Command Chains
🤔
Concept: Learn how Cypress commands are chained to perform sequential actions.
In Cypress, commands like cy.get(), cy.click(), and cy.contains() are chained together. Each command waits for the previous one to finish before running. For example, cy.get('button').click() finds a button and clicks it.
Result
Commands run one after another, ensuring the test flows logically and waits for elements to be ready.
Understanding command chaining is essential because dual commands build on this idea to combine actions and assertions smoothly.
2
FoundationBasic Cypress Assertions
🤔
Concept: Learn how to check if elements meet conditions using assertions.
Cypress uses assertions like .should('be.visible') or .should('contain', 'Submit') to verify element states or content. These assertions can be chained after commands to check results.
Result
You can confirm that elements are visible, contain text, or have attributes as expected.
Knowing assertions lets you verify outcomes immediately after actions, which dual commands leverage to combine steps.
3
IntermediateCombining Actions and Assertions
🤔Before reading on: do you think you can chain an action and an assertion in one command line? Commit to yes or no.
Concept: Dual commands let you chain an action and an assertion directly, making tests concise.
For example, cy.get('button').click().should('be.disabled') clicks a button and then checks if it is disabled. This combines two steps into one chain.
Result
Tests become shorter and easier to read, with related steps grouped together.
Combining actions and assertions reduces repetition and improves test clarity by showing cause and effect in one place.
4
IntermediateUsing Dual Commands with Custom Commands
🤔Before reading on: can custom commands also use dual command chaining? Commit to yes or no.
Concept: You can create custom Cypress commands that perform dual commands internally for reuse.
For example, Cypress.Commands.add('clickAndCheck', (selector) => { return cy.get(selector).click().should('have.class', 'active') }); Then use cy.clickAndCheck('button') in tests.
Result
Custom commands encapsulate dual commands, making tests DRY (Don't Repeat Yourself) and easier to maintain.
Knowing that dual commands can be wrapped in custom commands helps build scalable test suites.
5
AdvancedHandling Timing with Dual Commands
🤔Before reading on: do you think dual commands automatically handle waiting for elements? Commit to yes or no.
Concept: Dual commands benefit from Cypress's automatic waiting, but understanding timing is key to avoid flaky tests.
Cypress waits for elements before actions and assertions. For example, cy.get('button').click().should('be.visible') waits for the button to appear before clicking and asserting. However, if the assertion depends on a delayed state change, you may need explicit waits or retries.
Result
Tests run reliably without manual waits most of the time, but timing issues can still cause failures if misunderstood.
Understanding Cypress's waiting behavior with dual commands prevents flaky tests and improves stability.
6
ExpertDual Commands Internals and Command Queue
🤔Before reading on: do you think dual commands run synchronously or are queued internally? Commit to your answer.
Concept: Dual commands are queued in Cypress's command queue and run asynchronously with automatic retries and error handling.
Cypress maintains a command queue where each command, including dual commands, is added. Commands run asynchronously but appear synchronous in code. Cypress retries assertions automatically until they pass or timeout. Dual commands benefit from this queue and retry logic, making tests robust.
Result
Tests using dual commands are more reliable due to automatic retries and asynchronous execution managed by Cypress.
Knowing the command queue and retry mechanism explains why dual commands work smoothly and how to debug timing issues.
Under the Hood
Cypress commands, including dual commands, are added to an internal command queue. Each command runs asynchronously but appears synchronous to the user. When a dual command is used, Cypress executes the first action, then immediately queues the assertion or follow-up command. Cypress automatically waits for elements to be ready and retries assertions until they pass or timeout. This mechanism ensures smooth chaining and reliable test execution.
Why designed this way?
Cypress was designed to simplify asynchronous testing by hiding callback hell and promises. The command queue and automatic retries make tests easier to write and maintain. Dual commands fit this design by allowing combined actions and assertions without breaking the chain or requiring manual waits. Alternatives like manual waits or callbacks were error-prone and less readable.
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│ Command Queue │────▶│ Execute Action│────▶│ Execute Assert│
│  (cy.get)    │     │  (click)      │     │ (should)      │
└───────────────┘     └───────────────┘     └───────────────┘
         │                    │                    │
         └─────────Asynchronous Execution─────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think dual commands run instantly and synchronously? Commit to yes or no.
Common Belief:Dual commands run instantly and synchronously like normal code lines.
Tap to reveal reality
Reality:Dual commands are queued and run asynchronously with automatic retries and waits.
Why it matters:Assuming synchronous execution leads to misunderstanding test failures and flaky tests due to timing issues.
Quick: Can you chain any two commands arbitrarily as dual commands? Commit to yes or no.
Common Belief:Any two Cypress commands can be chained as dual commands without restrictions.
Tap to reveal reality
Reality:Only commands that return subjects and support chaining can be combined; some commands do not support chaining or assertions.
Why it matters:Trying to chain incompatible commands causes test errors and confusion.
Quick: Do you think dual commands eliminate the need for explicit waits? Commit to yes or no.
Common Belief:Dual commands always handle timing perfectly, so explicit waits are never needed.
Tap to reveal reality
Reality:While Cypress waits automatically, some complex timing scenarios still require explicit waits or retries.
Why it matters:Ignoring timing nuances can cause flaky tests that pass or fail unpredictably.
Quick: Do you think custom commands cannot use dual commands internally? Commit to yes or no.
Common Belief:Custom commands are separate and cannot combine actions and assertions like dual commands.
Tap to reveal reality
Reality:Custom commands can and often do use dual commands internally to simplify test code.
Why it matters:Missing this limits test code reuse and clarity.
Expert Zone
1
Dual commands rely on Cypress's automatic retry mechanism, but understanding when retries happen helps optimize test speed and reliability.
2
Some Cypress commands return 'void' and cannot be chained with assertions, so knowing which commands support dual chaining is crucial.
3
Custom dual commands can accept parameters and return Cypress chains, enabling flexible and reusable test building blocks.
When NOT to use
Dual commands are not suitable when you need to perform unrelated actions or when commands do not return chainable subjects. In such cases, separate commands or explicit waits should be used. Also, for complex asynchronous flows involving network stubbing or multiple page transitions, breaking commands into clear steps improves readability.
Production Patterns
In real-world tests, dual commands are used to combine user interactions with immediate assertions, like clicking a button and verifying its disabled state. Teams often wrap dual commands into custom commands for common UI patterns, improving test maintainability. Advanced usage includes chaining dual commands with network request assertions to verify backend responses after UI actions.
Connections
Promise chaining in JavaScript
Dual commands in Cypress build on the idea of chaining asynchronous operations like promises.
Understanding promise chaining helps grasp how Cypress queues commands and manages asynchronous test steps smoothly.
Assembly line workflow
Dual commands resemble an assembly line where one step immediately leads to the next related step.
Seeing dual commands as a workflow helps understand how combining actions and checks improves efficiency and clarity.
Human multitasking
Dual commands mimic how humans perform an action and immediately check the result without pausing.
This connection shows how dual commands make automated tests feel more natural and intuitive.
Common Pitfalls
#1Chaining commands that do not return chainable subjects causes errors.
Wrong approach:cy.visit('/page').click().should('be.visible')
Correct approach:cy.visit('/page'); cy.get('button').click().should('be.visible')
Root cause:cy.visit() does not return a chainable subject for click(), so chaining click() directly fails.
#2Assuming dual commands remove the need for waits in all cases.
Wrong approach:cy.get('button').click().should('have.class', 'active') // fails if class changes late
Correct approach:cy.get('button').click(); cy.wait(500); cy.get('button').should('have.class', 'active')
Root cause:Automatic waits do not cover delayed UI updates; explicit waits or retries are needed.
#3Writing custom commands without returning the Cypress chain breaks chaining.
Wrong approach:Cypress.Commands.add('clickAndCheck', (selector) => { cy.get(selector).click().should('be.visible') });
Correct approach:Cypress.Commands.add('clickAndCheck', (selector) => { return cy.get(selector).click().should('be.visible'); });
Root cause:Not returning the chain breaks Cypress's command queue and chaining.
Key Takeaways
Dual commands in Cypress combine actions and assertions into one chain for cleaner, more readable tests.
They rely on Cypress's command queue and automatic retry mechanism to run asynchronously and reliably.
Not all commands support chaining; understanding which do prevents errors and flaky tests.
Custom commands can use dual commands internally to create reusable test building blocks.
Knowing when dual commands fit and when to separate steps improves test clarity and stability.

Practice

(1/5)
1. What is the main benefit of using dual commands in Cypress tests?
easy
A. They enable writing tests without any selectors.
B. They allow running tests in parallel on multiple browsers.
C. They combine finding and acting on elements in one step.
D. They automatically generate test reports after each test.

Solution

  1. Step 1: Understand dual commands concept

    Dual commands in Cypress combine locating an element and performing an action on it in a single step.
  2. Step 2: Compare options with concept

    Only They combine finding and acting on elements in one step. correctly describes this benefit. Other options describe unrelated features.
  3. Final Answer:

    They combine finding and acting on elements in one step. -> Option C
  4. Quick Check:

    Dual commands = find + act [OK]
Hint: Dual commands = find element + act in one step [OK]
Common Mistakes:
  • Confusing dual commands with parallel test execution
  • Thinking dual commands generate reports automatically
  • Believing dual commands remove need for selectors
2. Which of the following is the correct syntax to click a button with id submitBtn using a dual command in Cypress?
easy
A. cy.click('#submitBtn')
B. cy.get('#submitBtn').click()
C. cy.find('#submitBtn').click()
D. cy.click().get('#submitBtn')

Solution

  1. Step 1: Identify correct dual command syntax

    In Cypress, cy.get(selector).click() finds the element and clicks it in one chain.
  2. Step 2: Check each option

    cy.get('#submitBtn').click() uses correct chaining. cy.click('#submitBtn') and D have invalid command order. cy.find('#submitBtn').click() uses find which is not a root command.
  3. Final Answer:

    cy.get('#submitBtn').click() -> Option B
  4. Quick Check:

    Use cy.get(selector).click() [OK]
Hint: Use cy.get(selector).click() to find and click [OK]
Common Mistakes:
  • Using cy.click(selector) which is invalid
  • Using cy.find() as root command instead of cy.get()
  • Reversing command order like cy.click().get()
3. What will be the result of this Cypress code snippet?
cy.get('.input-field').type('Hello').should('have.value', 'Hello')
medium
A. The test will fail because type does not return the element.
B. The test will fail because should cannot be chained after type.
C. The test will throw a syntax error due to missing semicolons.
D. The test will pass because type types text and should asserts the value.

Solution

  1. Step 1: Understand chaining of dual commands

    In Cypress, type() types text into the element and returns the element for further chaining.
  2. Step 2: Analyze the assertion

    The should('have.value', 'Hello') checks if the input's value is 'Hello', which is correct after typing.
  3. Final Answer:

    The test will pass because type types text and should asserts the value. -> Option D
  4. Quick Check:

    type() returns element, so should() works [OK]
Hint: type() returns element; can chain should() for assertions [OK]
Common Mistakes:
  • Thinking type() breaks the chain
  • Believing should() can't follow type()
  • Confusing syntax errors with missing semicolons
4. Identify the error in this Cypress code using dual commands:
cy.get('.checkbox').check('#checkbox1')
medium
A. The check command should not have a selector argument.
B. The get command is missing a closing parenthesis.
C. The selector '.checkbox' is invalid for check command.
D. The check command must be chained after click.

Solution

  1. Step 1: Review Cypress check command usage

    The check() command acts on the element found by get() and does not take any selector argument.
  2. Step 2: Analyze the code snippet

    Here, check('#checkbox1') incorrectly passes a selector, causing an error.
  3. Final Answer:

    The check command should not have a selector argument. -> Option A
  4. Quick Check:

    check() acts on found element, no selector inside [OK]
Hint: check() acts on found element; no selector inside [OK]
Common Mistakes:
  • Passing selector inside check()
  • Missing parentheses in get()
  • Thinking check() must follow click()
5. You want to fill a form with multiple fields using dual commands efficiently. Which approach is best to type 'John' into input with id firstName and 'Doe' into input with id lastName in Cypress?
hard
A. cy.get('#firstName').type('John').get('#lastName').type('Doe');
B. cy.get('#firstName').type('John'); cy.get('#lastName').type('Doe');
C. cy.get('#firstName, #lastName').type('John', 'Doe');
D. cy.type('#firstName', 'John').type('#lastName', 'Doe');

Solution

  1. Step 1: Understand chaining dual commands for multiple fields

    Using chaining, you can find first element, type, then find second element and type again in one chain.
  2. Step 2: Evaluate each option

    cy.get('#firstName').type('John'); cy.get('#lastName').type('Doe'); works but uses two separate commands, not chaining. cy.get('#firstName, #lastName').type('John', 'Doe'); tries to type into two selectors at once, which is invalid. cy.get('#firstName').type('John').get('#lastName').type('Doe'); chains get and type commands correctly. cy.type('#firstName', 'John').type('#lastName', 'Doe'); uses invalid cy.type syntax.
  3. Final Answer:

    cy.get('#firstName').type('John').get('#lastName').type('Doe'); -> Option A
  4. Quick Check:

    Chain get().type().get().type() for multiple fields [OK]
Hint: Chain get().type() for each field to fill multiple inputs [OK]
Common Mistakes:
  • Trying to type into multiple selectors at once
  • Using invalid cy.type() command
  • Not chaining commands for efficiency
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