How to Make Writing Performance Tests Easy With Cypress

Over the course of a web project, it’s important to keep an eye on app performance — something that can easily be handled with Cypress tests. As more components and complex logic are added to a website, performance metrics, such as page load, can also vary and change.

Here’s a quick overview of how to track page load for a web app with Cypress tests.

Setup Tests

The setup portion of the test is fairly straightforward. The steps required in setup will vary from app to app. If necessary, clear and set up the database. If a user is needed, now would be the time to create one.


context(“measure performance metrics”, () => {
  beforeEach(() => {
    clearDatabase();
    setupTestDatabase();
    createUserAndLogin();
  });
});

Visit Pages and Track Performance

Once the test is properly set up, it’s time to measure page load. Using Cypress, visit the page to test and provide the following onBeforeLoad option.


it(“measures page load on the home page”, () => {
  cy.visit(“/home”, {
    onBeforeLoad: (win) => {
      win.performance.mark(“start-loading”);
    }
  })
});

We can use performance.mark() to add a timestamp with the given name to the browser’s performance entry buffer. Using the performance property on the window, we can look for these timestamps by name.

We can tell if a given page is loaded by looking for specific components. This could be based on text that is visible or a certain number of records being displayed. Once a page is loaded, we’ll want to add another timestamp.


it(“measures page load on the home page”, () => {
  cy.visit(“/home”, {
    onBeforeLoad: (win) => {
      win.performance.mark(“start-loading”);
    }
  })
  // Get the performance property to work with
  .its(“performance”)
  .then((performance) => {
    // This is how we will tell that our page is loaded
    cy.get(“body”).should(“have.text”, “Hello World!”)
    // Add a timestamp once the page has loaded
    .then(() => performance.mark(“end-loading”));
  });
});

At this point, we’ve collected both the start time and end time for page load, so we can measure the time between them. Using performance.measure() creates another timestamp spanning the start time and end time. Once we get the duration of the page load, we can add assertions based on how long we expect the load time to be.


it(“measures page load on the home page”, () => {
  cy.visit(“/home”, {
    onBeforeLoad: (win) => {
      win.performance.mark(“start-loading”);
    }
  })
  .its(“performance”).then((performance) => {
    cy.get(“body”).should(“have.text”, “Hello World!”)
    .then(() => performance.mark(“end-loading”))
    .then(() => {
      performance.measure(“pageLoad”, “start-loading”, “end-loading”);
      // Retrieve the timestamp we just created
      const measure = performance.getEntriesByName(“pageLoad”)[0]; 
      // This is the total amount of time (in milliseconds) between the start and end
      const duration = measure.duration;
      assert.isAtMost(duration, 5000);
    });
  });
});

Add and Collect Logs

In order to keep track of performance over time, collecting logs can be useful. To do this, we can utilize cypress-terminal-report. Details for installing and registering the plugin with Cypress can be found on the cypress-terminal-report GitHub page.

In addition to the installation, we can add options to collect the logs we want. We’ll add the following to cypress/plugins/index.ts to specify where to output the logs.


const plugins: Cypress.PluginConfig = (on, _config) => {
  const log options = {
    printLogsToFile: “always”,
    printLogsToConsole: “always”,
    outputRoot: _config.projectRoot + “/logs/“,
    outputTarget: {
      “performance-logs.txt”: “txt”
    }
  };

  require("cypress-terminal-report/src/installLogsPrinter")(on, logOptions);
}

Then we’ll update cypress/support/index.js to specify what types of logs to collect.


const logOptions = {
  collectTypes: ["cy:log"],
};
require("cypress-terminal-report/src/installLogsCollector")(logOptions);

Once all the configuration for collecting logs is in place, we simply need to update our test.


it(“measures page load on the home page”, () => {
  cy.visit(“/home”, {
    onBeforeLoad: (win) => {
      win.performance.mark(“start-loading”);
    }
  })
  .its(“performance”).then((performance) => {
    cy.get(“body”).should(“have.text”, “Hello World!”)
    .then(() => performance.mark(“end-loading”))
    .then(() => {
      performance.measure(“pageLoad”, “start-loading”, “end-loading”);
      const measure = performance.getEntriesByName(“pageLoad”)[0];
      const duration = measure.duration;
      assert.isAtMost(duration, 5000);

      cy.log(
        `[PERFORMANCE] Page load duration for HOME: ${duration / 1000} seconds`
      );
    });
  });
});

These logs files can be collected on local runs of tests or as artifacts in CI.


Performance tests are an important tool to use when creating apps. Poor performance can create an unfavorable user experience. But, using a framework like Cypress to keep track of changes in these metrics can help avoid major slowdowns as apps continue to develop.

Conversation
  • Satya says:

    The mark: “win.performance.mark(‘start-loading’);”, is not recognized in the then function at: “performance.measure(“pageLoad”, “start-loading”, “end-loading”);” and the test fails with error: “Failed to execute ‘measure’ on ‘Performance’: The mark ‘start-loading’ does not exist.”
    Do we have a solution for this.
    Thanks!

    • John says:

      I have found that it is due to the site you are accessing that depends on if the ‘start-loading’ does not exist. Im not sure what is required to fix it, but changing the url to something say http://www.google.com resolves the issue. This is how I know that it isn’t an issue with cypress but rather the test sites ability generate the mark before the page loads.

  • John says:

    I have found that it is due to the site you are accessing that depends on if the ‘start-loading’ does not exist. Im not sure what is required to fix it, but changing the url to something say http://www.google.com resolves the issue. This is how I know that it isn’t an issue with cypress but rather the test sites ability generate the mark before the page loads.

  • Comments are closed.