From c3cd48e5fd00a2d92fe5ac63de983c8f2f77047f Mon Sep 17 00:00:00 2001 From: Philip Walton Date: Sun, 13 Nov 2022 21:53:29 -0800 Subject: [PATCH 1/2] Ignore TTFB for loads where responseStart is zero --- src/onTTFB.ts | 23 +++++++++++++++-------- test/e2e/onTTFB-test.js | 29 ++++++++++++++++++++++++++++- test/views/ttfb.njk | 12 ++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/onTTFB.ts b/src/onTTFB.ts index c7b56867..04e3b0dc 100644 --- a/src/onTTFB.ts +++ b/src/onTTFB.ts @@ -67,21 +67,28 @@ export const onTTFB = (onReport: ReportCallback, opts?: ReportOpts) => { const navEntry = getNavigationEntry(); if (navEntry) { - // The activationStart reference is used because TTFB should be - // relative to page activation rather than navigation start if the - // page was prerendered. But in cases where `activationStart` occurs - // after the first byte is received, this time should be clamped at 0. - metric.value = Math.max(navEntry.responseStart - getActivationStart(), 0); + const responseStart = navEntry.responseStart; // In some cases the value reported is negative or is larger // than the current page time. Ignore these cases: // https://github.com/GoogleChrome/web-vitals/issues/137 // https://github.com/GoogleChrome/web-vitals/issues/162 - if (metric.value < 0 || metric.value > performance.now()) return; + if (responseStart < 0 || responseStart > performance.now()) return; - metric.entries = [navEntry]; + // If the navigation entry's `responseStart` value is 0, ignore it. + // This likely means the request included a cross-origin redirect, and + // the browser has removed timing info for privacy/security reasons. + // See: https://github.com/GoogleChrome/web-vitals/issues/275 + if (responseStart > 0) { + // The activationStart reference is used because TTFB should be + // relative to page activation rather than navigation start if the + // page was prerendered. But in cases where `activationStart` occurs + // after the first byte is received, this time should be clamped at 0. + metric.value = Math.max(responseStart - getActivationStart(), 0); - report(true); + metric.entries = [navEntry]; + report(true); + } // Only report TTFB after bfcache restores if a `navigation` entry // was reported for the initial load. diff --git a/test/e2e/onTTFB-test.js b/test/e2e/onTTFB-test.js index d573b4d0..c2417521 100644 --- a/test/e2e/onTTFB-test.js +++ b/test/e2e/onTTFB-test.js @@ -16,6 +16,7 @@ import assert from 'assert'; import {beaconCountIs, clearBeacons, getBeacons} from '../utils/beacons.js'; +import {domReadyState} from '../utils/domReadyState.js'; import {stubForwardBack} from '../utils/stubForwardBack.js'; @@ -175,8 +176,8 @@ describe('onTTFB()', async function() { const ttfb2 = await getTTFBBeacon(); - assert(ttfb2.value >= 0); assert(ttfb2.id.match(/^v3-\d+-\d+$/)); + assert.strictEqual(ttfb2.value, 0); assert.strictEqual(ttfb2.name, 'TTFB'); assert.strictEqual(ttfb2.value, ttfb2.delta); assert.strictEqual(ttfb2.rating, 'good'); @@ -184,6 +185,32 @@ describe('onTTFB()', async function() { assert.strictEqual(ttfb2.entries.length, 0); }); + it('ignores navigations with no responseStart timestamp', async function() { + await browser.url('/test/ttfb?responseStart=0'); + + await domReadyState('complete'); + + // Wait a bit to ensure no beacons were sent. + await browser.pause(1000); + + const loadBeacons = await getBeacons(); + assert.strictEqual(loadBeacons.length, 0); + + // Test back-forward navigations to ensure they're sent, even if the + // initial page TTFB value is ignored. + await stubForwardBack(); + + const ttfb = await getTTFBBeacon(); + + assert(ttfb.id.match(/^v3-\d+-\d+$/)); + assert.strictEqual(ttfb.value, 0); + assert.strictEqual(ttfb.name, 'TTFB'); + assert.strictEqual(ttfb.value, ttfb.delta); + assert.strictEqual(ttfb.rating, 'good'); + assert.strictEqual(ttfb.navigationType, 'back-forward-cache'); + assert.strictEqual(ttfb.entries.length, 0); + }); + describe('attribution', function() { it('includes attribution data on the metric object', async function() { await browser.url('/test/ttfb?attribution=1'); diff --git a/test/views/ttfb.njk b/test/views/ttfb.njk index 8707a6d6..7d0350b4 100644 --- a/test/views/ttfb.njk +++ b/test/views/ttfb.njk @@ -24,6 +24,18 @@

Navigate away

+ +