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

Test using location API to navigate to the current hash #32291

Merged
merged 1 commit into from
Jan 12, 2022
Merged
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
101 changes: 101 additions & 0 deletions html/browsers/history/the-location-interface/same-hash.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Using the location interface to navigate to the same hash as the current one</title>
<link rel="help" href="https://github.com/whatwg/html/issues/7386">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<iframe id="i" srcdoc="<div style='height: 200vh'></div><div id='te&lt;st'></div>"></iframe>

<script type="module">
setup({ explicit_done: true });
await new Promise(r => window.onload = r);

for (const value of ["#te<st", "te<st", "#te%3Cst", "te%3Cst"]) {
promise_test(async t => {
t.add_cleanup(() => { i.contentWindow.location.hash = ""; });
assert_equals(i.contentWindow.scrollY, 0, "Setup: iframe starts at top");

i.contentWindow.location.hash = "te<st";
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "First hash assignment scrolls the iframe");

i.contentWindow.scroll({ top: 0, behavior: "instant" });
assert_equals(i.contentWindow.scrollY, 0, "Resetting the scroll position must work");

i.contentWindow.location.hash = value;
await delayForFragmentNavigationScrolling(t);

assert_equals(i.contentWindow.scrollY, 0, "Reassigning the same hash must not change the scroll position");
}, `Using location.hash = "${value}" must not reset scroll position`);
}

// These don't canonicalize to the current value of location.hash; the post-parsing version of
// "te<st" is "te%3Cst", uppercase.
Comment on lines +34 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

for (const value of ["#te%3cst", "te%3cst"]) {
promise_test(async t => {
t.add_cleanup(() => { i.contentWindow.location.hash = ""; });
assert_equals(i.contentWindow.scrollY, 0, "Setup: iframe starts at top");

i.contentWindow.location.hash = "te<st";
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "First hash assignment scrolls the iframe");

i.contentWindow.scroll({ top: 0, behavior: "instant" });
assert_equals(i.contentWindow.scrollY, 0, "Resetting the scroll position must work");

i.contentWindow.location.hash = value;
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "Reassigning the same-ish hash scrolls the iframe");
}, `Using location.hash = "${value}" must reset scroll position`);
}

for (const value of ["about:srcdoc#te<st", "about:srcdoc#te%3cst", "about:srcdoc#te%3Cst"]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this assumes you can navigate to about:srcdoc, but I don't think we have any allowance for that, do we? I think it ends up as a network error currently.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These iframes start on about:srcdoc (because I used a srcdoc iframe for the test), so this just causes a fragment navigation, which is allowed.

promise_test(async t => {
t.add_cleanup(() => { i.contentWindow.location.hash = ""; });
assert_equals(i.contentWindow.scrollY, 0, "Setup: iframe starts at top");

i.contentWindow.location.hash = "te<st";
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "First hash assignment scrolls the iframe");

i.contentWindow.scroll({ top: 0, behavior: "instant" });
assert_equals(i.contentWindow.scrollY, 0, "Resetting the scroll position must work");

i.contentWindow.location.href = value;
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "Setting href must scroll the iframe");
}, `Using location.href = "${value}" must reset scroll position`);

promise_test(async t => {
t.add_cleanup(() => { i.contentWindow.location.hash = ""; });
assert_equals(i.contentWindow.scrollY, 0, "Setup: iframe starts at top");

i.contentWindow.location.hash = "te<st";
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "First hash assignment scrolls the iframe");

i.contentWindow.scroll({ top: 0, behavior: "instant" });
assert_equals(i.contentWindow.scrollY, 0, "Resetting the scroll position must work");

i.contentWindow.location.assign(value);
await delayForFragmentNavigationScrolling(t);

assert_greater_than(i.contentWindow.scrollY, i.contentWindow.innerHeight, "Setting href must scroll the iframe");
}, `Using location.assign("${value}") must reset scroll position`);
}

function delayForFragmentNavigationScrolling(t) {
// Scroll behavior for fragment navigation is set to "auto" in the spec, so we can't guarantee it's instant.
// In practice 10 milliseconds seems to be enough.
return new Promise(r => t.step_timeout(r, 10));
}

done();
</script>