Skip to content

Commit

Permalink
Support 'discarded' as a navigationType
Browse files Browse the repository at this point in the history
  • Loading branch information
tunetheweb committed Nov 15, 2022
1 parent 861d065 commit 2704ae1
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 4 deletions.
9 changes: 6 additions & 3 deletions README.md
Expand Up @@ -697,10 +697,13 @@ interface Metric {
* The type of navigation
*
* Navigation Timing API (or `undefined` if the browser doesn't
* support that API). For pages that are restored from the bfcache, this
* value will be 'back-forward-cache'.
* support that API).
* For pages that are restored from the bfcache, this value will
* be 'back-forward-cache'.
* For pages that are restored after being discarded, this value will
* be 'discarded'.
*/
navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender';
navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'discarded';
}
```

Expand Down
2 changes: 2 additions & 0 deletions src/lib/initMetric.ts
Expand Up @@ -30,6 +30,8 @@ export const initMetric = (name: Metric['name'], value?: number): Metric => {
} else if (navEntry) {
if (document.prerendering || getActivationStart() > 0) {
navigationType = 'prerender';
} else if (document.wasDiscarded) {
navigationType = 'discarded';
} else {
navigationType =
navEntry.type.replace(/_/g, '-') as Metric['navigationType'];
Expand Down
11 changes: 10 additions & 1 deletion src/types/base.ts
Expand Up @@ -65,7 +65,7 @@ export interface Metric {
* support that API). For pages that are restored from the bfcache, this
* value will be 'back-forward-cache'.
*/
navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender';
navigationType: 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender' | 'discarded';
}

/**
Expand Down Expand Up @@ -105,3 +105,12 @@ export interface ReportOpts {
* loading. This is equivalent to the corresponding `readyState` value.
*/
export type LoadState = 'loading' | 'dom-interactive' | 'dom-content-loaded' | 'complete';

/**
* Extend the document with the new wasDiscarded boolean which is not supported
* in typescript yet
* https://github.com/WICG/page-lifecycle/blob/main/README.md
*/
declare global {
interface Document { wasDiscarded?: boolean; }
}
21 changes: 21 additions & 0 deletions test/e2e/onCLS-test.js
Expand Up @@ -632,6 +632,27 @@ describe('onCLS()', async function() {
assert.strictEqual(cls.navigationType, 'back-forward-cache');
});

it('reports discarded as nav type for wasDiscarded', async function() {
if (!browserSupportsCLS) this.skip();

await browser.url('/test/cls?wasDiscarded=1');

// Wait until all images are loaded and rendered, then change to hidden.
await imagesPainted();
await stubVisibilityChange('hidden');

await beaconCountIs(1);
const [cls] = await getBeacons();

assert(cls.value >= 0);
assert(cls.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(cls.name, 'CLS');
assert.strictEqual(cls.value, cls.delta);
assert.strictEqual(cls.rating, 'good');
assert.strictEqual(cls.entries.length, 2);
assert.strictEqual(cls.navigationType, 'discarded');
});

describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
if (!browserSupportsCLS) this.skip();
Expand Down
17 changes: 17 additions & 0 deletions test/e2e/onFCP-test.js
Expand Up @@ -235,6 +235,23 @@ describe('onFCP()', async function() {
assert.strictEqual(fcp2.navigationType, 'back-forward-cache');
});

it('reports discarded as nav type for wasDiscarded', async function() {
if (!browserSupportsFCP) this.skip();

await browser.url('/test/fcp?wasDiscarded=1');

await beaconCountIs(1);

const [fcp] = await getBeacons();
assert(fcp.value >= 0);
assert(fcp.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(fcp.name, 'FCP');
assert.strictEqual(fcp.value, fcp.delta);
assert.strictEqual(fcp.rating, 'good');
assert.strictEqual(fcp.entries.length, 1);
assert.strictEqual(fcp.navigationType, 'discarded');
});

describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
if (!browserSupportsFCP) this.skip();
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/onFID-test.js
Expand Up @@ -194,6 +194,28 @@ describe('onFID()', async function() {
assert.match(fid2.entries[0].name, /(mouse|pointer)down/);
});

it('reports discarded as nav type for wasDiscarded', async function() {
if (!browserSupportsFID) this.skip();

await browser.url('/test/fid?wasDiscarded=1');

// Click on the <h1>.
const h1 = await $('h1');
await h1.click();

await beaconCountIs(1);

const [fid] = await getBeacons();
assert(fid.value >= 0);
assert(fid.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(fid.name, 'FID');
assert.strictEqual(fid.value, fid.delta);
assert.strictEqual(fid.rating, 'good');
assert.strictEqual(fid.navigationType, 'discarded');
assert.match(fid.entries[0].name, /(mouse|pointer)down/);
});


describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
if (!browserSupportsFID) this.skip();
Expand Down
24 changes: 24 additions & 0 deletions test/e2e/onINP-test.js
Expand Up @@ -316,6 +316,30 @@ describe('onINP()', async function() {
assert.strictEqual(beacons.length, 0);
});

it('reports discarded as nav type for wasDiscarded', async function() {
if (!browserSupportsINP) this.skip();

await browser.url('/test/inp?click=100&wasDiscarded=1');

const h1 = await $('h1');
await h1.click();

await stubVisibilityChange('hidden');

await beaconCountIs(1);

const [inp] = await getBeacons();
assert(inp.value >= 0);
assert(inp.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(inp.name, 'INP');
assert.strictEqual(inp.value, inp.delta);
assert.strictEqual(inp.rating, 'good');
assert(containsEntry(inp.entries, 'click', 'h1'));
assert(interactionIDsMatch(inp.entries));
assert(inp.entries[0].interactionId > 0);
assert.strictEqual(inp.navigationType, 'discarded');
});

describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
if (!browserSupportsINP) this.skip();
Expand Down
24 changes: 24 additions & 0 deletions test/e2e/onLCP-test.js
Expand Up @@ -373,6 +373,30 @@ describe('onLCP()', async function() {
assert.strictEqual(lcp2.navigationType, 'back-forward-cache');
});

it('reports discarded as nav type for wasDiscarded', async function() {
if (!browserSupportsLCP) this.skip();

await browser.url('/test/lcp?wasDiscarded=1');

// Wait until all images are loaded and fully rendered.
await imagesPainted();

// Load a new page to trigger the hidden state.
await browser.url('about:blank');

await beaconCountIs(1);

const [lcp] = await getBeacons();

assert(lcp.value > 0); // Greater than the image load delay.
assert(lcp.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(lcp.name, 'LCP');
assert.strictEqual(lcp.value, lcp.delta);
assert.strictEqual(lcp.rating, 'good');
assert.strictEqual(lcp.entries.length, 1);
assert.strictEqual(lcp.navigationType, 'discarded');
});

describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
if (!browserSupportsLCP) this.skip();
Expand Down
18 changes: 18 additions & 0 deletions test/e2e/onTTFB-test.js
Expand Up @@ -209,6 +209,24 @@ describe('onTTFB()', async function() {
}
});

it('reports discarded as nav type for wasDiscarded', async function() {
await browser.url('/test/ttfb?wasDiscarded=1');

const ttfb = await getTTFBBeacon();

assert(ttfb.value >= 0);
assert(ttfb.value >= ttfb.entries[0].requestStart);
assert(ttfb.value <= ttfb.entries[0].loadEventEnd);
assert(ttfb.id.match(/^v3-\d+-\d+$/));
assert.strictEqual(ttfb.name, 'TTFB');
assert.strictEqual(ttfb.value, ttfb.delta);
assert.strictEqual(ttfb.rating, 'good');
assert.strictEqual(ttfb.navigationType, 'discarded');
assert.strictEqual(ttfb.entries.length, 1);

assertValidEntry(ttfb.entries[0]);
});

describe('attribution', function() {
it('includes attribution data on the metric object', async function() {
await browser.url('/test/ttfb?attribution=1');
Expand Down
20 changes: 20 additions & 0 deletions test/views/layout.njk
Expand Up @@ -100,6 +100,22 @@
});
}
/**
* @return {Promise<void>}
*/
self.__stubWasDiscarded = () => {
return new Promise((resolve) => {
const navEntry = performance.getEntriesByType('navigation')[0];
// Only stub if the page isn't actually discarded.
if (!document.wasDiscarded) {
Object.defineProperty(document, 'wasDiscarded', {
value: true,
configurable: true,
});
}
});
}
// Uncomment to stub running in a browser that doesn't support performance APIs
// (e.g. some version of Opera support this).
// delete self.performance;
Expand Down Expand Up @@ -131,6 +147,10 @@
if (params.has('prerender')) {
self.__stubPrerender();
}
if (params.has('wasDiscarded')) {
self.__stubWasDiscarded();
}
}());
</script>
{% if polyfill %}
Expand Down

0 comments on commit 2704ae1

Please sign in to comment.