Documentation / Single page application

Test a single page application

Chrome soft navigations

Sitespeed.io 40 (via Browsertime 27) supports Chrome soft-navigation entries out of the box. When Chrome's PerformanceObserver detects a soft navigation — a user interaction + URL change + visible paint inside a short window — the route change automatically gets its own HAR page and the standard FCP / LCP / CLS / INP metrics, without any scripting on your side. Most React / Next.js / Vue / Turbo apps will Just Work.

You still need scripting if you want to drive a specific user flow (log in, click through a checkout, etc.) — that's what the rest of this page is about. But for "measure the route change after the user clicks", the browser-native path is now the simplest option.

Test by scripting

To test a single page application you probably want to measure more than just the first page (that loads the framework). You do that by using the Browsertime command/scripting. You can use either our commands or Selenium scripts.

When you test a single page application, make sure you add the --spa parameter to your test run command, so that Browsertime/sitespeed.io knows it's an SPA. That will enable:

  • Automatic handling of URLs with #.
  • Ending the page load test after X seconds of no activity in the Resource Timing API. This makes sure that when you navigate to different pages, the navigation ends when everything has finished loading.

Metrics

Using a single page application makes it harder to measure how fast a page loads, since the Navigation Timing API will not work. Instead you can use the User Timing API, pick up visual metrics, and metrics from the CPU.

The navigation timing metrics are only useful for the first page that you test. Remember, subsequent pages in your SPA will not populate new navigation timing metrics.

Visual Metrics

Visual Metrics will work fine, but depending on how you navigate, First Visual Change can be when you click your link, so focus on Last Visual Change or one of the VisualComplete metrics instead.

User Timing

You need to instrument the code yourself or use a framework to do that automatically. Read how LinkedIn uses User Timings to measure their SPA.

CPU metrics

If you run your tests with Chrome and enable --chrome.timeline, you will also get metrics for where Chrome spends its time rendering and executing JavaScript.

Example: Performance test Grafana

In this example we navigate and measure the start page of our Grafana installation, then measure clicking the link to see the data for the last thirty days.

Let's create a script file and call it thirtydays.js.

module.exports = async function(context, commands) {
 await commands.measure.start('https://dashboard.sitespeed.io/d/000000044/page-timing-metrics?orgId=1');
 try {
 await commands.click.byClassName('gf-timepicker-nav-btn');
 await commands.wait.byTime(1000);
 // We give the page an alias that will be used if the metrics is sent to Graphite/InfluxDB 
 await commands.measure.start('pageTimingMetricsLast30Days');
 await commands.click.byLinkTextAndWait('Last 30 days');
 await commands.measure.stop();
 } catch (e) {
     // If the GUI change and a link is not there,
     // the click commands will throw an error. 
     // sitespeed.io will catch, log and rethrow 
     // and you can choose if you want to have a different
     // user flow
 }
};

Then you run it by passing the script file, using --spa to notify that you are testing a single page application and --multi to indicate that you plan to test multiple pages within one run.

docker run --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io:40.2.0 thirtydays.js --spa --multi