A Collection of my Favourite Cypress Features

Marie Drake

Quality Engineering Manager, Zoopla

@mcruzdrake | mariedrake.com

@mcruzdrake

@mcruzdrake

Cypress Test

Runner

@mcruzdrake

@mcruzdrake

@mcruzdrake

@mcruzdrake

@mcruzdrake

@mcruzdrake

@mcruzdrake

Handling network requests

@mcruzdrake

cy.intercept('search/photos?query=jehrjehrjehrjkerae+').as(
	'invalidSearchResults'
);

cy.get('@searchInput').type('jehrjehrjehrjkerae {enter}');
cy.wait('@invalidSearchResults');
cy.contains('No content found');

@mcruzdrake

@mcruzdrake

@mcruzdrake

💡 Tip:

🔵 real network call 

@mcruzdrake

Stubbing network requests 

@mcruzdrake

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

cy.visit('/');
{
	"id": "1",
  	"description": "This is a mock data",
   	"alt_description": "pancakes mock data",
   	"urls": {
     	   "small": "https://images.unsplash.com/photo-1541288097308-7b8e3f58c4c6"
     	},
   	"width": 250,
   	"height": 250,
   	"liked_by_user": "false"
}

@mcruzdrake

@mcruzdrake

@mcruzdrake

cy.intercept('GET', 'search/photos?query=mock+', {
      statusCode: 200, 
      body: { 
        results: [], total: 0
      }
});

cy.visit('/');

@mcruzdrake

@mcruzdrake

Screenshots & Videos

@mcruzdrake

npx cypress run

@mcruzdrake

{
	"videoUploadOnPasses": false,
  	"video": false
}

@mcruzdrake

npx cypress run

@mcruzdrake

{
	"screenshotOnRunFailure": false
}

@mcruzdrake

💡 Tip:

Add screenshots and videos as artifacts in your CI pipeline

@mcruzdrake

Cypress + Mochawesome

@mcruzdrake

Cypress Plugins

@mcruzdrake

Code Coverage 

@mcruzdrake

@cypress/code-coverage

@mcruzdrake

But, how does code coverage works?

@mcruzdrake

import '@cypress/code-coverage/support'

cypress/support/index.js

cypress/plugins/index.js

@mcruzdrake

Instrumenting your code!

@mcruzdrake

{
  "env": {
    "test": {
      "plugins": [ "istanbul" ]
    }
  }
}

@mcruzdrake

@mcruzdrake

@mcruzdrake

💡 Tip:

Combine code coverage reports (jest and cypress)

@mcruzdrake

Accessibility Plugin 

@mcruzdrake

cypress-axe

@mcruzdrake

"devDependencies": {
    "axe-core": "^4.2.2",
    "cypress": "7.5.0",
    "cypress-axe": "0.12.2",
 }
import './commands';
import 'cypress-axe';

cypress/support/index.js

describe('Axe Demo', () => {
  it('should catch accessibility issues on the entire page', () => {
    cy.visit('https://todomvc.com/examples/react/#/');
    cy.injectAxe();

    // By default, this will test the entire page
    cy.checkA11y();

    // If you want to exclude certain elements
    cy.checkA11y({ exclude: ['.info'] });

    // If you only want to check a specific element
    cy.checkA11y('.info');

    // If you want to disable some rules
    cy.checkA11y(null, {
      rules: {
        'color-contrast': { enabled: false },
      },
    });
  });
});

@mcruzdrake

@mcruzdrake

@mcruzdrake

💡 Tip:

Integrate accessibility checks earlier on.

@mcruzdrake

Performance Plugin

@mcruzdrake

cypress-audit

@mcruzdrake

"devDependencies": {
    "cypress": "9.0.0",
    "cypress-audit": "1.1.0"
}
import "cypress-audit/commands";

cypress/support/commands.js

const { lighthouse, prepareAudit } = require('cypress-audit');

module.exports = (on, config) => {
  on('before:browser:launch', (browser = {}, launchOptions) => {
    prepareAudit(launchOptions);
  });

  on('task', {
    lighthouse: lighthouse(),
  });
};

cypress/plugins/index.js

@mcruzdrake

it('should run lighthouse performance audits using default thresholds', () => {
    cy.visit('/');
    cy.lighthouse();
});

@mcruzdrake

@mcruzdrake

it('should run lighthouse performance audits using custom thresholds', () => {
    const thresholds = {
      performance: 50,
      accessibility: 80,
      'first-contentful-paint': 2000,
      'largest-contentful-paint': 3000,
      interactive: 2000,
      seo: 60,
      pwa: 50,
    };

    const lighthouseConfig = {
      formFactor: 'desktop',
      screenEmulation: { disabled: true },
    };

    cy.visit('/');
    cy.lighthouse(thresholds, lighthouseConfig);
});

@mcruzdrake

💡 Tip/Advice:

This is just synthetic testing. Don't take the scores as gospel!

@mcruzdrake

Visual Testing Plugin

@mcruzdrake

@mcruzdrake

@mcruzdrake

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

describe('Image search', () => {
    it('should look ok visually', () => {
        cy.visit('/');

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

@mcruzdrake

@mcruzdrake

💡 Tip:

When doing visual testing, there are a lot of things to consider (browser support, test maintenance, reporting, dev experience etc.)

@mcruzdrake

Cypress Studio

@mcruzdrake

{
  "baseUrl": "http://localhost:3000/",
  "experimentalStudio": true
}

@mcruzdrake

@mcruzdrake

@mcruzdrake

@mcruzdrake

it('should not return any images when search term is invalid', () => {
    cy.intercept('search/photos?query=jehrjehrjehrjkerae+').as(
      'invalidSearchResults'
    );

    cy.get('[data-testid="search-input"]').type('jehrjehrjehrjkerae {enter}');
    cy.wait('@invalidSearchResults');
    cy.contains('No content found');
    cy.get('[data-test-id="image-gallery"] img').should('not.exist');
    /* ==== Generated with Cypress Studio ==== */
    cy.get('[data-testid=search-input]').clear();
    cy.get('[data-testid=search-input]').type('2342343{enter}');
    cy.get('.grid > :nth-child(3)').should('be.visible');
    /* ==== End Cypress Studio ==== */
  });

@mcruzdrake

@mcruzdrake

💡 Tip:

Give feedback 💜 

A Collection of my Favourite Cypress Features

Marie Drake

Quality Engineering Manager, Zoopla

@mcruzdrake | mariedrake.com

Made with Slides.com