summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html')
-rw-r--r--testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html252
1 files changed, 252 insertions, 0 deletions
diff --git a/testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html b/testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html
new file mode 100644
index 0000000000..73931d4b0e
--- /dev/null
+++ b/testing/web-platform/tests/scroll-to-text-fragment/scroll-to-text-fragment.html
@@ -0,0 +1,252 @@
+<!doctype html>
+<title>Navigating to a text fragment directive</title>
+<meta charset=utf-8>
+<link rel="help" href="https://wicg.github.io/ScrollToTextFragment/">
+<meta name="timeout" content="long">
+<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="/common/utils.js"></script>
+<script src="stash.js"></script>
+<!--
+ This test suite performs scroll to text navigations to
+ scroll-to-text-fragment-target.html and then checks the results, which are
+ communicated back from the target page via the WPT Stash server (see stash.py).
+ This structure is necessary because scroll to text security restrictions
+ specifically restrict the navigator from being able to observe the result of
+ the navigation, e.g. the target page cannot have a window opener.
+-->
+<script>
+let test_cases = [
+ // Test non-text fragment directives
+ {
+ fragment: '#',
+ expect_position: 'top',
+ description: 'Empty hash should scroll to top'
+ },
+ {
+ fragment: '#:~:text=this,is,test,page',
+ expect_position: 'top',
+ description: 'Text directive with invalid syntax (context terms without "-") should not parse as a text directive'
+ },
+ {
+ fragment: '#element:~:directive',
+ expect_position: 'element',
+ description: 'Generic fragment directive with existing element fragment should scroll to element'
+ },
+ {
+ fragment: '#:~:TEXT=test',
+ expect_position: 'top',
+ description: 'Uppercase TEXT directive should not parse as a text directive'
+ },
+ // Test exact text matching, with all combinations of context terms
+ {
+ fragment: '#:~:text=test',
+ expect_position: 'text',
+ description: 'Exact text with no context should match text'
+ },
+ {
+ fragment: '#:~:text=this is a-,test',
+ expect_position: 'text',
+ description: 'Exact text with prefix should match text'
+ },
+ {
+ fragment: '#:~:text=test,-page',
+ expect_position: 'text',
+ description: 'Exact text with suffix should match text'
+ },
+ {
+ fragment: '#:~:text=this is a-,test,-page',
+ expect_position: 'text',
+ description: 'Exact text with prefix and suffix should match text'
+ },
+ // Test tricky edge case where prefix and query are equal
+ {
+ fragment: '#:~:text=foo-,foo,-bar',
+ expect_position: 'text',
+ description: 'Exact text with prefix and suffix and query equals prefix.'
+ },
+ // Test text range matching, with all combinations of context terms
+ {
+ fragment: '#:~:text=this,page',
+ expect_position: 'text',
+ description: 'Text range with no context should match text'
+ },
+ {
+ fragment: '#:~:text=this-,is,test',
+ expect_position: 'text',
+ description: 'Text range with prefix should match text'
+ },
+ {
+ fragment: '#:~:text=this,test,-page',
+ expect_position: 'text',
+ description: 'Text range with suffix should match text'
+ },
+ {
+ fragment: '#:~:text=this-,is,test,-page',
+ expect_position: 'text',
+ description: 'Text range with prefix and suffix should match text'
+ },
+ // Test partially non-matching text ranges
+ {
+ fragment: '#:~:text=this,none',
+ expect_position: 'top',
+ description: 'Text range with non-matching endText should not match'
+ },
+ {
+ fragment: '#:~:text=none,page',
+ expect_position: 'top',
+ description: 'Text range with non-matching startText should not match'
+ },
+ // Test non-matching context terms
+ {
+ fragment: '#:~:text=this-,is,page,-none',
+ expect_position: 'top',
+ description: 'Text range with prefix and nonmatching suffix should not match'
+ },
+ {
+ fragment: '#:~:text=none-,this,test,-page',
+ expect_position: 'top',
+ description: 'Text range with nonmatching prefix and matching suffix should not match'
+ },
+ // Test percent encoded characters
+ {
+ fragment: '#:~:text=this%20is%20a%20test%20page',
+ expect_position: 'text',
+ description: 'Exact text with percent encoded spaces should match text'
+ },
+ {
+ fragment: '#:~:text=test%20pag',
+ expect_position: 'top',
+ description: 'Non-whole-word exact text with spaces should not match'
+ },
+ {
+ fragment: '#:~:text=%26%2C%2D',
+ expect_position: 'text',
+ description: 'Fragment directive with percent encoded syntactical characters "&,-" should match text'
+ },
+ {
+ fragment: '#:~:text=%E3%83%8D%E3%82%B3',
+ expect_position: 'text',
+ description: 'Fragment directive with percent encoded non-ASCII unicode character should match text'
+ },
+ {
+ fragment: '#:~:text=!$\'()*+./:;=?@_~',
+ expect_position: 'text',
+ description: 'Fragment directive with all TextMatchChars should match text'
+ },
+ // Test multiple text directives
+ {
+ fragment: '#:~:text=this&text=test,page',
+ expect_position: 'text',
+ description: 'Multiple matching exact texts should match text'
+ },
+ {
+ fragment: '#:~:text=tes&text=age',
+ expect_position: 'top',
+ description: 'Multiple non-whole-word exact texts should not match'
+ },
+ {
+ fragment: '#:~:text=none&text=test%20page',
+ expect_position: 'text',
+ description: 'A non-matching text directive followed by a matching text directive should match and scroll into view the second text directive'
+ },
+ {
+ fragment: '#:~:text=test%20page&directive',
+ expect_position: 'text',
+ description: 'Text directive followed by non-text directive should match text'
+ },
+ {
+ fragment: '#:~:text=test&directive&text=page',
+ expect_position: 'text',
+ description: 'Multiple text directives and a non-text directive should match text'
+ },
+ // Test text directive behavior when there's an element fragment identifier
+ {
+ fragment: '#element:~:text=test',
+ expect_position: 'text',
+ description: 'Text directive with existing element fragment should match and scroll into view text'
+ },
+ {
+ fragment: '#pagestate:~:text=test',
+ expect_position: 'text',
+ description: 'Text directive with nonexistent element fragment should match and scroll into view text'
+ },
+ {
+ fragment: '#element:~:text=nomatch',
+ expect_position: 'element',
+ description: 'Non-matching text directive with existing element fragment should scroll to element'
+ },
+ {
+ fragment: '#pagestate:~:text=nomatch',
+ expect_position: 'top',
+ description: 'Non-matching text directive with nonexistent element fragment should not match and not scroll'
+ },
+ // Test ambiguous text matches disambiguated by context terms
+ {
+ fragment: '#:~:text=more-,test%20page',
+ expect_position: 'more-text',
+ description: 'Multiple match text directive disambiguated by prefix should match the prefixed text'
+ },
+ {
+ fragment: '#:~:text=test%20page,-text',
+ expect_position: 'more-text',
+ description: 'Multiple match text directive disambiguated by suffix should match the suffixed text'
+ },
+ {
+ fragment: '#:~:text=more-,test%20page,-text',
+ expect_position: 'more-text',
+ description: 'Multiple match text directive disambiguated by prefix and suffix should match the text with the given context'
+ },
+ // Test context terms separated by node boundaries
+ {
+ fragment: '#:~:text=prefix-,test%20page,-suffix',
+ expect_position: 'cross-node-context',
+ description: 'Text directive should match when context terms are separated by node boundaries'
+ },
+ // Test text directive within shadow DOM
+ {
+ fragment: '#:~:text=shadow%20text',
+ expect_position: 'shadow',
+ description: 'Text directive should match text within shadow DOM'
+ },
+ // Test text directive within hidden and display none elements. These cases should not scroll into
+ // view, but still "match" in that they should be highlighted or otherwise visibly indicated
+ // if they were to become visible.
+ {
+ fragment: '#:~:text=hidden%20text',
+ expect_position: 'top',
+ description: 'Text directive should not scroll to hidden text'
+ },
+ {
+ fragment: '#:~:text=display%20none',
+ expect_position: 'top',
+ description: 'Text directive should not scroll to display none text'
+ },
+ // Test horizontal scroll into view
+ {
+ fragment: '#:~:text=horizontally%20scrolled%20text',
+ expect_position: 'horizontal-scroll',
+ description: 'Text directive should horizontally scroll into view'
+ }
+];
+
+for (const test_case of test_cases) {
+ promise_test(t => new Promise((resolve, reject) => {
+ let key = token();
+
+ test_driver.bless('Open a URL with a text fragment directive', () => {
+ window.open(`scroll-to-text-fragment-target.html?key=${key}${test_case.fragment}`, '_blank', 'noopener');
+ });
+
+ fetchResults(key, resolve, reject);
+ }).then(data => {
+ // If the position is not 'top', the :target element should be the positioned element.
+ assert_true(data.scrollPosition == 'top' || data.target == data.scrollPosition);
+ assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
+ assert_equals(data.scrollPosition, test_case.expect_position,
+ `Expected ${test_case.fragment} (${test_case.description}) to scroll to ${test_case.expect_position}.`);
+ }), `Test navigation with fragment: ${test_case.description}.`);
+}
+</script>