How to use Cypress App Actions?

Learn what Cypress App Actions is, its benefits, when to use it, and how to use it to automate Cypress tests effectively.

Get Started free
Home Guide How to use Cypress App Actions?

How to use Cypress App Actions?

Cypress App Actions make it easy to automate and simulate real user behaviors, such as clicking buttons, filling out forms, and navigating through pages.

Overview

What are Cypress App Actions

App Actions in Cypress are commands or interactions implemented by directly dispatching actions using the app’s internal logic and bypassing UI elements.

Cypress App Actions Benefits

  • Faster compared to UI-based actions
  • Increases Stability
  • Reduced dependency on DOM elements

This article explores what Cypress App Actions are, how to use them, and why they are important for ensuring your app works smoothly for users.

What are App Actions in Cypress?

App Actions in Cypress are commands or interactions implemented by directly dispatching the action within the app’s internal logic instead of interacting through the UI elements.

Advantages of Cypress App actions

  • Faster compared to UI-based actions or Page object model
  • More stable, as the tests are directly interacting with internal logic tests are more stable
  • Reduced dependency of DOM elements. The DOM elements usually cause flaky tests or false positives whenever there are changes at the DOM level.

Limitation of Cypress App actions

  • Requires understanding of internal code level knowledge
  • Doesn’t simulate end-user interaction, and may fail to catch the UI level defects
  • Calling too many actions too fast may result in unreliable results as the application may not be prepared to handle faster(unrealistic) interactions.

Automating Cypress Tests using App Actions

Let’s understand how to automate Cypress tests using the App actions pattern. As mentioned earlier the app actions have a lot of advantages however it has a limitation as well, the app action is a new concept that Cypress introduced to end-to-end testing.

For the demo purpose, the MVC Todo Github repository code will be used.

The MVC Todo app is a simple app, it adds the tasks to the to-do list, and as soon as you add the tasks it increases the to-do task counter.

Before moving to App actions, let’s consider the Cypress automation code in a Generic way without using App actions which help to understand the app action better.

Automate the simple scenario

  1. Navigate to Todo App
  2. Add the Todo task
  3. Verify the todo count

Example code, without using App actions

describe('TodoMVC without App Actions', function () {
beforeEach(function () {
cy.visit('/')
})

it('should add task and verify the count',() => {
cy.get('input[class="new-todo"]').type("Explore Browserstack")
cy.get('input[class="new-todo"]').type('{Enter}')
cy.get('.todo-count').contains('1 item left')
})
})

In the above code, you are navigating to the application using cy.visit()

Using the cy.get() you are getting the locator for todo text box

The .type() command is used to type the Todo task and then use {Enter} to hit the [Enter] key.

The cy.get().contains() is used to validate the count after adding the task.

Remember all these actions are done, exactly how the end user does. You are just simulating all these actions using the Cypress tool.

Once you execute the above test you can see the output below.

How to use Cypress App Actions

Example of Cypress App actions

Cypress allows interacting with the application under the test directly using the application logic. This makes the application testing faster and more stable as it bypasses the UI element interaction.

Rewrite the above Cypress test to use the App actions

Example of Cypress App actions

describe('TodoMVC with App Actions', function () {
beforeEach(function () {
cy.visit('/')
})

it('should add task and verify the count',() => {
cy.window().its('model').should('be.an','object').invoke('addTodo','Explore Browserstack')
cy.get('.todo-count').contains('1 item left')
})

The above code does exactly what the previous test is doing, it adds the new task and verifies the task counter. But it does everything by calling the internal logic. Let’s understand that.

The cy.window().its(‘model’) gets the underlying application object, once it gets the application object, you can call any underlying exposed logic or function.

Cypress runs inside the browser and it can directly access the internals of your application. If you carefully observe the application code, The application has been exposed using the below code.

 if (window.Cypress) {
window.model = model
}

The .invoke(‘addTodo’) is used for calling the addTodo() function of the application which is responsible for adding the task. You can call it directly using Cypress. In the end, it is ensured whether the counter value has increased.

Execute the code view results

Execute the code view results

  • As you can see, the test result remains the same, only our approach is different.
  • The first one used a UI-based testing approach, and the last one used App actions.
  • You can notice the major difference in execution time: the App action-based test took 737ms to complete and the Non-app action-based test took 1 sec to complete.

This might not seem like a bigger difference, as there is only a simple test scenario with one use case; if you consider having hundreds of test cases with a complicated scenario, it can impact the test execution time.

When to Use Cypress App Actions: Use Cases

Cypress App Actions are designed to automate real user interactions within your application to ensure that it behaves as expected during actual usage.

Below are some common use cases of Cypress App Actions:

1. Form Interactions

Use Case: Automating the testing of form elements such as user input, validation messages, and form submission behavior.

Example:

cy.get('input[name="username"]').type('testuser')

cy.get('input[name="password"]').type('securepassword')

cy.get('button[type="submit"]').click()

cy.url().should('include', '/dashboard')

2. Button Clicks

Use Case: Simulating button clicks in order to test functionality like submitting forms, opening modals, or triggering events.

Example:

cy.get('button#openModal').click()

cy.get('.modal').should('be.visible')

3. Navigation and Page Interactions

Use Case: Test the navigation between different pages and check for correct content display.

Example:

cy.get('a[href="/https/www.browserstack.com/about"]').click()

cy.url().should('include', '/about')

cy.get('h1').should('contain', 'About Us')

4. Dropdown and Select Box Interactions

Use Case: Automating the selection of values from dropdowns and select boxes.

Example:

cy.get('select#country').select('USA')

cy.get('input[name="city"]').should('have.value', 'New York')

5. File Uploads

Use Case: Testing file upload functionality by simulating user file selection.

Note: To use the attachFile command, the cypress-file-upload plugin needs to be installed.

Example:

cy.get('input[type="file"]').attachFile('example.txt')

cy.get('.file-name').should('contain', 'example.txt')

6. Hover and Mouse Events

Use Case: Simulating hover actions or mouse events to test UI changes or pop-ups.

Example:

cy.get('.menu-item').trigger('mouseover')

cy.get('.submenu').should('be.visible')

7. Checkbox and Radio Button Interactions

Use Case: Testing checkbox and radio button selections to verify that the correct input is captured.

Example:

cy.get('input[type="checkbox"]').check()

cy.get('input[type="radio"]').check('option1')

8. Scrolling and Lazy Load Testing

Use Case: Verifying content loading when scrolling or using infinite scroll.

Example:

cy.scrollTo('bottom')

cy.get('.new-content').should('be.visible')

9. Modal and Popup Interactions

Use Case: Automating interactions with modals, popups, or alert dialogs.

Example:

cy.get('button#openAlert').click()

cy.on('window:alert', (text) => {

  expect(text).to.contains('Are you sure?')

})

10. Keyboard Shortcuts

Use Case: Testing keyboard shortcuts and actions that depend on keyboard events.

Example:

cy.get('body').type('{esc}')  // Close modal using ESC key

cy.get('.modal').should('not.be.visible')

11. API Request and Response Testing

Use Case: Cypress allows the testing of API calls directly in the application. Use cy.intercept() to spy on or stub network requests during testing.

Example:

cy.intercept('GET', '/api/user').as('getUser')

cy.get('button#loadUser').click()

cy.wait('@getUser').its('response.statusCode').should('eq', 200)

12. Cross-Browser Testing

Use Case: Cypress now supports cross-browser testing (Chrome, Firefox, and Edge), which allows testing on different browsers without needing to set up complex configurations.

Example:

# Run tests in Firefox

npx cypress run --browser firefox

13. Visual Regression Testing

Use Case: You can integrate visual testing with Cypress using plugins like cypress-image-snapshot to capture screenshots and compare them to previous baselines.

Example:

cy.get('.button').toMatchImageSnapshot()

This ensures that your UI elements and layouts don’t unexpectedly change, leading to better visual consistency across releases.

What is Cypress POM?

Cypress Page Object Model (POM) is a design pattern used in automated testing to create reusable and maintainable code when testing web applications with Cypress. The idea behind POM is to separate the test logic from the user interface (UI) elements in a web application, making the test code more modular, organized, and easier to maintain.

Advantages of Cypress POM

Here are some of the benefits of using Cypress POM:

  • Reusability: Page objects can be reused across multiple tests, reducing code duplication.
  • Maintainability: Changes in the UI or application structure only need to be updated in the page object, rather than in every individual test case.
  • Readability: The test scripts become easier to read and understand since they focus on what the test is doing, not how it’s interacting with the UI.
  • Modularity: Each page object represents a specific part of the application, making it easy to maintain and scale tests for large applications.

Limitations of POM in Cypress

Here are the drawbacks of using Cypress Page Object Model (POM) in a normal font:

  • Difficulty with Dynamic Pages: Cypress struggles with dynamic content such as AJAX or JavaScript-heavy elements, making it harder to maintain reliability in POM when interacting with dynamically loaded elements.
  • Limited Support for Shadow DOM: Cypress has limited support for interacting with elements within the Shadow DOM, a common scenario with modern web apps using custom web components.
  • Complexity in Large Applications:As the application grows, managing a large number of page objects can become cumbersome, resulting in maintenance overhead and longer test scripts that are harder to manage and debug.
  • No Native Support for Multiple Windows/Tabs: Cypress operates in a single browser window and cannot handle tests involving multiple tabs or windows, limiting the use of POM for scenarios involving cross-window interactions.
  • Performance Overhead with Heavy DOM Manipulation: Excessive manipulation of the DOM and chaining many actions can introduce performance issues, leading to slower tests and potentially unstable results.
  • Challenges with Global State Management: Managing global state across tests can become error-prone, especially in POM, since Cypress tests are stateful by default, which can lead to state conflicts across tests.
  • Not Ideal for Multi-Page Flow Testing: Testing multi-page flows is challenging in Cypress with POM, especially when the app requires interaction across multiple pages, as Cypress is primarily suited for single-page testing.

Cypress App Actions vs. Page Object Model (POM)

Both Cypress App Actions and the Page Object Model (POM) are strategies used in test automation, but they serve different purposes and have different structures. Here’s a breakdown of both approaches with examples and a final verdict on which to use.

Cypress App Actions

Cypress App Actions refer to the built-in Cypress commands that simulate real user interactions with your application during testing. These actions are focused on how the application behaves when interacting with elements (like buttons, forms, links, etc.) and include actions like clicking, typing, selecting options etc. The objective is to run end-to-end testing that replicates user behavior to ensure that the application functions as expected.

Key Characteristics

  • Tests are written to simulate real user flows.
  • Actions are directly tied to the UI elements being tested.
  • The tests are often more concise and focused on end-to-end scenarios.
  • These tests mimic real user behavior (e.g., clicking buttons, typing in forms, navigating between pages).

Example:

describe('User login flow', () => {

  it('should allow users to log in', () => {

    cy.visit('/login') // Visit the login page

    cy.get('input[name="username"]').type('myusername') // Type username

    cy.get('input[name="password"]').type('mypassword') // Type password

    cy.get('button[type="submit"]').click() // Click the submit button

    cy.url().should('include', '/dashboard') // Check if redirected to dashboard

  })

})

In this example, Cypress actions like .type() and .click() directly interact with UI elements to simulate a user logging in. This approach is simple and focuses on testing the user flow.

Page Object Model (POM)

The Page Object Model (POM) is a design pattern that suggests creating a separate class or file for each page or component in the application. This model focuses on creating reusable functions for interacting with page elements and keeping the test scripts clean and easy to maintain. By abstracting the interaction logic into page objects, tests become more readable and maintainable.

Key Characteristics

  • A separate file or class represents each page or component in the application.
  • It contains methods to interact with page elements, encapsulating the logic.
  • It promotes reusability, especially when the same interactions are needed across multiple tests.
  • It helps in reducing redundancy by centralizing the interaction code.

Example:

Page Object (loginPage.js):

class LoginPage {

  visit() {

    cy.visit('/login') // Navigate to login page

  }


  fillUsername(username) {

    cy.get('input[name="username"]').type(username) // Fill in the username

  }


  fillPassword(password) {

    cy.get('input[name="password"]').type(password) // Fill in the password

  }


  submit() {

    cy.get('button[type="submit"]').click() // Click the submit button

  }


  checkDashboardRedirect() {

    cy.url().should('include', '/dashboard') // Verify redirection to dashboard

  }

}


export default LoginPage

Test Case (loginSpec.js):

import LoginPage from './loginPage'



describe('User login flow', () => {

  it('should allow users to log in', () => {

    const loginPage = new LoginPage() // Create instance of LoginPage object



    loginPage.visit() // Navigate to login page

    loginPage.fillUsername('myusername') // Fill in username

    loginPage.fillPassword('mypassword') // Fill in password

    loginPage.submit() // Submit login form

    loginPage.checkDashboardRedirect() // Verify redirection to dashboard

  })

})

Final Verdict: In this example, the test case imports the LoginPage object, which contains all the methods to interact with the login page. This approach keeps the test script clean, and organized, and the interactions reusable across different test cases.

  • Cypress App Actions are perfect for quick, user-flow-focused tests with minimal setup.
  • Page Object Model is better suited for larger, more complex applications where reusable, maintainable test code is necessary.

Both strategies are valid, and you may choose the best one depending on your project’s requirements. For smaller projects, Cypress App Actions are quick and simple, while POM shines in larger, long-term projects focusing on maintainability and scalability.

Conclusion

Cypress App actions provide stable and faster tests and is worth considering. However, the major drawback is one needs to know the application’s internal logic. The QA team typically performs the end-to-end test automation; they don’t involve development.

  • Understanding internal logic may be difficult. Adding to this, App actions do not perform any actions using the UI, this bypasses the user actions, and any error which may occur due to user actions is not caught.
  • The end-to-end tests are written considering both the functionality and user interface, but the App action mostly concentrates on the functionality.

UI Testing is one of the critical parts of application testing where functionality alone cannot be considered for testing sign-off. While testing, the QA team needs to ensure the user interface and functionality are working seamlessly across the supported platforms and browsers to provide a smoother experience to the user.

Note – it is important to test on a real device cloud for more accuracy. Cypress tests can leverage the cloud infrastructure provided by BrowserStack Automate for higher efficiency.

Run Cypress Tests on Real Devices

Frequently Asked Questions

1. How to implement POM in Cypress?

Implementing the Page Object Model (POM) in Cypress is straightforward and involves creating separate JavaScript files (or classes) for each page or component in your application. Each file contains reusable methods for interacting with elements on that page, which helps avoid redundancy in your tests.

Steps to implement POM in Cypress:

1. Create a Page Object file:

Define methods for common actions or verifications on that page. For example, a login page could have methods for entering the username, password, and submitting the form.

2. Use the Page Object in your test:

In your test files, import the Page Object and call the methods to perform the actions.

Example:

class LoginPage {

  visit() {

    cy.visit('/login')

  }



  fillUsername(username) {

    cy.get('input[name="username"]').type(username)

  }



  fillPassword(password) {

    cy.get('input[name="password"]').type(password)

  }



  submit() {

    cy.get('button[type="submit"]').click()

  }



  checkDashboardRedirect() {

    cy.url().should('include', '/dashboard')

  }

}



export default LoginPage

This structure promotes code reusability, making your tests easier to maintain and scale.

2. Is Cypress object-oriented?

Cypress itself is not strictly object-oriented, but it does provide object-like structures through its commands and chaining syntax. Cypress commands, such as cy.get(), return objects (actually jQuery-like objects) that can be chained for further actions, mimicking some object-oriented principles. However, Cypress does not use classical object-oriented paradigms like inheritance or encapsulation in the way languages like Java or Python do.

3. What are app actions in Cypress?

App actions in Cypress refer to the interactions that can be performed on your web application during testing. These actions simulate user behavior such as clicking buttons, typing text, selecting options, and navigating between pages.

Cypress app actions are used to ensure that the application functions as expected when interacted with by a user.

4. How do I perform Cypress actions on elements in my app?

To perform Cypress actions, you can use commands like cy.get(), cy.click(), cy.type(), and cy.select(). For example, to simulate a user typing into an input field, you would use:

javascript

cy.get('input[name="username"]').type('myUser');

This command simulates a user typing “myUser” into an input field.

5. What are some common Cypress app actions for form testing?

Some common Cypress app actions for testing forms include:

  • cy.get().type() to type text into form fields.
  • cy.get().click() to click on checkboxes or submit buttons.
  • cy.get().should() to validate if the form is correctly filled out or if an error message appears.

These actions help ensure that forms function correctly in your application.

6. Can I customize app actions in Cypress for different user scenarios?

Yes, you can customize Cypress app actions to simulate various user scenarios. You can chain multiple actions together, add delays, or interact with different elements based on user roles. This flexibility allows you to test complex user workflows and ensure your application behaves as expected across different situations.

Useful Resources for Cypress

Understanding Cypress

Use Cases

Tool Comparisons

Tags
Automation Testing Visual Testing

Get answers on our Discord Community

Join our Discord community to connect with others! Get your questions answered and stay informed.

Join Discord Community
Discord