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.
Read More: Cypress Installation for Test Automation
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
- Navigate to Todo App
- Add the Todo task
- 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.
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
- 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')
Read More: How to Fill and Submit Forms in Cypress
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="/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')
Read More: What is Lazy loading?
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)
Read More: What Is API Automation Testing?
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.
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.
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.
Useful Resources for Cypress
Understanding Cypress
- Cross Browser Testing with Cypress : Tutorial
- Run Cypress tests in parallel without Dashboard: Tutorial
- Handling Test Failures in Cypress A Comprehensive Guide
- Cypress Test Runner: Tutorial
- Handling Touch and Mouse events using Cypress
- Cypress Automation Tutorial
- CSS Selectors in Cypress
- Performance Testing with Cypress: A detailed Guide
- Cypress Best Practices for Test Automation
- Test React Native Apps with Cypress
- Cypress E2E Angular Testing: Advanced Tutorial
- Cypress Locators : How to find HTML elements
- Maximizing Web Security with Cypress: A Step-by-Step Guide
- Conditional Testing in Cypress: Tutorial
- Cypress Web Testing Framework: Getting Started
- Cypress Disable Test: How to use Skip and Only in Cypress
- What’s new in Cypress 10? How it will change your current testing requirements
Use Cases
- How to Record Cypress Tests? (Detailed Guide)
- How to run your first Visual Test with Cypress
- How to Fill and Submit Forms in Cypress
- How to Automate Localization Testing using Cypress
- How to run Cypress Tests in Chrome and Edge
- How to use Cypress App Actions?
- How to Run Cypress Tests for your Create-React-App Application
- How to Run Cypress Tests in Parallel
- How to handle Click Events in Cypress
- How to Test React using Cypress
- How to Perform Visual Testing for Components in Cypress
- How to run UI tests in Cypress
- How to test redirect with Cypress
- How to Perform Screenshot Testing in Cypress
- How to write Test Case in Cypress: (with testing example)
Tool Comparisons