Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NavigationActivation prototype #42873

Merged
merged 1 commit into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js"></script>
<script src="resources/is_uuid.js"></script>

<script>
// This test ensures that navigation.activation is properly updated when a page
// is restored from bfcache.
runBfcacheTest({
targetOrigin: originSameSite,
async funcAfterAssertion(pageA, pageB) {
const activationData = await pageA.execute_script(() => {
return { entryURL : navigation.activation.entry.url,
fromIsNull : navigation.activation.from === null,
navigationType : navigation.activation.navigationType }
});

// activation.entry should be the currently activated page, and
// activation.from should be omitted because it is a different origin.
assert_equals(activationData.entryURL, pageA.url);
assert_true(activationData.fromIsNull);
assert_equals(activationData.navigationType, "traverse");
}
}, "navigation.activation must be updated when restored from bfcache");
</script>
34 changes: 34 additions & 0 deletions navigation-api/navigation-activation/activation-after-bfcache.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js"></script>
<script src="resources/is_uuid.js"></script>

<script>
// This test ensures that navigation.activation is properly updated when a page
// is restored from bfcache.
runBfcacheTest({
targetOrigin: originSameOrigin,
async funcAfterAssertion(pageA, pageB) {
const activationData = await pageA.execute_script(() => {
return { entryURL : navigation.activation.entry.url,
fromURL : navigation.activation.from.url,
navigationType : navigation.activation.navigationType }
});

// activation.entry should be the currently activated page, and
// activation.from should be the page before restored from bfcache.
assert_equals(activationData.entryURL, pageA.url);
assert_equals(activationData.fromURL, pageB.url);
assert_equals(activationData.navigationType, "traverse");

const entryAndCurrentMatch = await pageA.execute_script(() => navigation.activation.entry === navigation.currentEntry);
assert_true(entryAndCurrentMatch);

const fromAndEntriesArrayMatch = await pageA.execute_script(() => navigation.activation.from === navigation.entries()[navigation.currentEntry.index + 1]);
assert_true(fromAndEntriesArrayMatch);
}
}, "navigation.activation must be updated when restored from bfcache");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

assert_equals(navigation.activation.entry, navigation.currentEntry);
let activationEntry = navigation.activation.entry;
let entryIndexBeforePush = activationEntry.index;
history.pushState("#fragment", "", "");
assert_not_equals(navigation.activation.entry, navigation.currentEntry);
assert_equals(navigation.activation.entry, activationEntry);
assert_equals(navigation.activation.entry.index, entryIndexBeforePush);
}, "navigation.activation.entry should not change due to history.pushState()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

assert_equals(navigation.activation.entry, navigation.currentEntry);
let activationEntry = navigation.activation.entry;
history.replaceState("#fragment", "", "");
assert_not_equals(navigation.activation.entry, navigation.currentEntry);
assert_equals(navigation.activation.entry, activationEntry);
assert_equals(navigation.activation.entry.index, -1);
}, "navigation.activation.entry should be orphaned by history.replaceState()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

assert_equals(i.contentWindow.navigation.activation, null);

i.contentWindow.navigation.navigate("/common/blank.html?a");
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry,
i.contentWindow.navigation.currentEntry);
assert_equals(i.contentWindow.navigation.activation.from.url, "about:blank");
assert_equals(i.contentWindow.navigation.activation.from.index, -1);
assert_equals(i.contentWindow.navigation.activation.navigationType, "replace");
}, "navigation.activation interaction with initial about:blank");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

let i = document.createElement("iframe");
i.src = get_host_info().HTTP_ORIGIN_WITH_DIFFERENT_PORT + "/common/blank.html";
document.body.appendChild(i);
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.location = "/common/blank.html";
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
let current_entry_after_nav = i.contentWindow.navigation.currentEntry;

assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.from, null);
assert_equals(i.contentWindow.navigation.activation.navigationType, "push");
}, "navigation.activation after push cross-origin");
</script>
30 changes: 30 additions & 0 deletions navigation-api/navigation-activation/activation-push.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.navigation.navigate("/common/blank.html?a");
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
let current_entry_after_nav = i.contentWindow.navigation.currentEntry;

assert_equals(i.contentWindow.navigation.entries().length, 2);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.from,
i.contentWindow.navigation.entries()[0]);
assert_equals(i.contentWindow.navigation.activation.navigationType, "push");

// Same-document navigation doesn't change navigation.activation.
await i.contentWindow.navigation.navigate("/common/blank.html?a#fragment").finished;

assert_equals(i.contentWindow.navigation.entries().length, 3);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.from,
i.contentWindow.navigation.entries()[0]);
assert_equals(i.contentWindow.navigation.activation.navigationType, "push");
}, "navigation.activation after push");
</script>
21 changes: 21 additions & 0 deletions navigation-api/navigation-activation/activation-reload.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.navigation.reload();
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

// activation.entry and activation.from are equal after reload
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry.index, 0);
assert_equals(i.contentWindow.navigation.activation.entry,
i.contentWindow.navigation.activation.from);
assert_equals(i.contentWindow.navigation.activation.navigationType, "reload");
}, "navigation.activation after reload");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

let i = document.createElement("iframe");
i.src = get_host_info().HTTP_ORIGIN_WITH_DIFFERENT_PORT + "/common/blank.html";
document.body.appendChild(i);
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.location.replace("/common/blank.html");
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
let current_entry_after_nav = i.contentWindow.navigation.currentEntry;

assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.from, null);
assert_equals(i.contentWindow.navigation.activation.navigationType, "replace");
}, "navigation.activation after replace cross-origin");
</script>
44 changes: 44 additions & 0 deletions navigation-api/navigation-activation/activation-replace.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

let before_key = i.contentWindow.navigation.currentEntry.key;
let before_id = i.contentWindow.navigation.currentEntry.id;
let before_url = i.contentWindow.navigation.currentEntry.url;
i.contentWindow.navigation.navigate("/common/blank.html?a", { history: "replace" });
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
let current_entry_after_nav = i.contentWindow.navigation.currentEntry;
let from_entry_after_nav = i.contentWindow.navigation.activation.from;

// activation.entry is the current entry. activation.from is a new
// NavigationHistoryEntry object (because there is a new window), with the
// same key/id/url as before the navigation, and an index of -1 because it is
// not present in the entries array.
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.entry.index, 0);
assert_equals(from_entry_after_nav.key, before_key);
assert_equals(from_entry_after_nav.id, before_id);
assert_equals(from_entry_after_nav.url, before_url);
assert_equals(from_entry_after_nav.index, -1);
assert_equals(i.contentWindow.navigation.activation.navigationType, "replace");

await i.contentWindow.navigation.navigate("/common/blank.html?a#fragment", { history: "replace" }).finished;

// activation.entry is no longer navigation.currentEntry and is disposed.
// activation.from has not changed.
assert_equals(i.contentWindow.navigation.entries().length, 1);
assert_equals(i.contentWindow.navigation.activation.entry, current_entry_after_nav);
assert_not_equals(i.contentWindow.navigation.activation.entry,
i.contentWindow.navigation.currentEntry);
assert_equals(i.contentWindow.navigation.activation.entry.index, -1);
assert_equals(i.contentWindow.navigation.activation.from, from_entry_after_nav);
assert_equals(i.contentWindow.navigation.activation.navigationType, "replace");
}, "navigation.activation after replace");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));
await i.contentWindow.navigation.navigate("/common/blank.html#fragment").finished;
assert_equals(i.contentWindow.navigation.entries().length, 2);

let urlAfterSameDoc = i.contentWindow.location.href;

i.contentWindow.navigation.navigate("/common/blank.html?a");
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
assert_equals(i.contentWindow.navigation.entries().length, 3);

assert_equals(i.contentWindow.navigation.activation.from,
i.contentWindow.navigation.entries()[1]);
assert_equals(i.contentWindow.navigation.activation.from.url, urlAfterSameDoc);
assert_equals(i.contentWindow.navigation.activation.navigationType, "push");
}, "navigation.activation same-document then cross-document");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script src="/common/get-host-info.sub.js"></script>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.location = get_host_info().HTTP_ORIGIN_WITH_DIFFERENT_PORT + "/common/blank.html";
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.location = get_host_info().HTTP_ORIGIN + "/common/blank.html";
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

// Go back to the first entry in the iframe. Because the navigation API only
// exposes same-origin *contiguous* entries, and there's a cross-origin entry
// in between, we have to use history.go().
history.go(-2);
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));
assert_equals(i.contentWindow.navigation.entries().length, 1);

// activation.from will be null because the entry that triggered the traversal
// is in a different same-origin contiguous region.
assert_equals(i.contentWindow.navigation.activation.entry, i.contentWindow.navigation.currentEntry);
assert_equals(i.contentWindow.navigation.activation.entry.index, 0);
assert_equals(i.contentWindow.navigation.activation.from, null);
assert_equals(i.contentWindow.navigation.activation.navigationType, "traverse");
}, "navigation.activation - traverse from a non-contiguous same-origin url");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));

i.contentWindow.navigation.navigate("/common/blank.html?a");
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

assert_equals(i.contentWindow.navigation.entries().length, 2);

i.contentWindow.navigation.back();
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0));

// activation.entry is the current entry. activation.from is the entry the
// traverse came from.
assert_equals(i.contentWindow.navigation.entries().length, 2);
assert_equals(i.contentWindow.navigation.activation.entry, i.contentWindow.navigation.currentEntry);
assert_equals(i.contentWindow.navigation.activation.entry.index, 0);
assert_equals(i.contentWindow.navigation.activation.from,
i.contentWindow.navigation.entries()[1]);
assert_equals(i.contentWindow.navigation.activation.navigationType, "traverse");

let from_key_before_push = i.contentWindow.navigation.activation.from.key;
let from_id_before_push = i.contentWindow.navigation.activation.from.id;
let from_url_before_push = i.contentWindow.navigation.activation.from.url;
await i.contentWindow.navigation.navigate("/common/blank.html#fragment").finished;

// pushing same document will not change activation.entry, but it will cut
// activation.from out of the entries array. Its parameters should not change
//except for its index, which becomes -1.
assert_equals(i.contentWindow.navigation.entries().length, 2);
assert_equals(i.contentWindow.navigation.activation.entry, i.contentWindow.navigation.entries()[0]);
assert_equals(i.contentWindow.navigation.activation.entry.index, 0);
assert_not_equals(i.contentWindow.navigation.activation.from,
i.contentWindow.navigation.entries()[1]);
assert_equals(i.contentWindow.navigation.activation.from.key, from_key_before_push);
assert_equals(i.contentWindow.navigation.activation.from.id, from_id_before_push);
assert_equals(i.contentWindow.navigation.activation.from.url, from_url_before_push);
assert_equals(i.contentWindow.navigation.activation.from.index, -1);
assert_equals(i.contentWindow.navigation.activation.navigationType, "traverse");
}, "navigation.activation - traverse, then push same-document");
</script>
Loading