Leveraging Cypress Beyond Functional Testing

Marie Drake

https://www.mariedrake.com/

/in/marie-drake

@mcruzdrake

 

@mcruzdrake

- Quality Engineering Manager at Zoopla

- Previously a Principal Test Automation Engineer at News UK

- Tech Blogger

- Cypress Ambassador

- Co-organiser of Cypress UK Community meet up

- Speaker at various meet ups and conferences

- Online Instructor at TAU and Ministry of Testing

- Accessibility Advocate

👋🏼 Hi, I'm Marie

@mcruzdrake

@mcruzdrake

What tests can it cover?

✅ End-to-end tests

✅ Component tests

✅ API tests

✅ Accessibility tests

✅ Client side performance tests

✅ Visual tests

@mcruzdrake

Cypress validates the structure of your DOM.

(what about the look and styling of your app?)

@mcruzdrake

@mcruzdrake

@mcruzdrake

it("it should display all fields and labels as expected", () => {
  cy.get(".logo-w a img").should("be.visible");
  cy.get(".auth-header").should("contain", "Login Form");
  cy.get("#username").should("be.visible");
  cy.get(".os-icon-user-male-circle").should("be.visible");
  cy.get("#password").should("be.visible");
  cy.get(".os-icon-fingerprint").should("be.visible");
  cy.get("#log-in").should("be.visible");
  cy.get(".form-check-label")
    .should("be.visible")
    .should("have.text", "Remember Me");
  cy.get('img[src="img/social-icons/twitter.png"]').should("be.visible");
  cy.get('img[src="img/social-icons/facebook.png"]').should("be.visible");
  cy.get('img[src="img/social-icons/linkedin.png"]').should("be.visible");
});

@mcruzdrake

@mcruzdrake

cy.get('#username').should('have.css', 'text-decoration', 'line-through');
cy.get('#username').should('have.css', 'color', 'rgb(217,217,217)');

@mcruzdrake

How can we test that our application looks good visually?

@mcruzdrake

Visual Testing!

@mcruzdrake

  • It's not new! 
  • A lot of existing visual tools already (pixel by pixel comparison)
if(isBaselineFound) {
  runSnapshot();
  checkDifferences();
  reportTestStatus();
} else {
  promoteImageAsBaseline();
}

Automated Visual Testing

@mcruzdrake

But which tool? 🤔

@mcruzdrake

But which tool? 🤔

@mcruzdrake

What to consider when doing Visual Testing?

@mcruzdrake

Choosing the right tooling!

@mcruzdrake

Level of Visual Testing

@mcruzdrake

@mcruzdrake

Test Maintenance

@mcruzdrake

Pipeline Integration

@mcruzdrake

Developer Experience

@mcruzdrake

Handling Baseline Images

@mcruzdrake

Handling Dynamic Data

@mcruzdrake

Budget and Time Constraints

@mcruzdrake

Reporting

@mcruzdrake

Community and Maintenance Support

@mcruzdrake

@mcruzdrake

Pros Cons
Free Not maintained recently
Easily integrate with Cypress No single report for visual differences
CI integration Only works well if you have static data
No support for other browsers

Cypress Image Snapshot

@mcruzdrake

Pros Cons
Free Starter Plan (5000 snaps a month) Doesn't support Safari and IE11
Easily integrate with Cypress Only works well if you have static data
CI integration
Github integration
Automatically checks Chrome, Firefox and Edge
Dashboard to view all results

Percy

@mcruzdrake

Pros Cons
AI comparison algorithm Pricey 💲💲💲
Easily integrate with Cypress
CI integration
Github integration
Dashboard to view all results
Supports major browsers

Applitools

@mcruzdrake

Code Walkthrough time!

@mcruzdrake

@mcruzdrake

@mcruzdrake

/// <reference types="cypress" />

describe('Image search with Mock API', () => {
    it('should look ok visually with static data', () => {
        cy.intercept('photos?page=1').as('defaultSearchResults');

        cy.visit('/').wait('@defaultSearchResults', {
            timeout: Cypress.config('defaultCommandTimeout'),
        });

        cy.intercept('search/photos?query=mock+', { fixture: 'unsplash.json' }).as('mockedResults');

        cy.get('[data-testid="search-input"]')
          .type('mock {enter}')
          .wait('@mockedResults', {
            timeout: Cypress.config('defaultCommandTimeout'),
        });

        cy.matchImageSnapshot();
    });
  });
"cy:image:snapshot:run": "cypress run --spec cypress/integration/cypress-image-snapshot/*.spec.js"

@mcruzdrake

@mcruzdrake

/// <reference types="cypress" />

describe('Image search with Mock API', () => {
    it('should look ok visually with static data', () => {
        cy.intercept('photos?page=1').as('defaultSearchResults');

        cy.visit('/').wait('@defaultSearchResults', {
            timeout: Cypress.config('defaultCommandTimeout'),
        });

        cy.intercept('search/photos?query=mock+', { fixture: 'unsplash.json' }).as('mockedResults');

        cy.get('[data-testid="search-input"]')
          .type('mock {enter}')
          .wait('@mockedResults', {
            timeout: Cypress.config('defaultCommandTimeout'),
        });

        cy.percySnapshot();
  });
"cy:percy:run": "percy exec -- cypress run --spec cypress/integration/percy/*.spec.js"

@mcruzdrake

@mcruzdrake

/// <reference types="@applitools/eyes-cypress" />
/// <reference types="cypress" />

describe('Image search', () => {
    it('should look ok visually', () => {
        cy.intercept('photos?page=1').as('defaultSearchResults');

        cy.visit('/').wait('@defaultSearchResults', {
            timeout: Cypress.config('defaultCommandTimeout'),
        });

        cy.eyesOpen({
            appName: 'ReactSplash',
            batchName: 'Image search',
            browser: [{ width: 1024, height: 768 }],
        });
    
        cy.eyesCheckWindow('Image Gallery');
        cy.eyesClose();
    });
  });

@mcruzdrake

Wrapping up

- Cypress alone is not the best tool for testing the look and feel of your application

- Leverage third party plugins instead that takes a snapshot of the page

- Remember there are so many things to consider when choosing which visual tool!

- The tool you choose should be able to work with your requirements

- Trial and error approach (experimentation culture!)

Made with Slides.com