Automatic update from web-platform-tests Reland "[text-fragment] Attempt search for dynamic content" Reland note: iframes.sub.html was timing out because it contains several sub-tests, each of which now wait 2s which, in total, exhausted the 6s timeout. Reland marks this test as timeout=long to use the extended timeout. Previously landed CL is first patchset. Text fragments currently perform up to two searches, one when document parsing completes and a second attempt when document load completes (if load wasn't completed at parse complete time). However, pages, often load content after document load, when content is "dynamically loaded". One popular example is Mobile Wikipedia, which adds `hidden=until-found` on collapsed sections in idle tasks after load. This meant text-fragments couldn't target pages like these. This CL attempts to make text fragments work on dynamically loaded pages by performing a third attempt, if needed. If all directives haven't matched at load time, a delayed task is scheduled for 500ms that will request attachment on unmatched directives. TextFragmentAnchor listens for relevant changes in the DOM and reschedules this task each time a change is made. At 3000ms it gives up and performs the search to avoid waiting forever. At a high level, this CL tries to separate the state tracking of actions performed for the first matching directive from the state tracking for running multiple searches. This is done by introducing a new iteration_ enum tracking the latter. Bug: 963045 Change-Id: Ied3f9c610c348eeeca23ace50864f0cc2ff2b233 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4629864 Commit-Queue: Vladimir Levin <vmpstr@chromium.org> Commit-Queue: David Bokan <bokan@chromium.org> Reviewed-by: Vladimir Levin <vmpstr@chromium.org> Auto-Submit: David Bokan <bokan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1160827} -- wpt-commits: 95d67cd661417e9c44440cba14dcce147e2768bf wpt-pr: 40654
114 lines
4.9 KiB
HTML
114 lines
4.9 KiB
HTML
<!doctype html>
|
|
<title>Navigating to text fragment directives in iframes</title>
|
|
<meta charset=utf-8>
|
|
<meta name="timeout" content="long">
|
|
<link rel="help" href="https://wicg.github.io/ScrollToTextFragment/">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script>
|
|
function getResult(iframe) {
|
|
return new Promise((resolve) => {
|
|
window.addEventListener('message', (e) => {
|
|
resolve(e.data);
|
|
}, {once: true});
|
|
iframe.contentWindow.postMessage('getResult', '*');
|
|
});
|
|
}
|
|
|
|
function reset(iframe) {
|
|
return new Promise((resolve) => {
|
|
window.addEventListener('message', (e) => {
|
|
resolve();
|
|
}, {once: true});
|
|
iframe.contentWindow.postMessage('reset', '*');
|
|
});
|
|
}
|
|
|
|
function runTests() {
|
|
const attribute_iframe = document.getElementById('srcattrib');
|
|
const sameorigin_iframe = document.getElementById('sameorigin');
|
|
const crossorigin_iframe = document.getElementById('crossorigin');
|
|
|
|
// Check behavior that occurs when a text fragment is specified directly in
|
|
// an iframe's src attribute. We expect the text fragment to be blocked.
|
|
promise_test(t => new Promise(async resolve => {
|
|
// No reset since we're checking the hash specified in the `src` attribute.
|
|
const data = await getResult(attribute_iframe);
|
|
resolve(data);
|
|
}).then( data => {
|
|
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
|
|
assert_equals(data.scrollPosition, 'top', 'Should not scroll to text fragment');
|
|
}), 'Text fragment specified in iframe.src');
|
|
|
|
// Check behavior when we set a text fragment using script from a
|
|
// same-origin parent. The text fragment should be allowed because this is
|
|
// a same-document navigation initiated by an origin that's same-origin
|
|
// with the current document.
|
|
promise_test(t => new Promise(async resolve => {
|
|
await reset(sameorigin_iframe);
|
|
sameorigin_iframe.contentWindow.location = `${sameorigin_iframe.src}#:~:text=Target`;
|
|
const data = await getResult(sameorigin_iframe);
|
|
resolve(data);
|
|
}).then( data => {
|
|
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
|
|
assert_equals(data.scrollPosition, 'target', 'Should scroll to text fragment');
|
|
}), 'Navigate same-origin iframe via window.location');
|
|
|
|
// Check behavior when we set a text fragment using script from a
|
|
// cross-origin parent. The text fragment should be blocked because the
|
|
// initiating origin is not same-origin with the current document.
|
|
promise_test(t => new Promise(async resolve => {
|
|
await reset(crossorigin_iframe);
|
|
crossorigin_iframe.contentWindow.location = `${crossorigin_iframe.src}#:~:text=Target`;
|
|
const data = await getResult(crossorigin_iframe);
|
|
resolve(data);
|
|
}).then( data => {
|
|
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
|
|
assert_equals(data.scrollPosition, 'top', 'Should not to scroll to text fragment.');
|
|
}), 'Navigate cross-origin iframe via window.location');
|
|
|
|
// Check the element-id fallback behavior when the text is not found. We
|
|
// should fallback to a regular element-id hash navigation.
|
|
promise_test(t => new Promise(async resolve => {
|
|
await reset(sameorigin_iframe);
|
|
sameorigin_iframe.contentWindow.location = `${sameorigin_iframe.src}#elementid:~:text=NonExistentText`;
|
|
const data = await getResult(sameorigin_iframe);
|
|
resolve(data);
|
|
}).then( data => {
|
|
assert_equals(data.scrollPosition, 'elementid', 'Should scroll to the element-id anchor.');
|
|
}), 'Non-matching text with element-id fallback');
|
|
|
|
// Check the element-id fallback behaviour when used across origins. The
|
|
// text fragment should be blocked across origins but the element id hash
|
|
// should not.
|
|
promise_test(t => new Promise(async resolve => {
|
|
await reset(crossorigin_iframe);
|
|
crossorigin_iframe.contentWindow.location = `${crossorigin_iframe.src}#elementid:~:text=Target%20Text`;
|
|
const data = await getResult(crossorigin_iframe);
|
|
resolve(data);
|
|
}).then( data => {
|
|
assert_equals(data.scrollPosition, 'elementid', 'Should scroll to the element-id anchor.');
|
|
}), 'Cross-origin with element-id fallback');
|
|
}
|
|
</script>
|
|
<style>
|
|
iframe {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
</style>
|
|
<body onload="runTests()">
|
|
<div>
|
|
Same-Origin with text fragment in src attribute:
|
|
<iframe id="srcattrib" src="iframe-target.html#:~:text=Target"></iframe>
|
|
</div>
|
|
<div>
|
|
Same-Origin:
|
|
<iframe id="sameorigin" src="iframe-target.html"></iframe>
|
|
</div>
|
|
<div>
|
|
Cross-Origin:
|
|
<iframe id="crossorigin" src="http://{{hosts[][www]}}:{{ports[http][0]}}/scroll-to-text-fragment/iframe-target.html"></iframe>
|
|
</div>
|
|
</body>
|