summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/navigation-api/navigate-event
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/navigation-api/navigate-event
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/navigation-api/navigate-event')
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-origin-traversal-does-not-fire-navigate.html25
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html41
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin.html30
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-sameorigin.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html41
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin.html39
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-sameorigin.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html34
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-sameorigin.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html34
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin.html32
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-sameorigin.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html35
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin.html24
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-sameorigin.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html35
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin.html33
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-sameorigin.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/cross-origin-iframe-helper.html28
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/document-domain-setter.sub.html3
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html41
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin.html30
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-sameorigin.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html41
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin.html39
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-sameorigin.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/event-constructor.html96
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-after-dispatch.html16
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-and-navigate.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-canceled-event.html17
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-document-same-origin.html21
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-origin.html18
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-detach-multiple.html18
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-detach.html17
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-null-or-undefined.html21
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-returns-non-promise.html18
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-throws.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-history-pushState.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-history-replaceState.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times-reject.html38
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times.html41
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-navigation-back.html19
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-on-synthetic-event.html17
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-popstate.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-reject.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-resolve.html20
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/intercept-same-document-history-back.html40
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-cross-origin.html24
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download-userInitiated.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download.html34
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-fragment.html25
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-same-origin-cross-document.html25
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-userInitiated.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-with-target.html31
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-back-forward.html26
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-navigate.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-reload.html25
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form-get.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form-reload.html28
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form-traverse.html44
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form-userInitiated.html30
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form-with-target.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-form.html25
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-fragment.html31
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-pushState.html31
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-cross-document.html32
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-go-0.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-pushState.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-history-replaceState.html29
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-iframe-location.html30
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-location.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-meta-refresh.html27
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-cross-document.html32
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-same-document.html32
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-navigate.html22
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-to-javascript.html18
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-to-srcdoc.html34
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open-self.html23
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open.html30
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-cross-document.html14
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-same-document.html10
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/resources/meta-refresh.html4
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/resources/navigatesuccess-cross-document-helper.html6
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/resources/opener-postMessage-onload.html6
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-detach-in-onnavigate.html21
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-intercept.html18
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-preventDefault.html19
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-after-intercept.html40
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-in-onnavigate.html24
-rw-r--r--testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop.html23
91 files changed, 2482 insertions, 0 deletions
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-origin-traversal-does-not-fire-navigate.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-origin-traversal-does-not-fire-navigate.html
new file mode 100644
index 0000000000..36491be22c
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-origin-traversal-does-not-fire-navigate.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../navigation-methods/return-value/resources/helpers.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+promise_test(async t => {
+ // Open a cross-origin window.
+ let w = window.open(get_host_info().HTTP_REMOTE_ORIGIN + "/navigation-api/navigate-event/resources/opener-postMessage-onload.html");
+ await new Promise(resolve => window.onmessage = resolve);
+
+ // Navigate the opened window to this origin.
+ w.location = get_host_info().ORIGIN + "/navigation-api/navigate-event/resources/opener-postMessage-onload.html";
+ await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(w.navigation.entries().length, 1);
+ assert_equals(w.navigation.currentEntry.index, 0);
+
+ // Go back. This should not fire a navigate event, because the traversal is
+ // cross-origin. Note that history.back() must be used instead of
+ // navigation.back() because navigation.back() can never go cross-origin.
+ w.navigation.onnavigate = t.unreached_func("navigate should not fire");
+ w.history.back();
+ await new Promise(resolve => window.onmessage = resolve);
+}, "A cross-origin traversal does not fire the navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..676672a230
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ url.search = "?foo";
+ const link = document.createElement("a");
+ link.href = url;
+ link.target = iframe.name;
+ document.body.append(link);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, link.href, "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ link.click();
+ });
+}, "clicking on an <a> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin.html
new file mode 100644
index 0000000000..2f40238912
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-crossorigin.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const url = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ url.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe");
+ iframe.src = url;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ url.search = "?postMessage-top-when-done";
+ const link = document.createElement("a");
+ link.href = url;
+ link.target = iframe.name;
+ document.body.append(link);
+
+ window.onmessage = t.step_func_done(e => {
+ // If we hit onnavigate in the target window, we'll get a different message, and fail.
+ assert_equals(e.data, "DONE");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => link.click());
+}, "clicking on an <a> element that navigates cross-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-sameorigin.html
new file mode 100644
index 0000000000..41c3ca71ee
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-crossdocument-sameorigin.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<a id="link" href="/common/blank.html?foo" target="windowname">Click me</a>
+<iframe id="i" name="windowname" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, link.href, "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ link.click();
+ });
+}, "clicking on an <a> element that navigates cross-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..a467ecf9d7
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ url.hash = "#foo";
+ const link = document.createElement("a");
+ link.href = url;
+ link.target = iframe.name;
+ document.body.append(link);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, link.href, "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ link.click();
+ });
+}, "clicking on an <a> element that navigates same-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin.html
new file mode 100644
index 0000000000..b9fa97f6d5
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-crossorigin.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const url = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ url.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe")
+ iframe.src = url;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ url.hash = "#foo";
+ const link = document.createElement("a");
+ link.href = url;
+ link.target = iframe.name;
+ document.body.append(link);
+
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.navigationType, "push", "navigationType");
+ assert_true(e.data.cancelable, "cancelable");
+ assert_true(e.data.canIntercept, "canIntercept");
+ assert_false(e.data.userInitiated, "userInitiated");
+ assert_true(e.data.hashChange, "hashChange");
+ assert_equals(e.data.formData, null, "formData");
+ assert_equals(e.data.destination.url, link.href, "destination.url");
+ assert_true(e.data.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.data.destination.key, null, "destination.key");
+ assert_equals(e.data.destination.id, null, "destination.id");
+ assert_equals(e.data.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => link.click());
+}, "clicking on an <a> element that navigates same-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-sameorigin.html
new file mode 100644
index 0000000000..566bea3dc7
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/click-samedocument-sameorigin.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<a id="link" href="/common/blank.html#foo" target="windowname">Click me</a>
+<iframe id="i" name="windowname" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, link.href, "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => link.click());
+}, "clicking on an <a> element that navigates same-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..77a5873c08
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.src = url;
+ document.body.append(iframe);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, iframe.src + "?foo", "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ iframe.contentWindow.location.href = url + "?foo";
+ });
+}, "using location.href to navigate cross-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin.html
new file mode 100644
index 0000000000..79df86fdc9
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-crossorigin.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const iframeURL = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ iframeURL.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe");
+ iframe.src = iframeURL;
+ document.body.append(iframe);
+
+ window.onmessage = t.step_func_done(e => {
+ // If we hit onnavigate in the target window, we'll get a different message, and fail.
+ assert_equals(e.data, "DONE");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => iframe.contentWindow.location.href = iframeURL + "?postMessage-top-when-done");
+}, "using location.href to navigate cross-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-sameorigin.html
new file mode 100644
index 0000000000..41ac1b0375
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-crossdocument-sameorigin.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe id="i" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, i.src + "?foo", "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => i.contentWindow.location.href = "/common/blank.html?foo");
+}, "using location.href to navigate cross-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..1eda74e982
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.src = url;
+ document.body.append(iframe);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, iframe.src + "#foo", "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ iframe.contentWindow.location.href = url + "#foo";
+ });
+}, "using location.href to navigate same-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin.html
new file mode 100644
index 0000000000..5679236a7d
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-crossorigin.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const iframeURL = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ iframeURL.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe")
+ iframe.src = iframeURL;
+ document.body.append(iframe);
+
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.navigationType, "push", "navigationType");
+ assert_true(e.data.cancelable, "cancelable");
+ assert_true(e.data.canIntercept, "canIntercept");
+ assert_false(e.data.userInitiated, "userInitiated");
+ assert_true(e.data.hashChange, "hashChange");
+ assert_equals(e.data.formData, null, "formData");
+ assert_equals(e.data.destination.url, iframe.src + "#foo", "destination.url");
+ assert_true(e.data.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.data.destination.key, null, "destination.key");
+ assert_equals(e.data.destination.id, null, "destination.id");
+ assert_equals(e.data.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => iframe.contentWindow.location.href = iframeURL + "#foo");
+}, "using location.href to navigate same-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-sameorigin.html
new file mode 100644
index 0000000000..a7e4181c3a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/location-samedocument-sameorigin.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe id="i" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, i.src + "#foo", "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => i.contentWindow.location.href = "/common/blank.html#foo");
+}, "using location.href to navigate same-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..ea9ea479c3
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, url + "?foo", "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ window.open(url + "?foo", iframe.name);
+ });
+}, "using window.open() to navigate cross-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin.html
new file mode 100644
index 0000000000..73ede89cbf
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-crossorigin.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const iframeURL = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ iframeURL.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe");
+ iframe.src = iframeURL;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ window.onmessage = t.step_func_done(e => {
+ // If we hit onnavigate in the target window, we'll get a different message, and fail.
+ assert_equals(e.data, "DONE");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => window.open(iframeURL + "?postMessage-top-when-done", "windowname"));
+}, "using window.open() to navigate cross-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-sameorigin.html
new file mode 100644
index 0000000000..478483e238
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-crossdocument-sameorigin.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe id="i" name="windowname" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, i.src + "?foo", "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => window.open("/common/blank.html?foo", "windowname"));
+}, "using window.open() to navigate cross-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..324adb32a4
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, url + "#foo", "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ window.open(url + "#foo", iframe.name);
+ });
+}, "using window.open() to navigate same-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin.html
new file mode 100644
index 0000000000..23dceb0420
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-crossorigin.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const iframeURL = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ iframeURL.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe")
+ iframe.src = iframeURL;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.navigationType, "push", "navigationType");
+ assert_true(e.data.cancelable, "cancelable");
+ assert_true(e.data.canIntercept, "canIntercept");
+ assert_false(e.data.userInitiated, "userInitiated");
+ assert_true(e.data.hashChange, "hashChange");
+ assert_equals(e.data.formData, null, "formData");
+ assert_equals(e.data.destination.url, iframe.src + "#foo", "destination.url");
+ assert_true(e.data.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.data.destination.key, null, "destination.key");
+ assert_equals(e.data.destination.id, null, "destination.id");
+ assert_equals(e.data.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => window.open(iframeURL + "#foo", "windowname"));
+}, "using window.open() to navigate same-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-sameorigin.html
new file mode 100644
index 0000000000..9ca8531803
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/open-samedocument-sameorigin.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe id="i" name="windowname" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, i.src + "#foo", "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => window.open("/common/blank.html#foo", "windowname"));
+}, "using window.open() to navigate same-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/cross-origin-iframe-helper.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/cross-origin-iframe-helper.html
new file mode 100644
index 0000000000..3393a2ecaa
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/cross-origin-iframe-helper.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script>
+navigation.onnavigate = e => {
+ const message = {
+ navigationType: e.navigationType,
+ cancelable: e.cancelable,
+ canIntercept: e.canIntercept,
+ userInitiated: e.userInitiated,
+ hashChange: e.hashChange,
+ formData: e.formData,
+ destination: {
+ url: e.destination.url,
+ sameDocument: e.destination.sameDocument,
+ key: e.destination.key,
+ id: e.destination.id,
+ index: e.destination.index
+ }
+ };
+ e.preventDefault();
+ top.postMessage(message, "*");
+};
+
+window.onload = () => {
+ if (location.href.includes("postMessage-top-when-done")) {
+ top.postMessage("DONE", "*");
+ }
+};
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/document-domain-setter.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/document-domain-setter.sub.html
new file mode 100644
index 0000000000..abe32ad8fb
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/resources/document-domain-setter.sub.html
@@ -0,0 +1,3 @@
+<script>
+document.domain = "{{host}}";
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..f611034617
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html?start", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ url.search = ""; // setting to "?" actually erases it anyway
+ const form = document.createElement("form");
+ form.action = url + "?";
+ form.target = iframe.name;
+ document.body.append(form);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, form.action, "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ form.submit();
+ });
+}, "submitting a <form> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin.html
new file mode 100644
index 0000000000..007f58b1fb
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-crossorigin.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const url = new URL("resources/cross-origin-iframe-helper.html", location.href);
+ url.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe")
+ iframe.src = url;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ const form = document.createElement("form");
+ form.action = url;
+ form.target = iframe.name;
+ form.innerHTML = `<input type="hidden" name="postMessage-top-when-done" value="yes">`;
+ document.body.append(form);
+
+ window.onmessage = t.step_func_done(e => {
+ // If we hit onnavigate in the target window, we'll get a different message, and fail.
+ assert_equals(e.data, "DONE");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => form.submit());
+}, "submitting a <form> element that navigates cross-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-sameorigin.html
new file mode 100644
index 0000000000..05347335a1
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-crossdocument-sameorigin.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<form id="form" action="/common/blank.html?" target="windowname"></form>
+<iframe id="i" name="windowname" src="/common/blank.html?start"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, form.action, "destination.url");
+ assert_false(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => form.submit());
+}, "submitting a <form> element that navigates cross-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html
new file mode 100644
index 0000000000..9e64a0124d
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin-sameorigindomain.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+
+<script>
+document.domain = "{{host}}";
+async_test(t => {
+ const url = new URL("resources/document-domain-setter.sub.html?", location.href);
+ url.hostname = "{{domains[www1]}}";
+ const iframe = document.createElement("iframe");
+ iframe.name = "windowname";
+ iframe.src = url;
+ document.body.append(iframe);
+
+ url.hash = "#foo";
+ const form = document.createElement("form");
+ form.action = url;
+ form.target = iframe.name;
+ document.body.append(form);
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, form.action, "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ form.submit();
+ });
+}, "submitting a <form> element that navigates cross-document targeting a same-origin-domain (but cross-origin) window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin.html
new file mode 100644
index 0000000000..e53a1f93e7
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-crossorigin.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+
+<script>
+async_test(t => {
+ const url = new URL("resources/cross-origin-iframe-helper.html?", location.href);
+ url.hostname = get_host_info().REMOTE_HOST;
+ const iframe = document.createElement("iframe")
+ iframe.src = url;
+ iframe.name = "windowname";
+ document.body.append(iframe);
+
+ url.hash = "#foo";
+ const form = document.createElement("form");
+ form.action = url;
+ form.target = iframe.name;
+ document.body.append(form);
+
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.navigationType, "push", "navigationType");
+ assert_true(e.data.cancelable, "cancelable");
+ assert_true(e.data.canIntercept, "canIntercept");
+ assert_false(e.data.userInitiated, "userInitiated");
+ assert_true(e.data.hashChange, "hashChange");
+ assert_equals(e.data.formData, null, "formData");
+ assert_equals(e.data.destination.url, form.action, "destination.url");
+ assert_true(e.data.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.data.destination.key, null, "destination.key");
+ assert_equals(e.data.destination.id, null, "destination.id");
+ assert_equals(e.data.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => form.submit());
+}, "submitting a <form> element that navigates same-document targeting a cross-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-sameorigin.html b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-sameorigin.html
new file mode 100644
index 0000000000..43aa3226fc
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/cross-window/submit-samedocument-sameorigin.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<form id="form" action="/common/blank.html?#foo" target="windowname"></form>
+<iframe id="i" name="windowname" src="/common/blank.html?"></iframe>
+
+<script>
+async_test(t => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push", "navigationType");
+ assert_true(e.cancelable, "cancelable");
+ assert_true(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_true(e.hashChange, "hashChange");
+ assert_equals(e.formData, null, "formData");
+ assert_equals(e.destination.url, form.action, "destination.url");
+ assert_true(e.destination.sameDocument, "destination.sameDocument");
+ assert_equals(e.destination.key, null, "destination.key");
+ assert_equals(e.destination.id, null, "destination.id");
+ assert_equals(e.destination.index, -1, "destination.index");
+ });
+
+ navigation.onnavigate = t.unreached_func("onnavigate must not fire in the source window");
+ window.onload = t.step_func(() => form.submit());
+}, "submitting a <form> element that navigates same-document targeting a same-origin window");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/event-constructor.html b/testing/web-platform/tests/navigation-api/navigate-event/event-constructor.html
new file mode 100644
index 0000000000..065884240e
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/event-constructor.html
@@ -0,0 +1,96 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new NavigateEvent("navigate");
+ });
+}, "can't bypass required members by omitting the dictionary entirely");
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new NavigateEvent("navigate", {
+ navigationType: "push",
+ canIntercept: false,
+ userInitiated: false,
+ hashChange: false,
+ signal: (new AbortController()).signal,
+ formData: null,
+ downloadRequest: null,
+ info: null
+ });
+ });
+}, "destination is required");
+
+async_test(t => {
+ // We need to grab an NavigationDestination.
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_throws_js(TypeError, () => {
+ new NavigateEvent("navigate", {
+ navigationType: "push",
+ destination: e.destination,
+ canIntercept: false,
+ userInitiated: false,
+ hashChange: false,
+ formData: null,
+ downloadRequest: null,
+ info: null
+ });
+ });
+ });
+ history.pushState(1, null, "#1");
+}, "signal is required");
+
+async_test(t => {
+ // We need to grab an NavigationDestination.
+ navigation.onnavigate = t.step_func_done(e => {
+ const info = { some: "object with identity" };
+ const formData = new FormData();
+ const signal = (new AbortController()).signal;
+ const downloadRequest = "abc";
+
+ const event = new NavigateEvent("navigate", {
+ navigationType: "replace",
+ destination: e.destination,
+ canIntercept: true,
+ userInitiated: true,
+ hashChange: true,
+ signal,
+ formData,
+ downloadRequest,
+ info
+ });
+
+ assert_equals(event.navigationType, "replace");
+ assert_equals(event.destination, e.destination);
+ assert_equals(event.canIntercept, true);
+ assert_equals(event.userInitiated, true);
+ assert_equals(event.hashChange, true);
+ assert_equals(event.signal, signal);
+ assert_equals(event.formData, formData);
+ assert_equals(event.downloadRequest, downloadRequest);
+ assert_equals(event.info, info);
+ });
+ history.pushState(2, null, "#2");
+}, "all properties are reflected back");
+
+async_test(t => {
+ // We need to grab an NavigationDestination.
+ navigation.onnavigate = t.step_func_done(e => {
+ const event = new NavigateEvent("navigate", {
+ destination: e.destination,
+ signal: (new AbortController()).signal
+ });
+
+ assert_equals(event.navigationType, "push");
+ assert_equals(event.canIntercept, false);
+ assert_equals(event.userInitiated, false);
+ assert_equals(event.hashChange, false);
+ assert_equals(event.formData, null);
+ assert_equals(event.downloadRequest, null);
+ assert_equals(event.info, undefined);
+ });
+ history.pushState(3, null, "#3");
+}, "defaults are as expected");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-after-dispatch.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-after-dispatch.html
new file mode 100644
index 0000000000..abb328050d
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-after-dispatch.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func(e => {
+ t.step_timeout(t.step_func_done(() => {
+ assert_equals(e.eventPhase, Event.NONE);
+ assert_throws_dom("InvalidStateError", () => e.intercept());
+ }), 0);
+ });
+
+ location.href = "#1";
+}, "event.intercept() throws if used after the dispatch phase");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-and-navigate.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-and-navigate.html
new file mode 100644
index 0000000000..dfbb67b6b6
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-and-navigate.html
@@ -0,0 +1,27 @@
+<!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(r => window.onload = () => t.step_timeout(r, 0));
+ await navigation.navigate("#1").finished;
+
+ navigation.onnavigate = e => e.intercept();
+ navigation.oncurrententrychange = e => {
+ if (e.navigationType == "traverse") {
+ assert_equals(location.hash, "");
+ assert_equals(navigation.currentEntry.index, 0);
+ assert_equals(navigation.entries().length, 2);
+ navigation.navigate("#2");
+ }
+ };
+ let back_result = navigation.back();
+ await back_result.committed;
+ assert_equals(location.hash, "#2");
+ await promise_rejects_dom(t, "AbortError", back_result.finished);
+ assert_equals(navigation.currentEntry.index, 1);
+ assert_equals(navigation.entries().length, 2);
+}, "Using intercept() then navigate() in the ensuing currententrychange should abort the finished promise (but not the committed promise)");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-canceled-event.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-canceled-event.html
new file mode 100644
index 0000000000..d4b9633c1a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-canceled-event.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+test(t => {
+ let assertionHappened = false;
+ navigation.onnavigate = t.step_func_done(e => {
+ e.preventDefault();
+ assert_throws_dom("InvalidStateError", () => e.intercept());
+ assertionHappened = true;
+ });
+
+ location.href = "#1";
+ assert_true(assertionHappened);
+}, "event.intercept() throws if used on a canceled event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-document-same-origin.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-document-same-origin.html
new file mode 100644
index 0000000000..0d610cce4f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-document-same-origin.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+async_test(t => {
+ let target_url = location.href + "?1";
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ e.intercept({ handler: async () => {
+ await Promise.resolve();
+ t.step_func_done(() => assert_equals(location.href, target_url));
+ }});
+ });
+
+ window.onload = t.step_func(() => location.href = target_url);
+}, "event.intercept() intercepts a same-origin cross-document navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-origin.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-origin.html
new file mode 100644
index 0000000000..b367df546c
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-cross-origin.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_true(e.cancelable);
+ assert_false(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_throws_dom("SecurityError", () => e.intercept());
+ e.preventDefault();
+ });
+
+ window.onload = t.step_func(() => location.href = get_host_info().HTTPS_REMOTE_ORIGIN);
+}, "event.intercept() should throw if called for a cross origin navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach-multiple.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach-multiple.html
new file mode 100644
index 0000000000..5b6a623284
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach-multiple.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ let second_handler_run = false;
+ i.contentWindow.navigation.onnavigate = e => {
+ e.intercept({ handler() { i.remove(); }});
+ e.intercept({ handler() { second_handler_run = true; }});
+ };
+
+ i.contentWindow.location.href = "#1";
+ t.step_timeout(t.step_func_done(() => assert_true(second_handler_run)), 0);
+ });
+}, "event.intercept() throws if used on an event from a detached iframe");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach.html
new file mode 100644
index 0000000000..b5ce45aa29
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-detach.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ let iframe_constructor = i.contentWindow.DOMException;
+ i.remove();
+ assert_throws_dom("InvalidStateError", iframe_constructor, () => e.intercept());
+ });
+
+ i.contentWindow.location.href = "#1";
+ });
+}, "event.intercept() throws if used on an event from a detached iframe");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-null-or-undefined.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-null-or-undefined.html
new file mode 100644
index 0000000000..7f5bd6b19f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-null-or-undefined.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_throws_js(TypeError, () => e.intercept({ handler: null }));
+ });
+
+ location.href = "#1";
+ assert_equals(location.hash, "#1");
+}, "event.intercept() should throw if the handler is null");
+
+async_test(t => {
+ navigation.onnavigatesuccess = t.step_func_done(e => {});
+ navigation.onnavigate = e => e.intercept({ handler: undefined });
+
+ location.href = "#2";
+ assert_equals(location.hash, "#2");
+}, "event.intercept() should not throw if the handler is explicit undefined");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-returns-non-promise.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-returns-non-promise.html
new file mode 100644
index 0000000000..96116e9295
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-returns-non-promise.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigatesuccess = t.step_func_done(e => {
+ assert_equals(location.hash, "#1");
+ assert_equals(e.constructor, Event);
+ assert_false(e.bubbles);
+ assert_false(e.cancelable);
+ });
+ navigation.onnavigateerror = t.step_func_done(assert_unreached);
+ navigation.onnavigate = e => e.intercept({ handler() { return "123"; }});
+
+ location.href = "#1";
+ assert_equals(location.hash, "#1");
+}, "event.intercept() should resolve immediately if the handler doesn't return a promise");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-throws.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-throws.html
new file mode 100644
index 0000000000..769f675999
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-handler-throws.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const err = new TypeError("a message");
+ let start_href = location.href;
+
+ navigation.onnavigatesuccess = t.step_func_done(assert_unreached);
+ navigation.onnavigateerror = t.step_func_done(e => {
+ assert_equals(location.hash, "#1");
+ assert_equals(e.constructor, ErrorEvent);
+ assert_true(e.error === err);
+ assert_equals(e.message, "Uncaught TypeError: a message");
+ assert_equals(e.filename, start_href);
+ assert_greater_than(e.colno, 0);
+ assert_greater_than(e.lineno, 0);
+ });
+ navigation.onnavigate = e => {
+ e.intercept({ handler() { throw err; }});
+ };
+
+ location.href = "#1";
+ assert_equals(location.hash, "#1");
+}, "event.intercept() should abort if the handler throws");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-pushState.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-pushState.html
new file mode 100644
index 0000000000..aad08b742e
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-pushState.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ let start_length = history.length;
+ navigation.onnavigate = t.step_func(e => {
+ e.intercept({ handler: async () => {
+ await new Promise(r => t.step_timeout(r, 0));
+ t.step_timeout(t.step_func_done(() => {
+ assert_equals(location.hash, "#1");
+ assert_equals(history.state, "update");
+ assert_equals(history.length, start_length + 1);
+ }, 0));
+ }});
+ });
+
+ history.pushState("update", "", "#1");
+ assert_equals(location.hash, "#1");
+ assert_equals(history.state, "update");
+ assert_equals(history.length, start_length + 1);
+}, "event.intercept() should proceed if the given promise resolves");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-replaceState.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-replaceState.html
new file mode 100644
index 0000000000..16edec8596
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-history-replaceState.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ let start_length = history.length;
+ navigation.onnavigate = t.step_func(e => {
+ e.intercept({ handler: async () => {
+ await new Promise(r => t.step_timeout(r, 0));
+ t.step_timeout(t.step_func_done(() => {
+ assert_equals(location.hash, "#1");
+ assert_equals(history.state, "update");
+ assert_equals(history.length, start_length);
+ }, 0));
+ }});
+ });
+
+ history.replaceState("update", "", "#1");
+ assert_equals(location.hash, "#1");
+ assert_equals(history.state, "update");
+ assert_equals(history.length, start_length);
+}, "event.intercept() should proceed if the given promise resolves");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times-reject.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times-reject.html
new file mode 100644
index 0000000000..0b0f1f0b8e
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times-reject.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async t => {
+ const err = new TypeError("a message");
+ let start_href = location.href;
+
+ let onnavigateerror_called = false;
+ let caught_rejection = false;
+ navigation.onnavigatesuccess = t.step_func(assert_unreached);
+ navigation.onnavigateerror = t.step_func(e => {
+ onnavigateerror_called = true;
+ assert_equals(location.hash, "#1");
+ assert_equals(e.constructor, ErrorEvent);
+ assert_equals(e.error, err);
+ assert_equals(e.message, "Uncaught TypeError: a message");
+ assert_equals(e.filename, start_href);
+ assert_greater_than(e.colno, 0);
+ assert_greater_than(e.lineno, 0);
+ });
+ navigation.onnavigate = t.step_func(e => {
+ e.intercept();
+ e.intercept({ handler: async () => {
+ await new Promise(r => t.step_timeout(r, 1));
+ return Promise.reject(err);
+ }});
+ e.intercept({ handler: () => new Promise(resolve => t.step_timeout(resolve, 1)) });
+ });
+
+ await navigation.navigate("#1").finished.catch(t.step_func(e => {
+ caught_rejection = true;
+ assert_equals(e, err);
+ }));
+ assert_true(onnavigateerror_called);
+ assert_true(caught_rejection);
+}, "event.intercept() is called multiple times and one of the promises rejects");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times.html
new file mode 100644
index 0000000000..6deaeeb507
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-multiple-times.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async t => {
+ let p1_resolved = false;
+ let p2_resolved = false;
+ let p3_resolved = false;
+ navigation.onnavigate = t.step_func(e => {
+ e.intercept({ handler: async () => {
+ await Promise.resolve();
+ assert_false(p2_resolved);
+ assert_false(p3_resolved);
+ p1_resolved = true;
+ }});
+ e.intercept({ handler: async () => {
+ await new Promise(resolve => t.step_timeout(resolve, 1));
+ assert_true(p1_resolved);
+ assert_false(p3_resolved);
+ p2_resolved = true;
+ }});
+ e.intercept({ handler: async () => {
+ await new Promise(resolve => t.step_timeout(resolve, 1));
+ assert_true(p1_resolved);
+ assert_true(p2_resolved);
+ p3_resolved = true;
+ }});
+ });
+
+ let promise = navigation.navigate("#1").finished;
+ assert_equals(location.hash, "#1");
+ assert_false(p1_resolved);
+ assert_false(p2_resolved);
+ assert_false(p3_resolved);
+
+ await promise;
+ assert_true(p1_resolved);
+ assert_true(p2_resolved);
+ assert_true(p3_resolved);
+}, "navigation.navigate() returns a finished promise that awaits all promises if event.intercept() is called multiple times");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-navigation-back.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-navigation-back.html
new file mode 100644
index 0000000000..8babf2bcdc
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-navigation-back.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(() => {
+ navigation.navigate("#foo").committed.then(() => {
+ assert_true(navigation.canGoBack);
+ navigation.onnavigate = t.step_func(e => e.intercept());
+ navigation.back().committed.then(t.step_func_done(() => {
+ assert_equals(navigation.entries().length, 2);
+ assert_equals(navigation.currentEntry, navigation.entries()[0]);
+ }));
+ });
+ }, 0);
+}, "event.intercept() can intercept navigation.back()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-on-synthetic-event.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-on-synthetic-event.html
new file mode 100644
index 0000000000..3a4b54de5e
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-on-synthetic-event.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // We need to grab an NavigationDestination to construct the event.
+ navigation.onnavigate = t.step_func_done(e => {
+ const event = new NavigateEvent("navigate", {
+ destination: e.destination,
+ signal: (new AbortController()).signal
+ });
+
+ assert_throws_dom("SecurityError", () => event.intercept());
+ });
+ history.pushState(1, null, "#1");
+}, "event.intercept() throws if invoked on a synthetic event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-popstate.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-popstate.html
new file mode 100644
index 0000000000..f5f9d82be7
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-popstate.html
@@ -0,0 +1,26 @@
+<!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));
+ history.replaceState({ state: "foo"}, "", "#replace");
+
+ let onpopstate_fired = false;
+ let last_state;
+ window.onpopstate = e => {
+ onpopstate_fired = true;
+ last_state = e.state;
+ }
+ navigation.onnavigate = t.step_func(e => e.intercept());
+
+ await navigation.navigate("#").finished;
+ assert_true(navigation.canGoBack);
+
+ await navigation.back().finished;
+ assert_true(onpopstate_fired);
+ assert_not_equals(last_state, null);
+}, "event.intercept() should provide popstate with a valid state object");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-reject.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-reject.html
new file mode 100644
index 0000000000..4c5ec0163d
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-reject.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ const err = new TypeError("a message");
+ let start_href = location.href;
+
+ navigation.onnavigatesuccess = t.step_func_done(assert_unreached);
+ navigation.onnavigateerror = t.step_func_done(e => {
+ assert_equals(location.hash, "#1");
+ assert_equals(e.constructor, ErrorEvent);
+ assert_true(e.error === err);
+ assert_equals(e.message, "Uncaught TypeError: a message");
+ assert_equals(e.filename, start_href);
+ assert_greater_than(e.colno, 0);
+ assert_greater_than(e.lineno, 0);
+ });
+ navigation.onnavigate = e => {
+ e.intercept({ handler: async () => {
+ await new Promise(r => t.step_timeout(r, 0));
+ return Promise.reject(err);
+ }});
+ };
+
+ location.href = "#1";
+ assert_equals(location.hash, "#1");
+}, "event.intercept() should abort if the given promise rejects");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-resolve.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-resolve.html
new file mode 100644
index 0000000000..b60d89b5df
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-resolve.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigatesuccess = t.step_func_done(e => {
+ assert_equals(location.hash, "#1");
+ assert_equals(e.constructor, Event);
+ assert_false(e.bubbles);
+ assert_false(e.cancelable);
+ });
+ navigation.onnavigateerror = t.step_func_done(assert_unreached);
+ navigation.onnavigate = e => {
+ e.intercept({ handler: () => new Promise(resolve => t.step_timeout(resolve, 0)) });
+ };
+
+ location.href = "#1";
+ assert_equals(location.hash, "#1");
+}, "event.intercept() should proceed if the given promise resolves");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/intercept-same-document-history-back.html b/testing/web-platform/tests/navigation-api/navigate-event/intercept-same-document-history-back.html
new file mode 100644
index 0000000000..6faabe1964
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/intercept-same-document-history-back.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(() => {
+ let onnavigate_calls = 0;
+ let onnavigatesuccess_calls = 0;
+ navigation.onnavigate = e => {
+ onnavigate_calls++;
+ e.intercept();
+ }
+ navigation.onnavigatesuccess = t.step_func(e => {
+ onnavigatesuccess_calls++;
+ if (onnavigatesuccess_calls == 3) {
+ assert_equals(navigation.entries().length, 3);
+ assert_equals(navigation.currentEntry.index, 1);
+ assert_equals(onnavigate_calls, 3);
+ history.back();
+ } else if (onnavigatesuccess_calls == 4) {
+ assert_equals(navigation.entries().length, 3);
+ assert_equals(navigation.currentEntry.index, 0);
+ assert_equals(onnavigate_calls, 4);
+ t.done();
+ }
+ });
+
+ navigation.navigate("?foo").finished
+ .then(t.step_func(() => navigation.navigate("?bar").finished))
+ .then(t.step_func(() => {
+ assert_equals(navigation.entries().length, 3);
+ assert_equals(navigation.currentEntry.index, 2);
+ assert_equals(onnavigate_calls, 2);
+ history.back();
+ }));
+ }, 0);
+}, "event.intercept() can intercept same-document history.back()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-cross-origin.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-cross-origin.html
new file mode 100644
index 0000000000..d8f2e38312
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-cross-origin.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<a id="a" href="https://does-not-exist/foo.html"></a>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_false(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.formData, null);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, "https://does-not-exist/foo.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ });
+ a.click();
+}, "<a> cross-origin navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download-userInitiated.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download-userInitiated.html
new file mode 100644
index 0000000000..90a612b758
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download-userInitiated.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<a id="a" href="?1">Click me</a>
+<script>
+async_test(t => {
+ a.download = "";
+ navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_true(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, "");
+ assert_equals(e.formData, null);
+ assert_equals(new URL(e.destination.url).search, "?1");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => assert_equals(location.hash, "")), 0);
+ });
+ test_driver.click(a);
+}, "<a download> click fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download.html
new file mode 100644
index 0000000000..c5ca306b79
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-download.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const tests = [["a", ""], ["a", "filename"], ["area", ""], ["area", "filename"]];
+
+for (const [tag, download_attr] of tests) {
+ async_test(t => {
+ let a = document.createElement(tag);
+ a.href = "foo.html";
+ a.download = download_attr;
+ document.body.appendChild(a);
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, download_attr);
+ assert_equals(e.formData, null);
+ assert_equals(new URL(e.destination.url).pathname,
+ "/navigation-api/navigate-event/foo.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ });
+ a.click();
+ }, `<${tag}> fires navigate and populates downloadRequest with '${download_attr}'`);
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-fragment.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-fragment.html
new file mode 100644
index 0000000000..b7706b7deb
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-fragment.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<a id="a" href="#1"></a>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.formData, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => assert_equals(location.hash, "")), 0);
+ });
+ a.click();
+}, "Fragment <a> click fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-same-origin-cross-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-same-origin-cross-document.html
new file mode 100644
index 0000000000..b8e925a4db
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-same-origin-cross-document.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<a id="a" href="foo.html"></a>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.formData, null);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname,
+ "/navigation-api/navigate-event/foo.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ });
+ a.click();
+}, "<a> cross-document (but same-origin) navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-userInitiated.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-userInitiated.html
new file mode 100644
index 0000000000..b746bbe3f0
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-userInitiated.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<a id="a" href="#1">Click me</a>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_true(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.formData, null);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => assert_equals(location.hash, "")), 0);
+ });
+
+ test_driver.click(a);
+}, "Fragment <a> click fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-with-target.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-with-target.html
new file mode 100644
index 0000000000..c2053a37b0
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-anchor-with-target.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+<a id="a" href="foo.html" target="i"></a>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(() => {
+ assert_unreached("onnavigate should not have fired in source window");
+ });
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.formData, null);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname,
+ "/navigation-api/navigate-event/foo.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.preventDefault();
+ });
+ a.click();
+ });
+}, "<a> with a target fires navigate event in target window but not source");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-back-forward.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-back-forward.html
new file mode 100644
index 0000000000..c118aa7a1f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-back-forward.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(t.step_func_done(() => {
+ let navState = { statevar: "state" };
+ navigation.navigate("#foo", { history: "replace", state: navState });
+ let target_key = navigation.currentEntry.key;
+ let target_id = navigation.currentEntry.id;
+ navigation.navigate("#bar");
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_not_equals(e.destination, null);
+ assert_not_equals(e.destination.getState(), undefined);
+ assert_not_equals(e.destination.getState(), e.destination.getState());
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ });
+ navigation.back();
+ }), 0);
+}, "navigate event destination.getState() on back/forward navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-navigate.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-navigate.html
new file mode 100644
index 0000000000..9c34c5753a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-navigate.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(() => {
+ let navState = { statevar: "state" };
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_not_equals(e.destination, null);
+ assert_not_equals(e.destination.getState(), undefined);
+ assert_equals(e.destination.getState().statevar, "state");
+ assert_not_equals(e.destination.getState(), e.destination.getState());
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ });
+ navigation.navigate("#foo", { state: navState });
+ }, 0);
+}, "navigate event destination.getState() should be the state given to navigate()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-reload.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-reload.html
new file mode 100644
index 0000000000..b3afb72482
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-destination-getState-reload.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(() => {
+ let navState = { statevar: "state" };
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "reload");
+ assert_not_equals(e.destination, null);
+ assert_not_equals(e.destination.getState(), undefined);
+ assert_equals(e.destination.getState().statevar, "state");
+ assert_not_equals(e.destination.getState(), e.destination.getState());
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ e.intercept();
+ });
+ navigation.updateCurrentEntry({ state: navState });
+ location.reload();
+ }, 0);
+}, "navigate event destination.getState() on location.reload()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-get.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-get.html
new file mode 100644
index 0000000000..69a49eb08a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-get.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<form id="form" action=""></form>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ e.preventDefault();
+
+ assert_equals(e.navigationType, "replace");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, location.href + "?");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+
+ // Because it's a GET, not a POST
+ assert_equals(e.formData, null);
+ });
+ window.onload = t.step_func(() => form.submit());
+}, "<form> submission with GET method fires navigate event but with formData null");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-reload.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-reload.html
new file mode 100644
index 0000000000..f18a11ebda
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-reload.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+<form id="form" action="/common/blank.html?1" method="post" target="i"></form>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(() => {
+ assert_unreached("onnavigate should not have fired in source window");
+ });
+ iframe.contentWindow.navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_not_equals(e.formData, null);
+
+ iframe.onload = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "reload");
+ assert_equals(e.formData, null);
+ });
+
+ iframe.contentWindow.location.reload();
+ });
+ });
+ form.submit();
+ });
+}, "reloading a page created from form submission results in formData of null, not the original form data");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-traverse.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-traverse.html
new file mode 100644
index 0000000000..d673537503
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-traverse.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+<form id="form" action="/common/blank.html?1" method="post" target="i"></form>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(() => {
+ assert_unreached("onnavigate should not have fired in source window");
+ });
+ iframe.contentWindow.navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_not_equals(e.formData, null);
+
+ iframe.onload = t.step_func(() => {
+ // Avoid the replace behavior that occurs if you navigate during the load handler
+ t.step_timeout(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_equals(e.formData, null);
+ });
+
+ iframe.contentWindow.onhashchange = t.step_func(() => {
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_equals(e.formData, null);
+ });
+
+ // 3: go back
+ iframe.contentWindow.history.back();
+ });
+
+ // 2: navigate from /common/blank.html?1-with-form-data to /common/blank.html?1#1-with-form-data
+ iframe.contentWindow.location.hash = "#1";
+ }, 0);
+ });
+ });
+
+ // 1: submit the form, navigating from /common/blank.html to /common/blank.html?1-with-form-data
+ form.submit();
+ });
+}, "reloading a page created from form submission results in formData of null, not the original form data");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-userInitiated.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-userInitiated.html
new file mode 100644
index 0000000000..454f077396
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-userInitiated.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<form id="form" method="post" action="">
+<input id="submit" type="submit" value="Submit">
+</form>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ e.preventDefault();
+
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_true(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, location.href);
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_not_equals(e.formData, null);
+ });
+ window.onload = t.step_func(() => test_driver.click(submit));
+}, "<form> submission fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-with-target.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-with-target.html
new file mode 100644
index 0000000000..b23ab3a70c
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form-with-target.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+<form id="form" method="post" action="foo.html" target="i"></form>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.unreached_func("onnavigate should not have fired in source window");
+
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname,
+ "/navigation-api/navigate-event/foo.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_not_equals(e.formData, null);
+ });
+ form.submit();
+ });
+}, "<form> submission with a target fires navigate event in target window but not source");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-form.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form.html
new file mode 100644
index 0000000000..b537a9b58f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-form.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<form id="form" method="post" action=""></form>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ e.preventDefault();
+
+ assert_equals(e.navigationType, "replace");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, location.href);
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_not_equals(e.formData, null);
+ });
+ window.onload = t.step_func(() => form.submit());
+}, "<form> submission fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-fragment.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-fragment.html
new file mode 100644
index 0000000000..976754f28a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-fragment.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = () => t.step_timeout(() => {
+ let start_length = history.length;
+ let target_key = navigation.currentEntry.key;
+ let target_id = navigation.currentEntry.id;
+ location.hash = "#1";
+ assert_equals(history.length, start_length + 1);
+
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_false(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, target_key);
+ assert_equals(e.destination.id, target_id);
+ assert_equals(e.destination.index, 0);
+ assert_equals(e.formData, null);
+ });
+
+ history.back();
+ }, 0);
+}, "history.back() fires the navigate event and sets hashChange when reversing a fragment navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-pushState.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-pushState.html
new file mode 100644
index 0000000000..4d870fb2ae
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-after-pushState.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = () => t.step_timeout(() => {
+ let start_length = history.length;
+ let target_key = navigation.currentEntry.key;
+ let target_id = navigation.currentEntry.id;
+ history.pushState(1, "", "pushState.html");
+ assert_equals(history.length, start_length + 1);
+
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_false(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, target_key);
+ assert_equals(e.destination.id, target_id);
+ assert_equals(e.destination.index, 0);
+ assert_equals(e.formData, null);
+ });
+
+ history.back();
+ }, 0);
+}, "history.back() fires the navigate event when reversing a pushState()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-cross-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-cross-document.html
new file mode 100644
index 0000000000..cd7be6e9ad
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-back-cross-document.html
@@ -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>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ let target_key = i.contentWindow.navigation.currentEntry.key;
+ let target_id = i.contentWindow.navigation.currentEntry.id;
+ i.contentWindow.navigation.navigate("?foo");
+ i.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_false(e.cancelable);
+ assert_false(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname, "/common/blank.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, target_key);
+ assert_equals(e.destination.id, target_id);
+ assert_equals(e.destination.index, 0);
+ assert_equals(e.formData, null);
+ assert_equals(e.info, undefined);
+ });
+ assert_true(i.contentWindow.navigation.canGoBack);
+ i.contentWindow.history.back();
+ })
+ });
+}, "navigate event for history.back() - cross-document");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-go-0.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-go-0.html
new file mode 100644
index 0000000000..96d98cf44c
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-go-0.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "reload");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname, "/common/blank.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ });
+
+ i.contentWindow.history.go(0);
+ });
+}, "history.go(0) fires the navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-pushState.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-pushState.html
new file mode 100644
index 0000000000..2f8c81c709
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-pushState.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ let start_length = history.length;
+ navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => {
+ assert_equals(location.hash, "");
+ assert_equals(history.state, null);
+ assert_equals(history.length, start_length);
+ }), 0);
+ });
+ history.pushState(1, null, "#1");
+}, "history.pushState() fires the navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-replaceState.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-replaceState.html
new file mode 100644
index 0000000000..d8417fbfd3
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-history-replaceState.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ let start_length = history.length;
+ navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "replace");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => {
+ assert_equals(location.hash, "");
+ assert_equals(history.state, null);
+ assert_equals(history.length, start_length);
+ }), 0);
+ });
+ history.replaceState(1, null, "#1");
+}, "history.replaceState() fires the navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-iframe-location.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-iframe-location.html
new file mode 100644
index 0000000000..059b995011
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-iframe-location.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(() => {
+ assert_unreached("onnavigate should not have fired in source window");
+ });
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ t.step_timeout(t.step_func_done(() => assert_equals(location.hash, "")), 0);
+ });
+ iframe.contentWindow.location.hash = "#1";
+ });
+}, "location API on another window fires navigate event in the target window only");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-location.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-location.html
new file mode 100644
index 0000000000..c5aa0be97a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-location.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<form id="form" action=""></form>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "replace");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ });
+ location.href = "#1";
+}, "location API fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-meta-refresh.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-meta-refresh.html
new file mode 100644
index 0000000000..1f8ed30685
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-meta-refresh.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="resources/meta-refresh.html"></iframe>
+</head>
+<script>
+async_test(t => {
+ i.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "reload");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, i.contentWindow.location.href);
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ });
+ });
+}, "<meta> refresh fires navigate event");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-cross-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-cross-document.html
new file mode 100644
index 0000000000..214644066e
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-cross-document.html
@@ -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>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ let target_key = i.contentWindow.navigation.currentEntry.key;
+ let target_id = i.contentWindow.navigation.currentEntry.id;
+ i.contentWindow.navigation.navigate("?foo");
+ i.onload = t.step_func(() => {
+ i.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_false(e.cancelable);
+ assert_false(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_false(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).pathname, "/common/blank.html");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, target_key);
+ assert_equals(e.destination.id, target_id);
+ assert_equals(e.destination.index, 0);
+ assert_equals(e.formData, null);
+ assert_equals(e.info, "hi");
+ });
+ assert_true(i.contentWindow.navigation.canGoBack);
+ i.contentWindow.navigation.back({ info: "hi" });
+ })
+ });
+}, "navigate event for navigation.back() - cross-document");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-same-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-same-document.html
new file mode 100644
index 0000000000..8753e6b1c8
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-back-same-document.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ // Wait for after the load event so that the navigation doesn't get converted
+ // into a replace navigation.
+ window.onload = () => t.step_timeout(() => {
+ let target_key = navigation.currentEntry.key;
+ let target_id = navigation.currentEntry.id;
+ navigation.navigate("#foo").committed.then(t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "traverse");
+ assert_false(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, target_key);
+ assert_equals(e.destination.id, target_id);
+ assert_equals(e.destination.index, 0);
+ assert_equals(e.formData, null);
+ assert_equals(e.info, "hi");
+ });
+ assert_true(navigation.canGoBack);
+ navigation.back({ info: "hi" });
+ }));
+ }, 0);
+}, "navigate event for navigation.back() - same-document");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-navigate.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-navigate.html
new file mode 100644
index 0000000000..76f98c7236
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-navigation-navigate.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "replace");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#foo");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ });
+ navigation.navigate("#foo");
+}, "navigate event for navigation.navigate()");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-javascript.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-javascript.html
new file mode 100644
index 0000000000..78f490d87b
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-javascript.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.unreached_func("onnavigate should not have fired in source window");
+
+ iframe.contentWindow.navigation.onnavigate = t.unreached_func("onnavigate should not have fired in iframe window");
+
+ iframe.contentWindow.location.href = "javascript:'foo'";
+
+ iframe.onload = () => t.done();
+ });
+}, "navigate event does not fire for javascript: URL navigations");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-srcdoc.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-srcdoc.html
new file mode 100644
index 0000000000..26ad135b6a
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-to-srcdoc.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.unreached_func("onnavigate should not have fired in source window");
+
+ iframe.contentWindow.navigation.onnavigate = t.step_func(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable, "cancelable");
+ assert_false(e.canIntercept, "canIntercept");
+ assert_false(e.userInitiated, "userInitiated");
+ assert_false(e.hashChange, "hashChange");
+ assert_equals(e.downloadRequest, null);
+ assert_equals(e.destination.url, "about:srcdoc");
+ assert_false(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+
+ // Make sure it doesn't navigate anyway.
+ iframe.onload = t.unreached_func("Must not load the srcdoc document");
+ t.step_timeout(() => t.done(), 10);
+ });
+
+ iframe.srcdoc = "srcdoc contents";
+ });
+}, "navigate event fires appropriately (and can be canceled) for adding the srcdoc attribute");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open-self.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open-self.html
new file mode 100644
index 0000000000..274c8bc4d5
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open-self.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ });
+ window.onload = t.step_func(() => window.open("#1", "_self"));
+}, "window.open() fires navigate event when targeting self");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open.html b/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open.html
new file mode 100644
index 0000000000..afc998271f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigate-window-open.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="iframe" name="i" src="/common/blank.html"></iframe>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ navigation.onnavigate = t.step_func_done(() => {
+ assert_unreached("onnavigate should not have fired in source window");
+ });
+ iframe.contentWindow.navigation.onnavigate = t.step_func_done(e => {
+ assert_equals(e.navigationType, "push");
+ assert_true(e.cancelable);
+ assert_true(e.canIntercept);
+ assert_false(e.userInitiated);
+ assert_true(e.hashChange);
+ assert_equals(e.downloadRequest, null);
+ assert_equals(new URL(e.destination.url).hash, "#1");
+ assert_true(e.destination.sameDocument);
+ assert_equals(e.destination.key, null);
+ assert_equals(e.destination.id, null);
+ assert_equals(e.destination.index, -1);
+ assert_equals(e.formData, null);
+ e.preventDefault();
+ });
+
+ window.open("/common/blank.html#1", "i");
+ });
+}, "window.open() fires navigate event in target window but not source");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-cross-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-cross-document.html
new file mode 100644
index 0000000000..1d528c1f5f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-cross-document.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="i" src="resources/navigatesuccess-cross-document-helper.html"></iframe>
+<script>
+async_test(t => {
+ // The iframe will post a message if it receives a navigatesuccess.
+ window.onmessage = t.unreached_func("navigatesuccess received");
+ window.onload = t.step_func(() => {
+ i.contentWindow.location.search = "?1";
+ i.onload = t.step_func_done(() => assert_equals(i.contentWindow.location.search, "?1"));
+ });
+}, "navigatesuccess does not fire for a cross-document navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-same-document.html b/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-same-document.html
new file mode 100644
index 0000000000..6007170ec1
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/navigatesuccess-same-document.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<a id="a" href="#1"></a>
+<script>
+async_test(t => {
+ navigation.onnavigatesuccess = t.step_func_done(() => assert_equals(location.hash, "#1"));
+ a.click();
+}, "navigatesuccess fires for a same-document navigation");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/resources/meta-refresh.html b/testing/web-platform/tests/navigation-api/navigate-event/resources/meta-refresh.html
new file mode 100644
index 0000000000..fd453e663f
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/resources/meta-refresh.html
@@ -0,0 +1,4 @@
+<head>
+<meta http-equiv="refresh" content="0"></meta>
+</head>
+<body></body>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/resources/navigatesuccess-cross-document-helper.html b/testing/web-platform/tests/navigation-api/navigate-event/resources/navigatesuccess-cross-document-helper.html
new file mode 100644
index 0000000000..aabc5015a9
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/resources/navigatesuccess-cross-document-helper.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<head>
+<script>
+navigation.onnavigatesuccess = () => top.postMessage("navigatesuccess received");
+</script>
+</head>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/resources/opener-postMessage-onload.html b/testing/web-platform/tests/navigation-api/navigate-event/resources/opener-postMessage-onload.html
new file mode 100644
index 0000000000..97e1d82058
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/resources/opener-postMessage-onload.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<head>
+<script>
+window.onload = () => opener.postMessage("onload", "*");
+</script>
+</head>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-detach-in-onnavigate.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-detach-in-onnavigate.html
new file mode 100644
index 0000000000..467ea88899
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-detach-in-onnavigate.html
@@ -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 => {
+ await new Promise(resolve => i.onload = resolve);
+ let iframe_constructor = i.contentWindow.DOMException;
+ let iframe_typeerror = i.contentWindow.TypeError;
+ let abort_signal;
+ let onabort_called = false;
+ i.contentWindow.navigation.onnavigate = t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => onabort_called = true;
+ i.remove();
+ });
+ await promise_rejects_dom(t, 'AbortError', iframe_constructor, i.contentWindow.navigation.navigate("#1").committed);
+ assert_true(abort_signal.aborted);
+ assert_true(onabort_called);
+}, "window detach inside a navigate event signals event.signal");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-intercept.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-intercept.html
new file mode 100644
index 0000000000..1e92d8e445
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-intercept.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async t => {
+ let abort_signal;
+ let onabort_called = false;
+ navigation.onnavigate = t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => onabort_called = true;
+ e.intercept();
+ });
+
+ await navigation.navigate("?1").finished;
+ assert_false(abort_signal.aborted);
+ assert_false(onabort_called);
+}, "event.intercept() does not signal event.signal");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-preventDefault.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-preventDefault.html
new file mode 100644
index 0000000000..60fed90ce6
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-preventDefault.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async t => {
+ let abort_signal;
+ let events = [];
+ navigation.onnavigateerror = () => events.push("onnavigateerror");
+ navigation.onnavigate = t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => events.push("onabort");
+ e.preventDefault();
+ });
+
+ await promise_rejects_dom(t, 'AbortError', navigation.navigate("?1").committed);
+ assert_true(abort_signal.aborted);
+ assert_array_equals(events, ["onabort", "onnavigateerror"]);
+}, "event.preventDefault() signals event.signal");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-after-intercept.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-after-intercept.html
new file mode 100644
index 0000000000..51ba7753a8
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-after-intercept.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ let start_url = location.href;
+ let abort_signal;
+ let onabort_called = false;
+ let navigateErrorException;
+ navigation.onnavigateerror = t.step_func(e => {
+ assert_equals(e.constructor, ErrorEvent);
+ navigateErrorException = e.error;
+ assert_equals(e.filename, start_url);
+ assert_greater_than(e.lineno, 0);
+ assert_greater_than(e.colno, 0);
+ });
+ navigation.onnavigatesuccess = t.unreached_func("onnavigatesuccess");
+ navigation.onnavigate = t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => onabort_called = true;
+ e.intercept({ handler: () => new Promise(resolve => t.step_timeout(resolve, 0)) });
+ });
+ let result = navigation.navigate("?1");
+ window.stop();
+ assert_true(abort_signal.aborted);
+ assert_true(onabort_called);
+
+ result.committed.then(() => {
+ return promise_rejects_dom(t, 'AbortError', result.finished);
+ }).then(() => {
+ return result.finished.catch(e => assert_equals(e, navigateErrorException));
+ }).then(() => {
+ // Complete the test asynchronously to ensure that onnavigatesuccess
+ // didn't fire on a microtask.
+ t.step_timeout(t.step_func_done(() => {}), 5);
+ });
+ });
+}, "window.stop() cancels the navigate event's intercept() and signals event.signal");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-in-onnavigate.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-in-onnavigate.html
new file mode 100644
index 0000000000..1b406c42d3
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop-in-onnavigate.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = t.step_func_done(() => {
+ let abort_signal;
+ let onabort_called = false;
+ let canceled_in_second_handler = false;
+ navigation.addEventListener("navigate", t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => onabort_called = true;
+ window.stop();
+ }));
+ navigation.addEventListener("navigate", t.step_func(e => {
+ canceled_in_second_handler = e.defaultPrevented;
+ }));
+ navigation.navigate("?1");
+ assert_true(abort_signal.aborted);
+ assert_true(onabort_called);
+ assert_true(canceled_in_second_handler);
+ });
+}, "window.stop() signals event.signal inside a navigate event handler");
+</script>
diff --git a/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop.html b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop.html
new file mode 100644
index 0000000000..43e005e8b4
--- /dev/null
+++ b/testing/web-platform/tests/navigation-api/navigate-event/signal-abort-window-stop.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = t.step_func(() => {
+ let abort_signal;
+ let onabort_called = false;
+ navigation.onnavigatesuccess = t.unreached_func("onnavigatesuccess");
+ navigation.onnavigate = t.step_func(e => {
+ abort_signal = e.signal;
+ abort_signal.onabort = () => onabort_called = true;
+ });
+ navigation.navigate("?1");
+ window.stop();
+ assert_true(abort_signal.aborted);
+ assert_true(onabort_called);
+ // Complete the test asynchronously to ensure that onnavigatesuccess
+ // didn't fire on a microtask.
+ t.step_timeout(t.step_func_done(() => {}), 0);
+ });
+}, "window.stop() signals event.signal");
+</script>