Bug 1735858 [wpt PR 31247] - App history: make it mostly nonfunctional for opaque origins, a=testonly

Automatic update from web-platform-tests
App history: make it mostly nonfunctional for opaque origins

Given that opaque origins complicate the notion of what the origin of a
history entry is and when they can be considered contiguous, discussion
on https://github.com/WICG/app-history/issues/167 suggests that we
should probably start with restricting the API to not work on them for
now, in the same way we do for the initial about:blank.

This also slightly improves the test coverage for detached window
scenarios since they are very similar to what we're changing here.

Fixed: 1252490
Change-Id: Id3c761d87dba0c3b75c0e70e4f6cc61e96429b8d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3161023
Commit-Queue: Domenic Denicola <domenic@chromium.org>
Reviewed-by: Nate Chapin <japhet@chromium.org>
Cr-Commit-Position: refs/heads/main@{#936101}

--

wpt-commits: 0ffde1b55c7b73abc2945697fbc45549cf9eafbb
wpt-pr: 31247
This commit is contained in:
Domenic Denicola 2021-11-01 16:33:02 +00:00 коммит произвёл moz-wptsync-bot
Родитель 60c91cb995
Коммит 1a6f91c518
20 изменённых файлов: 204 добавлений и 138 удалений

Просмотреть файл

@ -3,18 +3,28 @@
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<script>
async_test(t => {
window.onload = t.step_func_done(() => {
let i_entry = i.contentWindow.appHistory.current;
assert_true(i_entry.sameDocument);
assert_not_equals(i_entry.url, "");
assert_not_equals(i_entry.key, "");
assert_not_equals(i_entry.id, "");
i.remove();
assert_false(i_entry.sameDocument);
assert_equals(i_entry.url, "");
assert_equals(i_entry.key, "");
assert_equals(i_entry.id, "");
});
}, "AppHistoryEntry attributes after detach");
promise_test(async t => {
// Wait for after the load event so that the navigation doesn't get converted
// into a replace navigation.
await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0));
let i_appHistory = i.contentWindow.appHistory;
await i_appHistory.navigate("#1").finished;
await i_appHistory.navigate("#2").finished;
await i_appHistory.back().finished;
assert_not_equals(i_appHistory, null);
assert_not_equals(i_appHistory.current, null);
assert_equals(i_appHistory.entries().length, 3);
assert_true(i_appHistory.canGoBack, "canGoBack");
assert_true(i_appHistory.canGoForward, "canGoForward");
i.remove();
assert_equals(i_appHistory.current, null);
assert_equals(i_appHistory.entries().length, 0);
assert_false(i_appHistory.canGoBack);
assert_false(i_appHistory.canGoForward);
}, "appHistory.current/entries()/canGoBack/canGoForward after iframe removal");
</script>

Просмотреть файл

@ -1,17 +0,0 @@
<!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_done(() => {
let i_appHistory = i.contentWindow.appHistory;
assert_not_equals(i_appHistory, null);
assert_not_equals(i_appHistory.current, null);
assert_equals(i_appHistory.entries().length, 1);
i.remove();
assert_equals(i_appHistory.current, null);
assert_equals(i_appHistory.entries().length, 0);
});
}, "appHistory.current should be null after iframe removal");
</script>

Просмотреть файл

@ -1,23 +0,0 @@
<!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 start_key = i.contentWindow.appHistory.current.key;
let start_url = i.contentWindow.appHistory.current.url;
let start_id = i.contentWindow.appHistory.current.id;
window.onmessage = t.step_func_done(e => {
assert_equals(e.data.length, 1);
assert_not_equals(e.data.key, start_key);
assert_equals(e.data.protocol, "data:");
assert_not_equals(e.data.id, start_id);
});
i.src = "data:text/html,<script>top.postMessage({ length: appHistory.entries().length, " +
"key: appHistory.current.key, protocol: new URL(appHistory.current.url).protocol," +
"id: appHistory.current.id}, '*')</sc" +
"ript>";
});
}, "AppHistory behavior after navigation to a data: url");
</script>

Просмотреть файл

@ -0,0 +1,20 @@
<!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_done(() => {
let i_entry = i.contentWindow.appHistory.current;
assert_true(i_entry.sameDocument);
assert_not_equals(i_entry.url, "");
assert_not_equals(i_entry.key, "");
assert_not_equals(i_entry.id, "");
i.remove();
assert_false(i_entry.sameDocument);
assert_equals(i_entry.url, "");
assert_equals(i_entry.key, "");
assert_equals(i_entry.id, "");
});
}, "AppHistoryEntry attributes after detach");
</script>

Просмотреть файл

@ -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(() => {
window.onmessage = t.step_func_done(e => {
assert_equals(e.data.length, 0);
assert_true(e.data.currentIsNull);
});
i.src = "data:text/html,<script>top.postMessage({ length: appHistory.entries().length, " +
"currentIsNull: appHistory.current === null}, '*')</sc" +
"ript>";
});
}, "AppHistory behavior after navigation to a data: URL (which has an opaque origin)");
</script>

Просмотреть файл

@ -0,0 +1,9 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" sandbox="allow-scripts" src="resources/opaque-origin-page.html"></iframe>
<script>
fetch_tests_from_window(i.contentWindow);
</script>

Просмотреть файл

@ -0,0 +1,25 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<!-- Put this page in a sandbox to give it an opaque origin -->
<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));
location.hash = "#1";
await new Promise(resolve => window.onhashchange = resolve);
location.hash = "#2";
await new Promise(resolve => window.onhashchange = resolve);
history.back();
await new Promise(resolve => window.onhashchange = resolve);
assert_equals(location.hash, "#1");
assert_equals(appHistory.current, null);
assert_equals(appHistory.entries().length, 0);
assert_false(appHistory.canGoBack);
assert_false(appHistory.canGoForward);
}, "appHistory.current/entries()/canGoBack/canGoForward in an opaque origin iframe");
</script>

Просмотреть файл

@ -0,0 +1,15 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
promise_test(async t => {
const w = window.open("about:blank#1");
w.appHistory.oncurrentchange = t.unreached_func("currentchange should not fire");
assert_equals(w.location.href, "about:blank#1");
w.location.href = "about:blank#2";
assert_equals(w.location.href, "about:blank#2");
await new Promise(resolve => t.step_timeout(resolve, 10));
}, "AppHistoryCurrentChangeEvent does not fire when navigating away from the initial about:blank (popup window)");
</script>

Просмотреть файл

@ -1,11 +1,12 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<iframe id="i"></iframe>
<script>
promise_test(async t => {
i.contentWindow.appHistory.oncurrentchange = t.unreached_func("currentchange should not fire");
history.pushState(1, "", "#1");
await new Promise(resolve => i.onload = resolve);
i.contentWindow.location.href = "about:blank#1";
i.contentWindow.location.href = "about:blank#2";
await new Promise(resolve => t.step_timeout(resolve, 10));
}, "AppHistoryCurrentChangeEvent does not fire when navigating away from the initial about:blank");
</script>

Просмотреть файл

@ -1,11 +1,11 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" src="/common/blank.html"></iframe>
<iframe id="i"></iframe>
<script>
promise_test(async t => {
i.contentWindow.appHistory.oncurrentchange = t.unreached_func("currentchange should not fire");
i.contentWindow.appHistory.navigate("/common/blank.html#1");
await new Promise(resolve => i.onload = resolve);
i.contentWindow.appHistory.navigate("/common/blank.html");
await new Promise(resolve => t.step_timeout(resolve, 10));
}, "AppHistoryCurrentChangeEvent does not fire when navigating away from the initial about:blank");
</script>

Просмотреть файл

@ -1,24 +0,0 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="iframe" src="/common/blank.html"></iframe>
<script>
function waitOnLoad(target) {
return new Promise((resolve, reject) => {
target.onload = resolve;
});
}
promise_test(async t => {
await waitOnLoad(window);
iframe.contentWindow.appHistory.navigate("?1");
await waitOnLoad(iframe);
assert_equals(iframe.contentWindow.appHistory.entries().length, 2);
assert_equals(iframe.contentWindow.appHistory.canGoBack, true);
const cached_app_history = iframe.contentWindow.appHistory;
iframe.remove();
assert_equals(cached_app_history.canGoBack, false);
}, "canGoBack should return false if the document is not fully active");
</script>

Просмотреть файл

@ -1,26 +0,0 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="iframe" src="/common/blank.html"></iframe>
<script>
function waitOnLoad(target) {
return new Promise((resolve, reject) => {
target.onload = resolve;
});
}
promise_test(async t => {
await waitOnLoad(window);
iframe.contentWindow.appHistory.navigate("?1");
await waitOnLoad(iframe);
assert_equals(iframe.contentWindow.appHistory.entries().length, 2);
iframe.contentWindow.appHistory.back();
await waitOnLoad(iframe);
assert_equals(iframe.contentWindow.appHistory.canGoForward, true);
const cached_app_history = iframe.contentWindow.appHistory;
iframe.remove();
assert_equals(cached_app_history.canGoForward, false);
}, "canGoForward should return false if the document is not fully active");
</script>

Просмотреть файл

@ -15,10 +15,11 @@ promise_test(async t => {
// Since there's no way to do a non-replacement navigation on the initial
// about:blank, there's no way to actually get in a situation where we're on
// about:blank but there's something else backward in the history list. So
// this test will almost certainly pass just because there's nothing in the
// backward history list. Oh well; it's still reasonable coverage.
// about:blank but there's something else backward/forward in the history
// list. So this test will almost certainly pass just because there's nothing
// to go back/forward to. Oh well; it's still reasonable coverage.
await assertBothRejectDOM(t, i.contentWindow.appHistory.back(), "InvalidStateError", i.contentWindow);
}, "back() in initial about:blank document");
await assertBothRejectDOM(t, i.contentWindow.appHistory.forward(), "InvalidStateError", i.contentWindow);
}, "back() and forward() in initial about:blank document");
</script>

Просмотреть файл

@ -0,0 +1,9 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" sandbox="allow-scripts" src="resources/back-forward-opaque-origin-page.html"></iframe>
<script>
fetch_tests_from_window(i.contentWindow);
</script>

Просмотреть файл

@ -1,24 +0,0 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/helpers.js"></script>
<body>
<script>
promise_test(async t => {
let i = document.createElement("iframe");
document.body.append(i);
i.contentWindow.appHistory.onnavigate = t.unreached_func("onnavigate should not be called");
i.contentWindow.appHistory.onnavigatesuccess = t.unreached_func("onnavigatesuccess should not be called");
i.contentWindow.appHistory.onnavigateerror = t.unreached_func("onnavigateerror should not be called");
// Since there's no way to do a non-replacement navigation on the initial
// about:blank, there's no way to actually get in a situation where we're on
// about:blank but there's something else forward in the history list. So this
// test will almost certainly pass just because there's nothing in the forward
// history list. Oh well; it's still reasonable coverage.
await assertBothRejectDOM(t, i.contentWindow.appHistory.forward(), "InvalidStateError", i.contentWindow);
}, "forward() in initial about:blank document");
</script>

Просмотреть файл

@ -0,0 +1,9 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" sandbox="allow-scripts" src="resources/navigate-opaque-origin-page.html"></iframe>
<script>
fetch_tests_from_window(i.contentWindow);
</script>

Просмотреть файл

@ -0,0 +1,28 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="helpers.js"></script>
<!-- Put this page in a sandbox to give it an opaque origin -->
<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));
appHistory.onnavigate = t.unreached_func("onnavigate should not be called");
appHistory.onnavigatesuccess = t.unreached_func("onnavigatesuccess should not be called");
appHistory.onnavigateerror = t.unreached_func("onnavigateerror should not be called");
location.hash = "#1";
await new Promise(resolve => window.onhashchange = resolve);
location.hash = "#2";
await new Promise(resolve => window.onhashchange = resolve);
history.back();
await new Promise(resolve => window.onhashchange = resolve);
assert_equals(location.hash, "#1");
await assertBothRejectDOM(t, appHistory.back(), "InvalidStateError");
await assertBothRejectDOM(t, appHistory.forward(), "InvalidStateError");
}, "appHistory.back()/forward() in an opaque origin iframe");
</script>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="helpers.js"></script>
<!-- Put this page in a sandbox to give it an opaque origin -->
<script>
promise_test(async t => {
appHistory.onnavigate = t.unreached_func("onnavigate should not be called");
appHistory.onnavigatesuccess = t.unreached_func("onnavigatesuccess should not be called");
appHistory.onnavigateerror = t.unreached_func("onnavigateerror should not be called");
const result = appHistory.navigate("#1");
assertNeverSettles(t, result);
await new Promise(resolve => t.step_timeout(resolve, 10));
}, "appHistory.navigate() in an opaque origin iframe");
</script>

Просмотреть файл

@ -0,0 +1,9 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<iframe id="i" sandbox="allow-scripts" src="resources/opaque-origin-page.html"></iframe>
<script>
fetch_tests_from_window(i.contentWindow);
</script>

Просмотреть файл

@ -0,0 +1,11 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<!-- Put this page in a sandbox to give it an opaque origin -->
<script>
test(t => {
assert_throws_dom("InvalidStateError", () => {
appHistory.updateCurrent({ state: 1 });
});
}, "appHistory.updateCurrent() in an opaque origin iframe");
</script>