Skip to content

Commit

Permalink
[bfcache] Add notRestoredReasons field in PerformanceNavigationTiming
Browse files Browse the repository at this point in the history
This CL adds back/forward cache not restored reasons in Performance
NavigationTiming API.
It's proposed here:
w3c/navigation-timing#171
Explainer: https://github.com/rubberyuzu/bfcache-not-retored-reason/blob/main/NotRestoredReason.md

This CL...
(main)
- exposes not restored reasons to PerformanceNavigationTiming API
- adds WPT
(sub/refactor)
- removes a flag from blink/common and adds one in RuntimeEnabled
- changes blocklisted features' report string to be short
- changes BackForwardCacheMetrics::UpdateNotRestoredReasonsForNavigation to also be called in SendCommitNavigation in addition to DidCommitNavigation, so that at the time of sending the reasons it will be a complete list.

Bug: 1349228
Change-Id: I8dd96a60188bdff94a21c4e4e34cacf181a823db
  • Loading branch information
Yuzu Saijo authored and chromium-wpt-export-bot committed Sep 15, 2022
1 parent d73231a commit 70cbb30
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 0 deletions.
Expand Up @@ -46,3 +46,40 @@ async function assertHeaderIsAsExpected(
return res.headers.get(headerName);
}, [headerName]), 'header is set');
}

async function assertNotRestoredReasonsEquals(
remoteContextHelper, blocked, url, src, id, name, reasons, children) {
let result = await remoteContextHelper.executeScript(() => {
return performance.getEntriesByType('navigation')[0].notRestoredReasons;
});
assertReasonsStructEquals(result, blocked, url, src, id, name, reasons, children);
}

function assertReasonsStructEquals(result, blocked, url, src, id, name, reasons, children) {
assert_equals(result.blocked, blocked);
assert_equals(result.url, url);
assert_equals(result.src, src);
assert_equals(result.id, id);
assert_equals(result.name, name);
// Reasons should match.
assert_equals(result.reasons.length, reasons.length);
reasons.sort();
result.reasons.sort();
for (let i=0; i<reasons.length; i++) {
assert_equals(result.reasons[i], reasons[i]);
}
// Children should match.
assert_equals(result.children.length, children.length);
children.sort();
result.children.sort();
for (let j=0; j<children.length; j++) {
assertReasonsStructEquals(result.children[0],
children[0].blocked,
children[0].url,
children[0].src,
children[0].id,
children[0].name,
children[0].reasons,
children[0].children);
}
}
@@ -0,0 +1,31 @@
// META: title=RemoteContextHelper navigation using BFCache
// META: script=/common/dispatcher/dispatcher.js
// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js

'use strict';

// Ensure that notRestoredReasons is empty for successful BFCache restore.
promise_test(async t => {
const rcHelper = new RemoteContextHelper();

// Open a window with noopener so that BFCache will work.
const rc1 = await rcHelper.addWindow(
/*config=*/ null, /*options=*/ {features: 'noopener'});

// Navigate away.
const rc2 = await rc1.navigateToNew();

// Navigate back.
await rc2.historyBack();

// Verify that no reasons are recorded for successful restore.
assert_true(await rc1.executeScript(() => {
let reasons = performance.getEntriesByType('navigation')[0].notRestoredReasons;
return reasons == null;
}));
});
@@ -0,0 +1,66 @@
// META: title=RemoteContextHelper navigation using BFCache
// META: script=/common/dispatcher/dispatcher.js
// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js

'use strict';

// Ensure that cross-origin subtree's reasons are not exposed to notRestoredReasons.
promise_test(async t => {
const rcHelper = new RemoteContextHelper();
// Open a window with noopener so that BFCache will work.
const rc1 = await rcHelper.addWindow(
/*config=*/ null, /*options=*/ {features: 'noopener'});
const rc1_url = await rc1.executeScript(() => {
return location.href;
});
// Add a cross-origin iframe and use BroadcastChannel.
const rc1_child = await rc1.addIframe(
/*extraConfig=*/ {
origin: 'HTTP_REMOTE_ORIGIN',
scripts: [],
headers: [],
},
/*attributes=*/ {id: 'test-id'},
);
await rc1_child.executeScript(() => {
window.bc = new BroadcastChannel('foo');
});
const rc1_child_url = await rc1_child.executeScript(() => {
return location.href;
});
// Add a child to the iframe.
const rc1_grand_child = await rc1_child.addIframe();
const rc1_grand_child_url = await rc1_grand_child.executeScript(() => {
return location.href;
});

// Navigate away.
const rc2 = await rc1.navigateToNew();

// Navigate back.
await rc2.historyBack();

// Check the reported reasons.
await assertNotRestoredReasonsEquals(
rc1,
/*blocked=*/false,
/*url=*/rc1_url,
/*src=*/ "",
/*id=*/"",
/*name=*/"",
/*reasons=*/[],
/*children=*/[{
"blocked": true,
"url": "",
"src": "",
"id": "",
"name": "",
"reasons": [],
"children": []
}]);
});
@@ -0,0 +1,41 @@
// META: title=RemoteContextHelper navigation using BFCache
// META: script=/common/dispatcher/dispatcher.js
// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js

'use strict';

// Ensure that notRestoredReasons is populated when not restored.
promise_test(async t => {
const rcHelper = new RemoteContextHelper();
// Open a window with noopener so that BFCache will work.
const rc1 = await rcHelper.addWindow(
/*config=*/ null, /*options=*/ {features: 'noopener'});

await rc1.executeScript((domain) => {
var ws = new WebSocket('ws://www.example.com/echo');
});
const rc1_url = await rc1.executeScript(() => {
return location.href;
});

// Navigate away.
const rc2 = await rc1.navigateToNew();

// Navigate back.
await rc2.historyBack();
// Check the reported reasons.
await assertNotRestoredReasonsEquals(
rc1,
/*blocked=*/true,
/*url=*/rc1_url,
/*src=*/ "",
/*id=*/"",
/*name=*/"",
/*reasons=*/["WebSocket"],
/*children=*/[]);
});
@@ -0,0 +1,69 @@
// META: title=RemoteContextHelper navigation using BFCache
// META: script=/common/dispatcher/dispatcher.js
// META: script=/common/get-host-info.sub.js
// META: script=/common/utils.js
// META: script=/resources/testharness.js
// META: script=/resources/testharnessreport.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js

'use strict';

// Ensure that same-origin subtree's reasons are exposed to notRestoredReasons.
promise_test(async t => {
const rcHelper = new RemoteContextHelper();
// Open a window with noopener so that BFCache will work.
const rc1 = await rcHelper.addWindow(
/*config=*/ null, /*options=*/ {features: 'noopener'});
const rc1_url = await rc1.executeScript(() => {
return location.href;
});
// Add a same-origin iframe and use BroadcastChannel.
const rc1_child = await rc1.addIframe(/*extra_config=*/{}, /*attributes=*/ {id: 'test-id'});
await rc1_child.executeScript(() => {
window.bc = new BroadcastChannel('foo');
});
const rc1_child_url = await rc1_child.executeScript(() => {
return location.href;
});
// Add a child to the iframe.
const rc1_grand_child = await rc1_child.addIframe();
const rc1_grand_child_url = await rc1_grand_child.executeScript(() => {
return location.href;
});

// Navigate away.
const rc2 = await rc1.navigateToNew();

// Navigate back.
await rc2.historyBack();

// Check the reported reasons.
await assertNotRestoredReasonsEquals(
rc1,
/*blocked=*/false,
/*url=*/rc1_url,
/*src=*/ "",
/*id=*/"",
/*name=*/"",
/*reasons=*/[],
/*children=*/[{
"blocked": true,
"url": rc1_child_url,
"src": rc1_child_url,
"id": "test-id",
"name": "",
"reasons": ["BroadcastChannel"],
"children": [
{
"blocked": false,
"url": rc1_grand_child_url,
"src": rc1_grand_child_url,
"id": "",
"name": "",
"reasons": [],
"children": []
}
]
}]);
});

0 comments on commit 70cbb30

Please sign in to comment.