/cypress-audit

:zap: Run Lighthouse and Pa11y audits directly in your E2E test suites

Primary LanguageJavaScriptMIT LicenseMIT

Run Lighthouse and Pa11y audits directly in your Cypress E2E test suites

Build Status License: MIT

Why cypress-audit?

The tools we can use nowadays to verify the quality of our applications are awesome. They help us get a huge amount of confidence about what we ship in production and alert us when some kind of regression occurs.

  • Cypress has made business oriented workflow verification super easy and fun
  • Lighthouse has provided incredible tools to verify the performance of an application
  • Pa11y provides multiple tool to control the accessibility state of our applications in a wonderful way

The problem is that they run in their own context and with their own internal tricks for authentication and page browsing.

The idea of cypress-audit is to unify all of this by providing some Cypress Custom Commands so that you can use these tools directly inside your Cypress tests, close to your custom shortcut for navigation and login.

Usage

Installation

To make cypress-audit working in your project, you have to follow these 3 steps:

  • In your favorite terminal:
$ yarn add -D cypress-audit
# or
$ npm install --save-dev cypress-audit
  • In the cypress/plugins/index.js file:
const { lighthouse, pa11y, prepareAudit } = require("cypress-audit");

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

  on("task", {
    lighthouse: lighthouse(), // calling the function is important
    pa11y: pa11y(), // calling the function is important
  });
};
  • In the cypress/support/commands.js file:
import "cypress-audit/commands";

In your code

After completing the Installation section, you are now able to use the cy.audit and cy.pa11y commands inside your tests.

it("should pass the audits", function () {
  cy.lighthouse();
  cy.pa11y();
});

You can now check the APIs for the cy.lighthouse and cy.pa11y commands here.

cy.pa11y()

A Pa11y record showing some test failing on color contrast, landmark, heading and regions.

You can call cy.pa11Y(opts) with opts being any kind of the pa11y options.

cy.lighthouse()

A Lighthouse record showing some test failing on best-practices and performances

Good to know before

Lighthouse is a tool that is supposed to run against a production bundle for computing the performance and best-practices metrics. But it's widely suggested by Cypress to run their test on development environment. While this seems a bit counter intuitive, we can rely on the Cypress project feature to run some dedicated test suites against production bundles and to have quick feedbacks (or prevent regression) on these metrics.

Thresholds per tests

If you don't provide any argument to the cy.audit command, the test will fail if at least one of your metrics is under 100.

You can make assumptions on the different metrics by passing an object as argument to the cy.audit command:

it("should verify the lighthouse scores with thresholds", function () {
  cy.lighthouse({
    performance: 85,
    accessibility: 100,
    "best-practices": 85,
    seo: 85,
    pwa: 100,
  });
});

If the Lighthouse analysis returns scores that are under the one set in arguments, the test will fail.

You can also make assumptions only on certain metrics. For example, the following test will only verify the "correctness" of the performance metric:

it("should verify the lighthouse scores ONLY for performance", function () {
  cy.lighthouse({
    performance: 85,
  });
});

This test will fail only when the performance metric provided by Lighthouse will be under 85.

Globally set thresholds

While I would recommend to make per-test assumptions, it's possible to define general metrics inside the cypress.json file as following:

{
  "lighthouse": {
    "performance": 85,
    "accessibility": 50,
    "best-practices": 85,
    "seo": 85,
    "pwa": 50
  }
}

Note: These metrics are override by the per-tests one.

Passing options and config to Lighthouse directly

You can also pass any argument directly to the Lighthouse module using the second and third options of the command:

const thresholds = {
  /* ... */
};

const lighthouseOptions = {
  /* ... your lighthouse options */
};

const lighthouseConfig = {
  /* ... your lighthouse configs */
};

cy.lighthouse(thresholds, lighthouseOptions, lighthouseConfig);

Accessing the raw reports

When using custom tools, it can be conveniant to directly access to raw information provided by the specific tool for doing manual things like generating a custom reports.

To do so, you can pass a callback function to the task initializer and when an audit is run, it will be triggered with the raw information.

In the cypress/plugins/index.js file:

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

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

  on("task", {
    lighthouse: lighthouse(lighthouseReport => {
      console.log(lighthouseReport) // raw lighthouse report
    },
    pa11y: pa11y(pa11yReport => {
      console.log(pa11yReport) // raw pa11y report
    }),
  });
};