Bird
Raised Fist0
Cypresstesting~15 mins

App Actions pattern in Cypress - Deep Dive

Choose your learning style10 modes available
Overview - App Actions pattern
What is it?
The App Actions pattern is a way to organize test code by grouping user interactions and app behaviors into clear, reusable functions. These functions represent what a user does or what the app does, like clicking buttons or filling forms. This pattern helps keep tests clean, easy to read, and maintain. It separates the 'how' of interacting with the app from the 'what' the test wants to check.
Why it matters
Without the App Actions pattern, test code can become messy and hard to understand, especially as tests grow. Tests might repeat the same steps many times, making them fragile and slow to update. Using this pattern saves time, reduces errors, and makes tests more reliable, so developers can trust their tests and fix bugs faster.
Where it fits
Before learning this, you should know basic Cypress commands and how to write simple tests. After mastering App Actions, you can learn about Page Object Model, custom commands, and advanced test design patterns to organize even bigger test suites.
Mental Model
Core Idea
App Actions pattern means writing small, named functions that describe user or app behaviors to make tests clear and reusable.
Think of it like...
It's like having a recipe book where each recipe is a clear step, such as 'chop onions' or 'boil water', so cooking a meal is easy and repeatable without guessing what to do next.
┌───────────────┐
│ Test Scenario │
└──────┬────────┘
       │ calls
┌──────▼────────┐
│ App Actions   │
│ (clickLogin)  │
│ (fillForm)    │
└──────┬────────┘
       │ uses
┌──────▼────────┐
│ Cypress APIs  │
│ (cy.get,     │
│  cy.click)   │
└──────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Cypress Basic Commands
🤔
Concept: Learn the basic Cypress commands to interact with web elements.
Cypress uses commands like cy.get(selector) to find elements and cy.click() to click them. For example, cy.get('#submit').click() clicks a button with id 'submit'. These commands let you simulate user actions.
Result
You can write simple tests that open pages, find buttons, and click them.
Knowing how Cypress commands work is essential before grouping them into reusable actions.
2
FoundationWriting Simple Cypress Tests
🤔
Concept: Create basic tests that perform user steps directly in the test body.
A test might look like: cy.visit('/login'); cy.get('#username').type('user'); cy.get('#password').type('pass'); cy.get('#login').click(); cy.contains('Welcome').should('exist');
Result
Tests run and check if the app behaves as expected after user actions.
Directly writing steps works but can get repetitive and hard to maintain.
3
IntermediateIntroducing App Actions Functions
🤔Before reading on: do you think grouping commands into functions makes tests longer or shorter? Commit to your answer.
Concept: Group related Cypress commands into named functions that represent user actions.
Instead of repeating cy.get and cy.click everywhere, create functions like function login(username, password) { cy.get('#username').type(username); cy.get('#password').type(password); cy.get('#login').click(); } Then call login('user', 'pass') in tests.
Result
Tests become shorter and easier to read, focusing on what is done, not how.
Grouping commands into actions hides complexity and improves test clarity.
4
IntermediateUsing App Actions for Reusability
🤔Before reading on: do you think App Actions help reduce duplicated code or increase it? Commit to your answer.
Concept: Reuse App Actions functions across multiple tests to avoid repeating code.
If many tests need to log in, they all call the login() function. If the login process changes, update only login(), not every test.
Result
Tests are easier to maintain and less error-prone when app behavior changes.
Reusability through App Actions saves time and reduces bugs in test suites.
5
IntermediateSeparating Actions from Assertions
🤔Before reading on: should App Actions include checks or only perform steps? Commit to your answer.
Concept: Keep App Actions focused on performing steps; keep assertions separate in tests.
App Actions like login() do not check if login succeeded. Tests call login() then assert cy.contains('Welcome').should('exist'). This separation keeps actions reusable and tests clear.
Result
Tests clearly show what is done and what is checked, improving readability.
Separating actions and checks prevents mixing concerns and makes tests flexible.
6
AdvancedOrganizing App Actions in Modules
🤔Before reading on: do you think putting App Actions in separate files helps or complicates tests? Commit to your answer.
Concept: Place App Actions functions in separate files or folders to organize code better.
Create files like loginActions.js exporting login(), logout(), etc. Import them in tests. This keeps test files clean and actions reusable across projects.
Result
Test codebase is scalable and easier to navigate as it grows.
Modular organization supports team collaboration and long-term maintenance.
7
ExpertHandling Complex Flows with Parameterized Actions
🤔Before reading on: can App Actions handle different user roles or inputs with the same function? Commit to your answer.
Concept: Design App Actions to accept parameters for flexible, complex user flows.
For example, login(role) can fill different usernames/passwords based on role. This reduces function count and adapts to many scenarios.
Result
Tests can cover many cases with fewer, smarter action functions.
Parameterized actions increase power and reduce duplication in large test suites.
Under the Hood
App Actions are just JavaScript functions wrapping Cypress commands. Cypress commands queue asynchronously and run in order. When an App Action calls cy.get or cy.click, Cypress schedules these commands in its internal queue. The test runner executes them step-by-step, waiting for each to complete before moving on. This means App Actions do not run commands immediately but build a chain of commands that Cypress processes.
Why designed this way?
Cypress uses a command queue to handle asynchronous browser interactions smoothly. Wrapping commands in functions (App Actions) leverages this queue without blocking code. This design keeps tests readable and reliable, avoiding callback hell or complex async code. The pattern emerged to manage growing test suites by abstracting repeated steps into reusable units.
┌───────────────┐
│ Test Function │
└──────┬────────┘
       │ calls
┌──────▼────────┐
│ App Action Fn │
│ (wraps cmds) │
└──────┬────────┘
       │ queues
┌──────▼────────┐
│ Cypress Cmds  │
│ (cy.get,     │
│  cy.click)   │
└──────┬────────┘
       │ executed by
┌──────▼────────┐
│ Cypress Runner│
│ (async queue)│
└──────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think App Actions should include assertions inside them? Commit to yes or no.
Common Belief:App Actions should check if steps worked by including assertions inside the functions.
Tap to reveal reality
Reality:App Actions should only perform steps; assertions belong in tests to keep actions reusable and focused.
Why it matters:Mixing assertions in actions makes them less flexible and harder to reuse in different test scenarios.
Quick: Do you think writing App Actions makes tests slower? Commit to yes or no.
Common Belief:Adding App Actions adds overhead and slows down test execution.
Tap to reveal reality
Reality:App Actions are just wrappers around Cypress commands and do not slow tests; they improve maintainability without performance cost.
Why it matters:Avoiding App Actions due to false performance fears leads to messy, duplicated code.
Quick: Do you think App Actions replace the need to understand Cypress commands? Commit to yes or no.
Common Belief:Using App Actions means you don't need to know Cypress commands well.
Tap to reveal reality
Reality:Understanding Cypress commands is essential to write correct and effective App Actions.
Why it matters:Without Cypress knowledge, App Actions may hide bugs or misuse commands, causing flaky tests.
Quick: Do you think App Actions must be large functions covering many steps? Commit to yes or no.
Common Belief:App Actions should be big functions that do many things to reduce code size.
Tap to reveal reality
Reality:Smaller, focused App Actions are better for clarity, reuse, and debugging.
Why it matters:Large actions become hard to maintain and understand, defeating the pattern's purpose.
Expert Zone
1
App Actions can be combined with Cypress custom commands for even cleaner syntax and global reuse.
2
Parameterizing App Actions allows handling edge cases and different user roles without code duplication.
3
Keeping App Actions pure (no assertions, no test logic) enables easier mocking and stubbing in advanced test setups.
When NOT to use
Avoid App Actions for very simple tests or one-off scripts where abstraction adds unnecessary complexity. For UI elements that change frequently, consider using Page Object Model or component testing instead to better isolate UI structure.
Production Patterns
In real projects, teams organize App Actions by feature or page, often in separate files. They combine App Actions with fixtures for test data and use them in CI pipelines to ensure consistent, maintainable tests. Senior teams also integrate App Actions with reporting tools to trace user flows.
Connections
Page Object Model
Builds-on
App Actions focus on behaviors while Page Object Model organizes UI elements; combining both leads to highly maintainable test code.
Command Pattern (Software Design)
Same pattern
App Actions are an example of the Command Pattern, encapsulating requests as objects (functions) to decouple execution from invocation.
Instruction Manuals (Technical Writing)
Analogy in documentation
Just like clear instructions in manuals help users perform tasks step-by-step, App Actions provide clear, reusable steps for tests.
Common Pitfalls
#1Mixing assertions inside App Actions functions.
Wrong approach:function login() { cy.get('#username').type('user'); cy.get('#password').type('pass'); cy.get('#login').click(); cy.contains('Welcome').should('exist'); }
Correct approach:function login() { cy.get('#username').type('user'); cy.get('#password').type('pass'); cy.get('#login').click(); } // Assertions done separately in tests
Root cause:Confusing the role of actions (perform steps) with assertions (check results).
#2Duplicating Cypress commands in every test instead of using App Actions.
Wrong approach:cy.get('#username').type('user'); cy.get('#password').type('pass'); cy.get('#login').click(); // repeated in many tests
Correct approach:login('user', 'pass'); // Reuse the login action function
Root cause:Not recognizing the value of abstraction and reuse in test code.
#3Writing very large App Actions that do too many things.
Wrong approach:function fullUserSetup() { login(); fillProfile(); addPayment(); submitOrder(); }
Correct approach:Separate functions: login(), fillProfile(), addPayment(), submitOrder(); then combine in tests as needed.
Root cause:Trying to reduce code lines without considering readability and maintainability.
Key Takeaways
App Actions pattern organizes test steps into clear, reusable functions representing user or app behaviors.
Separating actions from assertions keeps tests flexible and easier to maintain.
Using App Actions reduces code duplication and improves test readability.
Parameterizing actions allows handling many scenarios with fewer functions.
Properly organizing App Actions supports scalable, reliable test suites in real projects.

Practice

(1/5)
1. What is the main benefit of using the App Actions pattern in Cypress tests?
easy
A. It automatically generates test data for each test run.
B. It speeds up test execution by running tests in parallel.
C. It replaces the need for assertions in tests.
D. It groups test steps into reusable methods to keep tests clean and maintainable.

Solution

  1. Step 1: Understand the purpose of App Actions pattern

    The pattern groups common test steps into reusable methods to avoid repetition.
  2. Step 2: Identify the benefit in test code

    This grouping makes tests cleaner and easier to maintain by reusing code.
  3. Final Answer:

    It groups test steps into reusable methods to keep tests clean and maintainable. -> Option D
  4. Quick Check:

    Reusable methods = cleaner tests [OK]
Hint: Remember: App Actions = reusable test steps [OK]
Common Mistakes:
  • Thinking App Actions generate test data automatically
  • Confusing App Actions with test assertions
  • Assuming App Actions speed up test execution
2. Which of the following is the correct way to define an App Action method for logging in a user in Cypress?
easy
A. const login = () => { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); }
B. cy.login = () => { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); }
C. function login() { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); }
D. login() { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); }

Solution

  1. Step 1: Identify valid JavaScript function syntax

    const login = () => { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); } uses a valid arrow function assigned to a constant, which is common in Cypress helper files.
  2. Step 2: Check other options for syntax errors

    function login() { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); } is a function declaration but not exported or assigned; cy.login = () => { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); } incorrectly assigns to cy object; login() { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); } is invalid syntax.
  3. Final Answer:

    const login = () => { cy.get('#user').type('admin'); cy.get('#pass').type('1234'); cy.get('#submit').click(); } -> Option A
  4. Quick Check:

    Arrow function assigned to const = correct syntax [OK]
Hint: Use arrow functions assigned to const for App Actions [OK]
Common Mistakes:
  • Using invalid function syntax without const or arrow
  • Attaching methods directly to cy object incorrectly
  • Omitting function keyword or arrow in definitions
3. Given this App Action method:
const addItem = (name) => { cy.get('#item-input').type(name); cy.get('#add-button').click(); }

What will be the result of this test code?
addItem('Book'); cy.get('#item-list').should('contain', 'Book');
medium
A. The test will fail because addItem does not return a value.
B. The test will pass if 'Book' appears in the item list after adding.
C. The test will throw a syntax error due to missing return statement.
D. The test will pass only if the input field has a placeholder 'Book'.

Solution

  1. Step 1: Understand what addItem does

    It types the given name into the input and clicks the add button, triggering UI update.
  2. Step 2: Analyze the assertion

    The test checks if '#item-list' contains the text 'Book', which should be true after adding.
  3. Final Answer:

    The test will pass if 'Book' appears in the item list after adding. -> Option B
  4. Quick Check:

    UI updates with added item = test passes [OK]
Hint: Add item then check list contains it [OK]
Common Mistakes:
  • Assuming missing return causes failure
  • Confusing input placeholder with typed value
  • Expecting addItem to return a value
4. This App Action method is intended to log in a user:
const login = (user, pass) => { cy.get('#username').type(user); cy.get('#password').type(pass); cy.get('#login-btn').click }

What is the error and how to fix it?
medium
A. Missing parentheses after click; fix by changing to cy.get('#login-btn').click().
B. Wrong selector for username; fix by using #user instead of #username.
C. Missing return statement; fix by adding return before cy commands.
D. Using arrow function incorrectly; fix by using function keyword.

Solution

  1. Step 1: Check method chaining syntax

    The click command is missing parentheses, so it is not called.
  2. Step 2: Fix the click command

    Add parentheses to call the function: click() to perform the click action.
  3. Final Answer:

    Missing parentheses after click; fix by changing to cy.get('#login-btn').click() -> Option A
  4. Quick Check:

    Method calls need parentheses [OK]
Hint: Always add () to call Cypress commands like click [OK]
Common Mistakes:
  • Forgetting parentheses on Cypress commands
  • Changing selectors without verifying correctness
  • Thinking return is needed for Cypress commands
5. You want to create an App Action to add multiple items from an array and verify all appear in the list. Which is the best approach?
hard
A. Use a single cy.get() call to type all items at once separated by commas.
B. Write separate tests for each item instead of looping in one method.
C. Create an addItems method that loops over the array, calls addItem for each, then asserts all items appear.
D. Add all items by typing them in one input, then click add once.

Solution

  1. Step 1: Understand the need for reusability and verification

    Looping over the array and calling addItem reuses existing code and ensures each item is added properly.
  2. Step 2: Verify all items appear after adding

    After adding, asserting all items appear confirms the UI updated correctly for each item.
  3. Final Answer:

    Create an addItems method that loops over the array, calls addItem for each, then asserts all items appear. -> Option C
  4. Quick Check:

    Loop + reuse + verify = best practice [OK]
Hint: Loop array, reuse addItem, then assert all present [OK]
Common Mistakes:
  • Typing all items at once without separate adds
  • Writing many separate tests instead of one reusable method
  • Assuming one click adds multiple items automatically
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