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
How to Use Cypress App Actions
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')
})
})
Copied

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')
})
Copied

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
}
Copied

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')
Copied

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')
Copied

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')
Copied

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')
Copied

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')
Copied

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')
Copied

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')
Copied

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')
Copied

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?')

})
Copied

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')
Copied

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)
Copied

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
Copied

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()
Copied

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

  })

})
Copied

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
Copied

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

  })

})
Copied

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
Copied

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

Use Cases

Tool Comparisons

Tags
Automation Testing Visual Testing