Skip to content

Commit

Permalink
Tentative WPTs for overlapping navigations/traverals
Browse files Browse the repository at this point in the history
See whatwg/html#6927.

This will help app history which needs its own versions of these tests.

Change-Id: I84c67c6f23149d9c106f011ec13807d68d749633
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3067883
Reviewed-by: Nate Chapin <japhet@chromium.org>
Commit-Queue: Domenic Denicola <domenic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#909433}
  • Loading branch information
domenic authored and chromium-wpt-export-bot committed Aug 6, 2021
1 parent 5d84070 commit 50e80a2
Show file tree
Hide file tree
Showing 24 changed files with 1,506 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Overlapping navigation and traversal tests

While developing [app history](https://wicg.github.io/app-history/), @domenic
noticed that cancelation of navigations and history traversals is not very
well-defined in the spec.

On the spec side, this will probably be fixed as part of, or after, the
[session history rewrite](https://github.com/whatwg/html/pull/6315).

In the meantime, this directory contains tests which try to match most browsers,
or picks one of the potential behaviors.

<https://github.com/whatwg/html/issues/6927> discusses these results.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Cross-document navigation after a cross-document navigation</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
According to the spec, the navigate algorithm synchronously cancels ongoing
non-mature navigations.
-->

<body>
<script type="module">
import { createIframe, waitForLoad, waitForPotentialNetworkLoads } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);

iframe.contentWindow.location.search = "?1";
iframe.contentWindow.location.search = "?2";
assert_equals(iframe.contentWindow.location.search, "");

await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.search, "?2");

iframe.onload = t.unreached_func("second load event");
await waitForPotentialNetworkLoads(t);
assert_equals(iframe.contentWindow.location.search, "?2");
}, "cross-document navigation then cross-document navigation");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Cross-document traversal during cross-document navigation</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
According to the spec, "traverse the history by a delta" (e.g. history.back())
cancels any non-mature navigations.
-->

<body>
<script type="module">
import { createIframe, waitForLoad, delay } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);

// Setup
// Extra delay()s are necessary because if we navigate "inside" the load
// handler (i.e. in a promise reaction for the load handler) then it will
// be a replace navigation.
iframe.contentWindow.location.search = "?1";
await waitForLoad(iframe);
await delay(t, 0);
iframe.contentWindow.location.search = "?2";
await waitForLoad(iframe);
await delay(t, 0);

iframe.contentWindow.location.search = "?3";
iframe.contentWindow.history.back();

assert_equals(iframe.contentWindow.location.search, "?2", "must not go back synchronously");

await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.search, "?1", "must go back one step eventually");
}, "cross-document navigations are stopped by same-document back()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Cross-document navigation after a same-document navigation</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
According to the spec, the "URL and history update steps" (used by
pushState()) and the fragment navigation steps, both cancel any ongoing
history traversals, but do *not* cancel any ongoing navigations.
-->

<body>
<script type="module">
import { createIframe, waitForLoad } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);

iframe.contentWindow.location.search = "?1";
iframe.contentWindow.location.hash = "#2";

assert_equals(iframe.contentWindow.location.search, "");
assert_equals(iframe.contentWindow.location.hash, "#2");

await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.search, "?1");
assert_equals(iframe.contentWindow.location.hash, "");
}, "cross-document navigation then fragment navigation");

promise_test(async t => {
const iframe = await createIframe(t);

iframe.contentWindow.location.search = "?1";
iframe.contentWindow.history.pushState(null, "", "/2");

assert_equals(iframe.contentWindow.location.search, "");
assert_equals(iframe.contentWindow.location.pathname, "/2");

await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.search, "?1");
assert_equals(iframe.contentWindow.location.pathname, "/common/blank.html");
}, "cross-document navigation then pushState()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Same-document traversal during cross-document navigation</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
According to the spec, "traverse the history by a delta" (e.g. history.back())
cancels any non-mature navigations.
-->

<body>
<script type="module">
import { createIframe, delay } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);

// Setup
iframe.contentWindow.location.hash = "#1";
await delay(t, 0);
iframe.contentWindow.location.hash = "#2";
await delay(t, 0);

iframe.contentWindow.location.search = "?1";
iframe.contentWindow.onload = t.unreached_func("load event fired");

iframe.contentWindow.history.back();

assert_equals(iframe.contentWindow.location.search, "", "must not go back synchronously (search)");
assert_equals(iframe.contentWindow.location.hash, "#2", "must not go back synchronously (hash)");

// Does go back eventually, and only one step
await t.step_wait(() => iframe.contentWindow.location.hash === "#1" && iframe.contentWindow.location.search === "");
}, "cross-document navigations are stopped by same-document back()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Stop during cross-document navigations</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<body>
<script type="module">
import { createIframe, waitForPotentialNetworkLoads } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);

iframe.contentWindow.location.search = "?1";
iframe.contentWindow.onload = t.unreached_func("load event fired");
iframe.contentWindow.stop();

await waitForPotentialNetworkLoads(t);
assert_equals(iframe.contentWindow.location.search, "");
}, "cross-document navigations are stopped by stop()");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Cross-document navigations during cross-document traversals</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<!--
Apparently if a cross-document traversal is in progress, a cross-document
navigation just gets ignored. (Instead of, as you might expect, a race.)
This does not match the spec. This test instead asserts browser behavior.
-->

<body>
<script type="module">
import { createIframe, waitForLoad, delay, waitForPotentialNetworkLoads } from "./resources/helpers.mjs";

promise_test(async t => {
const iframe = await createIframe(t);
const slowURL = (new URL("resources/slow.py", location.href)).href;

// Setup
// Extra delay()s are necessary because if we navigate "inside" the load
// handler (i.e. in a promise reaction for the load handler) then it will
// be a replace navigation.
iframe.contentWindow.location.href = slowURL;
await waitForLoad(iframe);
await delay(t, 0);
iframe.contentWindow.location.href = "/common/blank.html?2";
await waitForLoad(iframe);
await delay(t, 0);

iframe.contentWindow.history.back();

assert_equals(iframe.contentWindow.location.search, "?2", "must not go back synchronously");

iframe.contentWindow.location.href = "/common/blank.html?3";
assert_equals(iframe.contentWindow.location.search, "?2", "must not navigate synchronously");

// We end up at slow.py and never at /common/blank.html?3
await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.href, slowURL, "first load after the nav");

await waitForPotentialNetworkLoads(t);
assert_equals(iframe.contentWindow.location.href, slowURL, "must stay on slow.py");
}, "slow cross-document traversal and then fast cross-document navigation: traversal wins and nav is ignored");

promise_test(async t => {
const iframe = await createIframe(t);
const slowURL = (new URL("resources/slow.py", location.href)).href;

// Setup
// Extra delay()s are necessary because if we navigate "inside" the load
// handler (i.e. in a promise reaction for the load handler) then it will
// be a replace navigation.
iframe.contentWindow.location.search = "?1";
await waitForLoad(iframe);
await delay(t, 0);
iframe.contentWindow.location.search = "?2";
await waitForLoad(iframe);
await delay(t, 0);

iframe.contentWindow.history.back();

assert_equals(iframe.contentWindow.location.search, "?2", "must not go back synchronously");

iframe.contentWindow.location.href = slowURL;
assert_equals(iframe.contentWindow.location.search, "?2", "must not navigate synchronously");

// We end up at ?1 and never at slowURL
await waitForLoad(iframe);
assert_equals(iframe.contentWindow.location.search, "?1", "first load after the nav");

// The long timeout is because slow.py would take 2 seconds, if it did load.
await delay(t, 3000);
assert_equals(iframe.contentWindow.location.search, "?1", "must stay on ?1");
}, "fast cross-document traversal and then slow cross-document navigation: traversal wins and nav is ignored");
</script>
Loading

0 comments on commit 50e80a2

Please sign in to comment.