Get Blazing Fast UI Test Automation with Cypress

Cypress is truly a game-changing test automation tool. As someone who‘s tested web and mobile apps across over 3500 devices and browsers over 10+ years, I can tell you Cypress stands out from past frameworks I’ve used like Selenium and Appium.

In this comprehensive guide, I’ll share my best tips and practices to help you maximize Cypress based on countless hours of hands-on testing across dozens of projects.

What Makes Cypress Special?

Launched publicly in 2018, Cypress was specifically designed to overcome the pain points developers faced with traditional test frameworks like Selenium.

It runs directly in the browser, as opposed to Selenium which requires a browser driver. This means faster run times and the ability to watch tests execute in real time.

Key highlights of what makes Cypress unique include:

Time Travel Debugging

Freely move back and forth through your test run to understand what happened at each step – incredibly valuable for diagnosing failures.

Automatic Waiting

Cypress automatically waits for elements and assertions before continuing, removing the need for slow implicit waits and sleep() statements.

Network Traffic Control

Full control and stubbing of network traffic, service workers and localhost servers allows testing edge cases.

Screenshots & Videos

Cypress takes screenshots automatically at every step, and records videos of all runs for visual playback.

Component Testing

Cypress 10 introduces the ability to unit test React, Vue and other UI components in isolation without requiring a live server.

Cypress UI Testing in Action

Let‘s walk through a sample test to see Cypress in action:

describe(‘Homepage‘, () => {

  beforeEach(() => {
    cy.visit(‘https://www.mysite.com/‘) 
  })

  it(‘has logo‘, () => {
    cy.get(‘.brand-logo‘).should(‘be.visible‘) 
  })

  it(‘can search‘, () => {
    cy.get(‘#search‘).type(‘Automated Testing{enter}‘) 
    cy.url().should(‘include‘, ‘search=Automated+Testing‘)
  })

})

This test navigates to our site‘s homepage, and asserts:

  • The logo is visible
  • Search works and loads results page

Now let‘s dive deeper into common capabilities, customization techniques, cross-browser testing strategies, CI/CD integrations and more with Cypress!

Crafting Maintainable Tests

One key to maximizing Cypress is crafting tests sustainably from the start using patterns like:

  • Page objects – Abstract commonly used selectors into reusable objects
  • Custom commands – Encapsulate repetitive logic for reuse across tests
  • Config files – Keep test data, endpoints and config centralized
// pages.js 

export const loginPage = {
  emailInput: ‘#email‘,
  passwordInput: ‘#password‘,
  submitBtn: ‘.submit-btn‘  
}

// commands.js

Cypress.Commands.add(‘login‘, (email, password) => {

  cy.get(loginPage.emailInput).type(email)
  cy.get(loginPage.passwordInput).type(password)
  cy.get(loginPage.submitBtn).click() 

})

// config.js

export default {
  env: ‘staging‘,
  loginUrl: ‘https://website.com/login‘
}

Then in tests, reuse this reusable code:

import { loginPage } from ‘./pages‘
import config from ‘./config‘

describe(‘login suite‘, () => {

  beforeEach(() => {
    cy.visit(config.loginUrl)
  })

  it(‘allows login‘, () => {
    cy.login(‘[email protected]‘, ‘password123‘)
  })

})

Much cleaner! This sets you up nicely as tests grow in scope.

Level Up Your Selectors

Locating elements reliably is critical for avoiding flaky tests. Here are my top tips:

  • Use IDs over broad tags when possible – fastest and least prone to breakage
  • Add custom data attributes to your app markup to facilitate targeting
  • Leverage .contains() for partial text matches
  • Use .should(‘not.exist‘) to confirm UI elements are not present
  • Traverse DOM with .children() .closest() .parents() to zero-in on elements

I also recommend a library like TestID to auto-generate data attributes for testing.

Time Travel & Debuggability

One of my favorite Cypress capabilities is Time Travel debugging.

As tests run, Cypress takes periodic snapshots allowing you to jump between test steps – incredibly useful for understanding what went wrong.

Combine this withautomatic video recording, and you have unparalleled debuggability. The ability to visually replay tests is invaluable and unique among test frameworks.

Component Testing

Cypress 10 introduced a groundbreaking capability – Component Testing.

Instead of requiring a live app server to test against, you can directly import and mount individual components in complete isolation:


import Login from ‘./Login.jsx‘

it(‘calls onSubmit when form submitted‘, () => {
  cy.mount(<Login />)  
  cy.get(‘[data-testid="email"]‘).type(‘[email protected]‘) 
  cy.get(‘[data-testid="password"]‘).type(‘123456‘)
  cy.get(‘form‘).submit()

  // Assert onSubmit function called 
})  

This allows for lightning-fast unit testing of complex React, Vue and other components.

Going Cross-Browser with BrowserStack

A common need is running Cypress tests across browsers to catch cross-browser bugs.

While Cypress runs directly in the browser, services like BrowserStack make it simple to run your tests across 2000+ browser, device and operating system combinations in the cloud.

The BrowserStack Cypress integration makes set up a breeze:

npm install -g browserstack-cypress-cli
browserstack-cypress init
browserstack-cypress run

Now you can run that same Cypress test suite seamlessly across Chrome, Firefox, Edge and Safari on various operating systems without any modifications.

BrowserStack also provides advanced debugging and video recordings like Cypress does locally. Well worth the investment!

Integrating Cypress with CI/CD

To prevent regressions, it’s vital to incorporate Cypress into your continuous integration and delivery pipelines.

Popular options include:

  • GitHub Actions – Cypress GitHub Action using included docker images
  • CircleCI – Official Cypress CircleCI Orb
  • Custom Docker – Cypress provides Docker images for all base operating systems

Here is a sample GitHub Actions workflow:

name: E2E Tests
on: [push]
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Cypress run
        uses: cypress-io/github-action@v5
        with:
          build: npm run build
          start: npm start

Refer to Cypress CI documentation for additional examples.

Visual Testing Integrations

Beyond functionality, the visual appearance of your app is critical to the user experience.

Cypress enables visual validation through open source projects like Applitools and Percy which both have tight integrations.

These tools perform pixel-by-pixel comparisons of screenshots captured during test runs, allowing catching minute visual regressions pre-merge:

Percy Cypress diff comparison example

Additional Test Types

While Cypress focuses mainly on UI testing, additional types of tests are possible:

  • API Testing – Stub network calls while running UI tests or make requests directly during headless runs.
  • Load Testing – Use Artillery or k6 along with Cypress test code.
  • Accessibility – cypress-axe helps catch accessibility issues.
  • Visual Regression – As mentioned, Percy and Applitools integrations help.

So while best suited for UI testing, Cypress gives you options to branch out.

Cypress Limitations

As much as I love Cypress, it’s important to understand its limitations:

  • Cypress tests run within the browser, limiting support for non-UI tests
  • The test runner is CPU and memory intensive, requiring sufficient hardware resources
  • Browser support outside of Chromium-based browsers is imperfect
  • Cypress controls the browser directly so some native behavior differs slightly

My recommendation when evaluating Cypress is:

  • Use for critical customer-facing UI flows
  • Fill gaps with other open source tools or commercial services
  • Budget sufficient infrastructure underlying your CI/CD environment

Conclusion

I hope this guide has provided ideas and best practices to effectively incorporate Cypress test automation within your development lifecycle.

Properly crafted, maintainable tests will transform the way your team develops by allowing fearless refactors, faster feedback and higher quality software.

Cypress truly is a game-changing test framework. I cannot overemphasize how much time and headache it will save your team if leveraged thoughtfully.

Let me know if you have any other questions as you embark on your Cypress journey!

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.