diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /testing/web-platform/tests/css/css-scroll-snap | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-upstream/125.0.1.tar.xz firefox-upstream/125.0.1.zip |
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-scroll-snap')
15 files changed, 1366 insertions, 64 deletions
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html new file mode 100644 index 0000000000..d9989316e4 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html @@ -0,0 +1,174 @@ +<!DOCTYPE html> +<html> + +<head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js"></script> +</head> + +<body> + <style> + .placeholder { + top: 0px; + left: 0px; + position: absolute; + width: 10px; + height: 10px; + background-color: black; + scroll-snap-align: start; + } + .space { + position: absolute; + height: 300vh; + width: 300vw; + top: 100px; + left: 100px; + } + .scroller { + overflow: scroll; + scroll-snap-type: both mandatory; + width: 550px; + height: 550px; + border: solid 1px black; + position: relative; + resize: both; + } + .box { + background-color: green; + height: 200px; + width: 200px; + scroll-snap-align: start; + position: absolute; + border: solid 1px white; + } + .row { + top: 100px; + } + .col { + left: 100px; + } + /* Place boxes 0 through 4 on a horizontal row. */ + #box0 { + left: 300px; + } + #box1 { + left: 500px; + } + #box2 { + left: 700px; + } + #box3 { + left: 900px; + } + #box4 { + left: 1100px; + } + /* Place boxes 5 through 9 in a vertical column. */ + #box5 { + top: 300px; + } + #box6 { + top: 500px; + } + #box7 { + top: 700px; + } + #box8 { + top: 900px; + } + #box9 { + top: 1100px; + } + </style> + <div id="scroller" class="scroller"> + <!-- This placeholder is a snap target at the top-left of the + scroller. It gives the scroller an opportunity to scroll to the + snap targets, forcing the UA to run the snap point selection + algorithm. Each test case ensures the snap point selection algorithm is + invoked by: + - first resetting the scroller's scroll position to snap to the + placeholder, + - then configuring the tree-order and layout of the snap + targets as necessary, + - then scrolling to the snap areas and, + - finally, verifying that the correct snap area was selected. + Without the scroll from the placeholder to the snap targets, the UA would + be correct to simply make the scroller follow the previously selected snap + target (i.e. when there was no snap area aligned in both axes) even after + the layout changes made by the test. --> + <div class="placeholder"></div> + <div id="box0" class="row box">Box 0</div> + <div id="box1" class="row box">Box 1</div> + <div id="box2" class="row box">Box 2</div> + <div id="box3" class="row box">Box 3</div> + <div id="box4" class="row box">Box 4</div> + <div id="box5" class="col box">Box 5</div> + <div id="box6" class="col box">Box 6</div> + <div id="box7" class="col box">Box 7</div> + <div id="box8" class="col box">Box 8</div> + <div id="box9" class="col box">Box 9</div> + <div class="space" id="space"> + </div> + <script> + window.onload = async () => { + const scroller = document.getElementById("scroller"); + const boxes = document.querySelectorAll(".box"); + const box = (n) => { + return boxes[n]; + } + + async function test(n) { + return promise_test(async (t) => { + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + const target = document.getElementById(`box${n}`); + + assert_equals(scroller.scrollLeft, 0, "scrollLeft is reset"); + assert_equals(scroller.scrollTop, 0, "scrollTop is reset"); + + // Make target the last in tree-order. + scroller.removeChild(target); + scroller.appendChild(target); + + const old_style = getComputedStyle(target); + const old_top = old_style.top; + const old_left = old_style.left; + + // Make target snap-aligned in both axes. + t.add_cleanup(async () => { + target.style.top = old_top; + target.style.left = old_left; + }); + target.style.left = "100px"; + target.style.top = "100px"; + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(5), box(6), box(7), box(8), box(9)], + /*aligned_elements_y=*/[box(0), box(1), box(2), box(3), box(4)], + /*axis=*/"both", + /*expected_target_x*/target, + /*expected_target_y*/target); + }, `box${n} is common to both axes and is the snap target despite ` + + `being last in tree order.`); + } + + await test(0); + await test(1); + await test(2); + await test(3); + await test(4); + await test(5); + await test(6); + await test(7); + await test(8); + await test(9); + } + </script> +</body> +<html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html new file mode 100644 index 0000000000..15743026bc --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js" ></script> + </head> + <body> + <style> + .scroller { + overflow: scroll; + width: 450px; + height: 450px; + border: solid 1px black; + scroll-snap-type: both mandatory; + position: relative; + resize: both; + } + .large-space { + height: 300vh; + width: 300vw; + position: absolute; + } + .snap { + scroll-snap-align: start; + } + .box { + width: 200px; + height: 200px; + background-color: green; + position: absolute; + } + .inner { + width: 50px; + height: 50px; + background-color: yellow; + } + #box2 { + top: 0px; + left: 100px; + } + #box3 { + top: 100px; + left: 0px; + } + </style> + <div class="scroller" id="scroller"> + <div class="large-space"><div> + <div id="box1" class="snap box">Box 1</div> + <div id="box2" class="inner snap box">Box 2</div> + <div id="box3" class="inner snap box">Box 3</div> + </div> + <script> + window.onload = () => { + const scroller = document.getElementById("scroller"); + const boxes = document.querySelectorAll(".snap.box"); + function box(n) { + return boxes[n - 1]; + } + + promise_test(async (t) => { + await waitForCompositorCommit(); + + // Box 2 should be selected as the target in the y axis despite Box 1's + // being a common target in both axes because Box 2 is nested within + // Box 1. + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(1), box(2)], + /*axis=*/ "y", + /*expected_target_x=*/null, + /*expected_target_y=*/box(2)); + + // Box 3 should be selected as the target in the x axis despite Box 1's + // being a common target in both axes because Box 3 is nested within + // Box 1. + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(1), box(3)], + /*aligned_elements_y=*/[], + /*axis=*/"x", + /*expected_target_x=*/box(3)); + }, "scroller prefers nested area over area aligned in both axes."); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html new file mode 100644 index 0000000000..65195af621 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html> +<body> + <style> + .target { + width: 100px; + height: 100px; + background-color: green; + scroll-snap-align: start; + } + .placeholder { + background-color: purple; + } + .snapcontainer { + border:solid 1px black; + overflow: scroll; + scroll-snap-type: y mandatory; + } + .big { + height: 315px; + width: 600px; + position: relative; + } + .small { + height: 115px; + width: 120px; + } + .positioned { + position: absolute; + } + #target1, #target2, #target3, #target4, #target5 { + top: 400px; + } + #target1 { + left: 0px; + } + #target2 { + left: 110px; + } + #target3 { + left: 220px; + } + #target4 { + left: 330px; + } + #target5 { + left: 440px; + } + :target { + background-color: yellow; + } + .large-space { + position: absolute; + height: 300vh; + width: 300vw; + } + </style> + <div id="outer" class="big snapcontainer"> + <div id="outerplaceholder1" class="placeholder target"></div> + <div id="outerplaceholder2" class="placeholder target"></div> + <div id="inner" class="small snapcontainer"> + <div id="innerplaceholder1" class="placeholder target"></div> + <div id="innerplaceholder2" class="placeholder target"></div> + <div id="target1" class="positioned target"><h1>Box 1</h1></div> + <div id="target2" class="positioned target"><h1>Box 2</h1></div> + <div id="target3" class="positioned target"><h1>Box 3</h1></div> + <div id="target4" class="positioned target"><h1>Box 4</h1></div> + <div id="target5" class="positioned target"><h1>Box 5</h1></div> + </div> + <div class="large-space"></div> + </div> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html new file mode 100644 index 0000000000..09b81e7c0d --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html @@ -0,0 +1,151 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js" ></script> + </head> + <body> + <style> + .scroller { + overflow: scroll; + width: 350px; + height: 350px; + border: solid 1px black; + scroll-snap-type: both mandatory; + position: relative; + resize: both; + } + .large-space { + height: 300vh; + width: 300vw; + position: absolute; + } + .snap { + scroll-snap-align: start; + } + .box { + width: 100px; + height: 100px; + background-color: green; + display: inline-block; + position: relative; + } + .grid { + position: absolute; + width: 350px; + height: 350px; + } + .snap:focus { + background-color: blue; + } + </style> + <div class="scroller" id="scroller"> + <div class="large-space"><div> + <div class="grid" id="grid"> + <div id="box1" tabindex="1" class="snap box">Box 1</div> + <div id="box2" tabindex="1" class="snap box">Box 2</div> + <div id="box3" tabindex="1" class="snap box">Box 3</div> + <div id="box4" tabindex="1" class="snap box">Box 4</div> + <div id="box5" tabindex="1" class="snap box">Box 5</div> + <div id="box6" tabindex="1" class="snap box">Box 6</div> + <div id="box7" tabindex="1" class="snap box">Box 7</div> + <div id="box8" tabindex="1" class="snap box">Box 8</div> + <div id="box9" tabindex="1" class="snap box">Box 9</div> + </div> + </div> + <script> + window.onload = () => { + // This test sets up a 3x3 grid within scroller: + // ------------------------- + // | Box 1 | Box 2 | Box 3 | + // ------------------------ + // | Box 4 | Box 5 | Box 6 | + // ------------------------- + // | Box 7 | Box 8 | Box 9 | + // ------------------------- + const scroller = document.getElementById("scroller"); + const boxes = document.querySelectorAll(".snap.box"); + function box(n) { + return boxes[n - 1]; + } + + promise_test(async (t) => { + await waitForCompositorCommit(); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(1), box(2), box(3)], + /*axis=*/ "y", + /*expected_target_x=*/null, + /*expected_target_y=*/box(1)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(4), box(5), box(6)], + /*axis=*/ "y", + /*expected_target_x=*/null, + /*expected_target_y=*/box(4)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(7), box(8), box(9)], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_y=*/box(7)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(1), box(4), box(7)], + /*aligned_elements_y=*/[], + /*axis=*/"x", + /*expected_target_x=*/box(1)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(2), box(5), box(8)], + /*aligned_elements_y=*/[], + /*axis=*/"x", + /*expected_target_x=*/box(2)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(3), box(6), box(9)], + /*aligned_elements_y=*/[], + /*axis=*/"x", + /*expected_target_x=*/box(3)); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[box(2), box(5), box(8)], + /*aligned_elements_y=*/[box(4), box(5), box(6)], + /*axis=*/"both", + /*expected_target_x=*/box(5), + /*expected_target_y=*/box(5)); + }, "scroller prefers target aligned in both axes."); + + promise_test(async (t) => { + const box7 = box(7), box8 = box(8), box9 = box(9); + const initial_box8_top = box8.offsetTop; + t.add_cleanup(() => { + box8.style.top = `${initial_box8_top}px`; + }); + + // Move box 8 below box7 and box9. + box8.style.top = `${2 * box8.offsetTop}px`; + + // Snap to box8. + scroller.scrollTop = box8.offsetTop; + + // Test that if box7 and box9 are also shifted to align with box7, + // box8 is still treated as the selected snap target despite box7 being + // aligned on both axes. + runLayoutSnapSeletionVerificationTest(t, scroller, [box7, box9], + box8, "y"); + }, "scroller follows selected snap target after layout shift, " + + "regardless of common snap area."); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html new file mode 100644 index 0000000000..f4b32e10c7 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js"></script> + </head> +<body> + <style> + .large-space { + position: absolute; + height: 300vh; + width: 300vw; + z-index: -1; + } + .target { + width: 100px; + height: 100px; + background-color: green; + scroll-snap-align: start; + } + .snapcontainer { + border:solid 1px black; + overflow: scroll; + scroll-snap-type: y mandatory; + } + .outer { + height: 315px; + width: 1200px; + position: relative; + } + .inner { + height: 115px; + width: 120px; + } + .positioned { + position: absolute; + top: 150px; + } + .outer .target1 { + left: 0px; + } + .outer .target2 { + left: 110px; + } + .outer .target3 { + left: 220px; + } + .outer .target4 { + left: 330px; + } + .outer .target5 { + left: 440px; + } + .inner .target1 { + left: 550px; + } + .inner .target2 { + left: 660px; + } + .inner .target3 { + left: 770px; + } + .inner .target4 { + left: 880px; + } + .inner .target5 { + left: 990px; + } + .placeholder { + background-color: purple; + top: 0px; + } + .outer > .placeholder { + position: absolute; + top: 0px; + left: 200px; + } + </style> + <!-- + Placeholder snap areas are used to make it necessary for the scroller to + scroll in order to reach its snap targets. This forces the scroller to + invoke the snap point selection algorithm. Otherwise (i.e. if no scroll + happens) a layout change (inserting and removing children) may not be enough + to cause the scroller to select the intended snap targets. + --> + <div id="outerscroller" class="outer snapcontainer"> + <div id="outerplaceholder1" class="placeholder target">Outer placeholder + </div> + <div id="outertarget1" class="positioned target target1">Outer 1</div> + <div id="outertarget2" class="positioned target target2">Outer 2</div> + <div id="outertarget3" class="positioned target target3">Outer 3</div> + <div id="outertarget4" class="positioned target target4">Outer 4</div> + <div id="outertarget5" class="positioned target target5">Outer 5</div> + <div id="innerscroller" class="inner snapcontainer"> + <div id="innerplaceholder1" class="placeholder target">Inner Placeholder + </div> + <div id="innertarget1" class="positioned target target1">Inner 1</div> + <div id="innertarget2" class="positioned target target2">Inner 2</div> + <div id="innertarget3" class="positioned target target3">Inner 3</div> + <div id="innertarget4" class="positioned target target4">Inner 4</div> + <div id="innertarget5" class="positioned target target5">Inner 5</div> + </div> + <div class="large-space"></div> + </div> + <script> + window.onload = async () => { + const outerscroller = document.getElementById("outerscroller"); + const innerscroller = document.getElementById("innerscroller"); + const outertargets = Array.from( + document.querySelectorAll(".outer > .positioned.target")); + const innertargets = Array.from( + document.querySelectorAll(".inner > .positioned.target")); + + promise_test(async (t) => { + for (const target of outertargets) { + await waitForScrollReset(t, outerscroller); + await waitForCompositorCommit(); + + // Make target first in tree order. + outerscroller.removeChild(target); + outerscroller.prepend(target); + + await runScrollSnapSelectionVerificationTest(t, outerscroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/outertargets, + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/target); + } + + // The next for-loop tests outerscroller's selection of + // out-of-positioned targets that are children of innerscroller. For + // outerscroller to consider them first in tree order relative to its + // own children, innerscroller must be the first child of outer + // scroller. + outerscroller.removeChild(innerscroller); + outerscroller.prepend(innerscroller); + + for (const target of innertargets) { + await waitForScrollReset(t, outerscroller); + await waitForCompositorCommit(); + + // Make target first in tree order. + innerscroller.removeChild(target); + innerscroller.prepend(target); + + await runScrollSnapSelectionVerificationTest(t, outerscroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/innertargets, + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/target); + } + }, "first in tree-order is selected as snap target."); + } + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html index f15a291f08..9acf0e905c 100644 --- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html @@ -71,15 +71,19 @@ focusAndAssert(bottomright); await runScrollSnapSelectionVerificationTest(t, scroller, - [bottomright, - bottomleft], - /*expected_target=*/bottomright, "y"); + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[bottomright, bottomleft], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_y=*/bottomright); focusAndAssert(bottomleft); await runScrollSnapSelectionVerificationTest(t, scroller, - [bottomright, - bottomleft], - /*expected_target=*/bottomleft, "y"); + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[bottomright, bottomleft], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_y=*/bottomleft); }, "scroller selects focused target from aligned choices on snap"); promise_test(async (t) => { @@ -94,9 +98,11 @@ // Set focus on bottomright without scrolling to it. focusAndAssert(bottomright, true); await runScrollSnapSelectionVerificationTest(t, scroller, - [bottomright, - bottomleft], - /*expected_target=*/bottomleft, "y"); + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[bottomright, bottomleft], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_y=*/bottomleft); }, "out-of-viewport focused element is not the selected snap target."); promise_test(async(t) => { diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html index a6a087316f..4330022b27 100644 --- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html @@ -97,11 +97,19 @@ focusAndAssert(lefttarget1, /*preventScroll=*/true); await runScrollSnapSelectionVerificationTest(t, outercontainer, - [leftcontainer, rightcontainer], leftcontainer, "y"); + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[leftcontainer, rightcontainer], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_x=*/leftcontainer); focusAndAssert(righttarget1, /*preventScroll=*/true); await runScrollSnapSelectionVerificationTest(t, outercontainer, - [leftcontainer, rightcontainer], rightcontainer, "y"); + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[leftcontainer, rightcontainer], + /*axis=*/"y", + /*expected_target_x=*/null, + /*expected_target_x=*/rightcontainer); }, "Snap container prefers focused nested snap target."); } </script> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html new file mode 100644 index 0000000000..3cabbc7945 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html @@ -0,0 +1,158 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js" ></script> + </head> + <body> + <style> + .scroller { + overflow: scroll; + position: relative; + height: 400px; + width: 400px; + border:solid 1px black; + scroll-snap-type: y mandatory; + } + .no-snap { scroll-snap-align: none } + .scroller div:focus { + border: solid 1px red; + } + .large-space { + height: 300vh; + width: 300vw; + position: absolute; + } + .target { + scroll-snap-align: start; + position: absolute; + width: 100px; + height: 100px; + border: solid 1px black; + } + .top { + top: 0px; + } + .left { + left: 0px; + } + .right { + left: 200px; + } + .bottom { + top: 200px; + } + .inner { + text-align: right; + } + .inner1 { + height: 150px; + width: 150px; + top: 150px; + left: 100px; + background-color: blue; + } + .inner2 { + height: 100px; + width: 100px; + top: 150px; + left: 100px; + background-color: pink; + } + .inner3 { + height: 75px; + width: 75px; + top: 150px; + left: 100px; + background-color: green; + } + .inner4 { + height: 50px; + width: 50px; + top: 150px; + left: 100px; + background-color: grey; + } + .outer { + height: 200px; + width: 200px; + top: 150px; + left: 50px; + left: 50px; + background-color: yellow; + } + </style> + <div id="scroller" class="scroller"> + <div class="large-space"></div> + <div class="top left target">Top Left</div> + <div class="top right target">Top Right</div> + <div class="outer target" id="outer">Outer</div> + <div class="inner inner1 target" id="inner1">I1</div> + <div class="inner inner2 target" id="inner2">I2</div> + <div class="inner inner3 target" id="inner3">I3</div> + <div class="inner inner4 target" id="inner4">I4</div> + </div> + <script> + function cleanup() { + inner.style.top = 100; + outer.style.top = 100; + } + window.onload = (async () => { + const inner1 = document.getElementById("inner1"); + const inner2 = document.getElementById("inner2"); + const inner3 = document.getElementById("inner3"); + const inner4 = document.getElementById("inner4"); + const outer = document.getElementById("outer"); + const scroller = document.getElementById("scroller"); + + promise_test(async (t) => { + await waitForCompositorCommit(); + + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/inner4); + + // Push inner4 outside the snapport. It should no longer be considered + // the snap target; inner3 is next in line. + inner4.style.left = "500px"; + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/inner3); + + // Reset inner4's style. + inner4.style.left = "100px"; + }, "snap container selects innermost area as snap target"); + + promise_test(async (t) => { + t.add_cleanup(() => { + outer.style.top = "150px"; + }); + await waitForCompositorCommit(); + + // Move outer target below inner targets. + outer.style.top = "400px"; + + // Snap to now-below outer target. + scroller.scrollTop = outer.offsetTop; + + runLayoutSnapSeletionVerificationTest(t, scroller, + [inner1, inner2, inner3, inner4], outer, "y"); + }, "snap container follows selected snap target after layout change " + + "(the pre-existing snap target should not be overriden because of " + + "the innermost area)"); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html new file mode 100644 index 0000000000..35b0684b26 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html> + <body> + <style> + .scroller { + overflow: scroll; + width: 350px; + height: 350px; + border: solid 1px black; + scroll-snap-type: y mandatory; + position: relative; + resize: both; + } + .large-space { + height: 300vh; + width: 300vw; + position: absolute; + } + .snap { + scroll-snap-align: start; + } + .box { + width: 100px; + height: 100px; + background-color: green; + display: inline-block; + position: relative; + } + .grid { + position: absolute; + width: 350px; + height: 350px; + } + .snap:target { + background-color: blue; + } + </style> + <div class="scroller" id="scroller"> + <div class="large-space"></div> + <div class="grid" id="grid"> + <div id="box1" class="snap box">Box 1</div> + <div id="box2" class="snap box">Box 2</div> + <div id="box3" class="snap box">Box 3</div> + <div id="box4" class="snap box">Box 4</div> + <div id="box5" class="snap box">Box 5</div> + <div id="box6" class="snap box">Box 6</div> + <div id="box7" class="snap box">Box 7</div> + <div id="box8" class="snap box">Box 8</div> + <div id="box9" class="snap box">Box 9</div> + </div> + </div> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html new file mode 100644 index 0000000000..6bc47d15ef --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html @@ -0,0 +1,137 @@ +<!DOCTYPE html> +<html> +<body> + <style> + #space { + height: 300vh; + width: 300vw; + position: absolute; + } + #scroller { + overflow-y: scroll; + scroll-snap-type: y mandatory; + width: 450px; + height: 450px; + border: solid 1px black; + position: relative; + } + .box { + height: 200px; + width: 200px; + position: absolute; + background-color: green; + scroll-snap-align: start; + } + .box:target { + background-color: red; + } + .toprow { top: 0px; } + .midrow { top: 210px; } + .bottomrow { top: 420px; } + .leftcol { left: 0px; } + .midcol { left: 210px; } + .rightcol { left: 420px; } + </style> + <div id="scroller"> + <div id="space"></div> + <div class="leftcol toprow box" id="box1"></div> + <div class="midcol toprow box" id="box2"></div> + <div class="rightcol toprow box" id="box3"></div> + <div class="leftcol midrow box" id="box4"></div> + <div class="midcol midrow box" id="box5"></div> + <div class="rightcol midrow box" id="box6"></div> + <div class="leftcol bottomrow box" id="box7"></div> + <div class="midcol bottomrow box" id="box8"></div> + <div class="rightcol bottomrow box" id="box9"></div> + </div> + <script> + // This test sets up a 3x3 grid within scroller: + // ------------------------- + // | Box 1 | Box 2 | Box 3 | + // ------------------------ + // | Box 4 | Box 5 | Box 6 | + // ------------------------- + // | Box 7 | Box 8 | Box 9 | + // ------------------------- + // This function just gets the numbers beside |box_number| on each row. + // E.g. 4: 4%3 = 1; so the numbers we want are 5 (4+1) and 6 (4+2). + function getAlignedNumbers(n) { + n = parseInt(n); + const mod_3 = n % 3; + if (mod_3 == 1) { + return [n + 1, n + 2]; + } else if (mod_3 == 2) { + return [n - 1, n + 1]; + } + return [n - 1, n - 2]; + } + function stashResult(key, result) { + fetch(`/css/css-scroll-snap/snap-after-relayout` + + `/multiple-aligned-targets/stash.py?key=${key}`, { + method: "POST", + body: result + }).then(() => { + window.close(); + }); + } + function assert_equals(v1, v2) { + if (v1 != v2) { + throw new Error(`Expected equality of v1(${v1}) and v2(${v2}).`); + } + } + async function record() { + let key = (new URL(document.location)).searchParams.get("key"); + try { + // Get the id of that targeted element. + const target_id = location.hash.substring(1); + const box_number = target_id.substring(3); + + // Get the elements aligned with the targeted element. + const target = document.getElementById(target_id); + if (target == null) { + throw new Error("Null hash fragment target."); + } + let [aligned_number_1, aligned_number_2] = + getAlignedNumbers(box_number); + const aligned_box_1 = document.getElementById(`box${aligned_number_1}`); + const aligned_box_2 = document.getElementById(`box${aligned_number_2}`); + + // Make sure all the boxes are equally aligned. + assert_equals(aligned_box_1.offsetTop, target.offsetTop); + assert_equals(aligned_box_1.offsetTop, aligned_box_2.offsetTop); + + // Scroll to the aligned boxes if necessary. + if (scroller.scrollTop != target.offsetTop) { + const scrollend_promise = new Promise((res) => { + scroller.addEventListener(res); + }); + scroller.scrollTop = target.offsetTop; + await scrollend_promise; + } + + // Save target's original top and move it down by 100px; + const original_top = getComputedStyle(target).top; + target.style.top = `${target.offsetTop + 100}px`; + + // Assert that scroller followed target as it moved down. + assert_equals(scroller.scrollTop, target.offsetTop); + + // Cleanup: undo style change. + target.style.top = `${original_top}px`; + + // Stash result. + stashResult(key, "PASS"); + } catch (error) { + stashResult(key, error.message); + } + } + + window.onload = () => { + window.requestAnimationFrame(function () { + window.requestAnimationFrame(record); + }) + } + </script> +</body> + +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html new file mode 100644 index 0000000000..6221b0e4b5 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap Test: snap selection with targeted element</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="/common/utils.js"></script> +</head> + +<body onload="runTest()"> + <script> + async function fetchResult(key) { + const url = `/css/css-scroll-snap/snap-after-relayout/` + + `multiple-aligned-targets/stash.py?key=${key}`; + // We may need multiple requests. Return a promise that will be resolved + // when an actual response is received. + return new Promise(async (resolve) => { + async function fetchResultInternal(url) { + const response = await fetch(url); + const text = await response.text(); + if (text) { + resolve(text); + } else { + requestAnimationFrame(fetchResultInternal.bind(this, url)); + } + } + fetchResultInternal(url); + }); + } + + function runTest() { + function test(n) { + return promise_test(async (t) => { + let key = token(); + + test_driver.bless("Open a URL with a text fragment directive", () => { + window.open(`prefer-targeted-element-main-frame-target.html` + + `?key=${key}#box${n}`, "_blank", "noopener"); + }); + + assert_equals(await fetchResult(key), "PASS"); + }, `targeted box${n} is selected snap target.`); + } + + test(1); + test(2); + test(3); + test(4); + test(5); + test(6); + test(7); + test(8); + test(9); + } + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html new file mode 100644 index 0000000000..3a2b1a9089 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html> + <head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js"></script> + </head> +<body> + <style> + .iframe { + height: 1000px; + width: 1000px; + } + </style> + <script> + window.onload = async () => { + await waitForCompositorCommit(); + async function test(target_number) { + return promise_test(async (t) => { + let finish = null; + const finished = new Promise((res) => { finish = res; }); + var iframe = document.createElement("iframe"); + iframe.classList.add("iframe"); + iframe.onload = async () => { + let boxes = + iframe.contentDocument.getElementsByClassName("positioned"); + const box = (i) => { + return boxes[i - 1]; + } + let scroller = iframe.contentDocument.getElementById("outer"); + // There are 5 aligned boxes in positioned-target-iframe.html. + assert_equals(boxes.length, 5); + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(1), box(2), box(3), box(4), box(5)], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_x*/box(target_number)); + + // Let scroller no longer be a scroll container. + scroller.style.overflow = "visible"; + assert_equals(scroller.scrollTop, 0); + + // Let scroller be a scroll container once again. + scroller.style.overflow = "scroll"; + + // Run the test again. + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(1), box(2), box(3), box(4), box(5)], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_x*/box(target_number)); + finish(); + }; + iframe.src = `positioned-target-iframe.html#target${target_number}`; + document.body.appendChild(iframe); + await finished; + document.body.removeChild(iframe); + }, ""); + } + + await test(1); + await test(2); + await test(3); + await test(4); + await test(5); + } + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html new file mode 100644 index 0000000000..ceb9bd2ee0 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html @@ -0,0 +1,109 @@ +<!DOCTYPE html> +<html> +<head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + <script src="resources/common.js"></script> +</head> + +<body> + <style> + .iframe { + width: 1000px; + height: 1000px; + } + </style> + <script> + window.onload = async () => { + await waitForCompositorCommit(); + // This test sets up a 3x3 grid within scroller: + // ------------------------- + // | Box 1 | Box 2 | Box 3 | + // ------------------------ + // | Box 4 | Box 5 | Box 6 | + // ------------------------- + // | Box 7 | Box 8 | Box 9 | + // ------------------------- + // within an iframe. + // This function just gets the numbers beside |box_number| on each row. + // E.g. 4: 4%3 = 1; so the numbers we want are 5 (4+1) and 6 (4+2). + function getAlignedNumbers(n) { + const mod_3 = n % 3; + if (mod_3 == 1) { + return [n + 1, n + 2]; + } else if (mod_3 == 2) { + return [n - 1, n + 1]; + } + return [n - 1, n - 2]; + } + + async function test(box_number) { + return promise_test(async (t) => { + let [other_box_1, other_box_2] = getAlignedNumbers(box_number); + let finish = null; + const finished = new Promise((res) => { + finish = res; + }); + var iframe = document.createElement("iframe"); + iframe.classList.add("iframe"); + iframe.onload = async () => { + let boxes = iframe.contentDocument.getElementsByClassName("box"); + const box = (i) => { + return boxes[i - 1]; + } + let scroller = iframe.contentDocument.getElementById("scroller"); + assert_equals(boxes.length, 9); + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(box_number), + box(other_box_1), + box(other_box_2)], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/box(box_number)); + + // Let scroller no longer be a scroll container. + scroller.style.overflow = "visible"; + assert_equals(scroller.scrollTop, 0); + + // Let scroller be a scroll container once again. + scroller.style.overflow = "scroll"; + + // Run the test again. + await runScrollSnapSelectionVerificationTest(t, scroller, + /*aligned_elements_x=*/[], + /*aligned_elements_y=*/[box(box_number), + box(other_box_1), + box(other_box_2)], + /*axis=*/"y", + /*expected_target_x*/null, + /*expected_target_y*/box(box_number)); + + finish(); + }; + iframe.src = `prefer-targeted-element-iframe.html#box${box_number}`; + document.body.appendChild(iframe); + await finished; + document.body.removeChild(iframe); + }, `scroller selects targeted area box${box_number} among multiple` + + ` aligned areas.`); + } + + await test(1); + await test(2); + await test(3); + await test(4); + await test(5); + await test(6); + await test(7); + await test(8); + await test(9); + } + </script> +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js index 6ceec9118c..1fd88949b3 100644 --- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js @@ -6,54 +6,55 @@ // This function should be used by scroll snap WPTs wanting to test snap target // selection when scrolling to multiple aligned targets. -// It assumes scroll-snap-align: start alignment and tries to align to the list -// of snap targets provided, |elements|, which are all expected to be at the -// same offset. -async function scrollToAlignedElementsInAxis(scroller, elements, axis) { +// It assumes scroll-snap-align: start alignment and tries to align to the lists +// of snap targets provided, |elements_x| and |elements_y|, which are all +// expected to be at the same offset in the relevant axis. +async function scrollToAlignedElements(scroller, elements_x, elements_y) { let target_offset_y = null; let target_offset_x = null; - if (axis == "y") { - for (const e of elements) { - if (target_offset_y) { - assert_equals(e.offsetTop, target_offset_y, - `${e.id} is at y offset ${target_offset_y}`); - } else { - target_offset_y = e.offsetTop; - } + for (const e of elements_y) { + if (target_offset_y != null) { + assert_equals(e.offsetTop, target_offset_y, + `${e.id} is at y offset ${target_offset_y}`); + } else { + target_offset_y = e.offsetTop; } - assert_equals(); - } else { - for (const e of elements) { - if (target_offset_x) { - assert_equals(e.offsetLeft, target_offset_x, - `${e.id} is at x offset ${target_offset_x}`); - } else { - target_offset_x = e.offsetLeft; - } + } + for (const e of elements_x) { + if (target_offset_x != null) { + assert_equals(e.offsetLeft, target_offset_x, + `${e.id} is at x offset ${target_offset_x}`); + } else { + target_offset_x = e.offsetLeft; } } - assert_not_equals(target_offset_x || target_offset_y, null); + assert_true((target_offset_x != null) || (target_offset_y != null), + "scrolls in at least 1 axis"); - const scrollend_promise = waitForScrollendEventNoTimeout(scroller); - await new test_driver.Actions().scroll(0, 0, - (target_offset_x || 0) - scroller.scrollLeft, - (target_offset_y || 0) - scroller.scrollTop, - { origin: scroller }) - .send(); - await scrollend_promise; - if (axis == "y") { + if ((target_offset_x != null && scroller.scrollLeft != target_offset_x) || + (target_offset_y != null && scroller.scrollTop != target_offset_y)) { + const scrollend_promise = waitForScrollendEventNoTimeout(scroller); + await new test_driver.Actions().scroll(0, 0, + (target_offset_x || scroller.scrollLeft) - scroller.scrollLeft, + (target_offset_y || scroller.scrollTop) - scroller.scrollTop, + { origin: scroller }) + .send(); + await scrollend_promise; + } + if (target_offset_y) { assert_equals(scroller.scrollTop, target_offset_y, "vertical scroll done"); - } else { - assert_equals(scroller.scrollLeft,target_offset_x, "horizontal scroll done"); + } + if (target_offset_x) { + assert_equals(scroller.scrollLeft, target_offset_x, "horizontal scroll done"); } } -// This function verifies the snap target that a scroller picked by triggerring +// This function verifies the snap target that a scroller picked by triggering // a layout change and observing which target is followed. Tests using this // method should ensure that there is at least 100px of room to scroll in the // desired axis. // It assumes scroll-snap-align: start alignment. -function verifySelectedSnapTarget(scroller, expected_snap_target, axis) { +function verifySelectedSnapTarget(t, scroller, expected_snap_target, axis) { // Save initial style. const initial_left = getComputedStyle(expected_snap_target).left; const initial_top = getComputedStyle(expected_snap_target).top; @@ -62,19 +63,26 @@ function verifySelectedSnapTarget(scroller, expected_snap_target, axis) { const initial_scroll_top = scroller.scrollTop; const target_top = expected_snap_target.offsetTop + 100; expected_snap_target.style.top = `${target_top}px`; - assert_equals(scroller.scrollTop, expected_snap_target.offsetTop, - `scroller followed ${expected_snap_target.id} after layout change`); - assert_not_equals(scroller.scrollTop, initial_scroll_top, - "scroller actually scrolled in y axis"); + // Wrap these asserts in t.step (which catches exceptions) so that even if + // they fail, we'll get to undo the style changes we made, allowing + // subsequent tests to run with the expected style/layout. + t.step(() => { + assert_equals(scroller.scrollTop, expected_snap_target.offsetTop, + `scroller followed ${expected_snap_target.id} in y axis after layout change`); + assert_not_equals(scroller.scrollTop, initial_scroll_top, + "scroller actually scrolled in y axis"); + }); } else { - // Move the expected snap target along the y axis. + // Move the expected snap target along the x axis. const initial_scroll_left = scroller.scrollLeft; const target_left = expected_snap_target.offsetLeft + 100; expected_snap_target.style.left = `${target_left}px`; - assert_equals(scroller.scrollLeft, expected_snap_target.offsetLeft, - `scroller followed ${expected_snap_target.id} after layout change`); - assert_not_equals(scroller.scrollLeft, initial_scroll_left, - "scroller actually scrolled in x axis"); + t.step(() => { + assert_equals(scroller.scrollLeft, expected_snap_target.offsetLeft, + `scroller followed ${expected_snap_target.id} in x axis after layout change`); + assert_not_equals(scroller.scrollLeft, initial_scroll_left, + "scroller actually scrolled in x axis"); + }); } // Undo style changes. expected_snap_target.style.top = initial_top; @@ -83,19 +91,24 @@ function verifySelectedSnapTarget(scroller, expected_snap_target, axis) { // This is a utility function for tests which verify that the correct element // is snapped to when snapping at the end of a scroll. -async function runScrollSnapSelectionVerificationTest(t, scroller, aligned_elements, - expected_target, axis) { +async function runScrollSnapSelectionVerificationTest(t, scroller, + aligned_elements_x=[], aligned_elements_y=[], axis="", + expected_target_x=null, expected_target_y=null) { // Save initial scroll offset. const initial_scroll_left = scroller.scrollLeft; const initial_scroll_top = scroller.scrollTop; - await scrollToAlignedElementsInAxis(scroller, aligned_elements, axis); - verifySelectedSnapTarget(scroller, expected_target, axis); - // Restore initial scroll offsets. - const scrollend_promise = new Promise((resolve) => { - scroller.addEventListener("scrollend", resolve); + await scrollToAlignedElements(scroller, aligned_elements_x, + aligned_elements_y); + t.step(() => { + if (axis == "y" || axis == "both") { + verifySelectedSnapTarget(t, scroller, expected_target_y, axis); + } + if (axis == "x" || axis == "both") { + verifySelectedSnapTarget(t, scroller, expected_target_x, axis); + } }); - scroller.scrollTo(initial_scroll_left, initial_scroll_top); - await scrollend_promise; + // Restore initial scroll offsets. + await waitForScrollReset(t, scroller, initial_scroll_left, initial_scroll_top); } // This is a utility function for tests verifying that a layout shift does not @@ -127,7 +140,7 @@ async function runLayoutSnapSeletionVerificationTest(t, scroller, elements_to_al } shiftLayoutToAlignElements(elements_to_align, expected_target, axis); - verifySelectedSnapTarget(scroller, expected_target, axis); + verifySelectedSnapTarget(t, scroller, expected_target, axis); // Restore initial scroll offset and position states. let num_elements = initial_tops.length; diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py new file mode 100644 index 0000000000..a70672ecf0 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py @@ -0,0 +1,27 @@ +# Copyright 2024 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +""" +This file allows the different windows created by +css/css-scroll-snap/snap-after-relayout/prefer-targeted-element-main-frame.html +to store and retrieve data. + +prefer-targeted-element-main-frame.html (test file) opens a window to +prefer-targeted-element-main-frame.html-target.html which writes some data +which the test file will eventually read. This file handles the requests from +both windows. +""" + +import time + +def main(request, response): + key = request.GET.first(b"key") + + if request.method == u"POST": + # Received result data from target page + request.server.stash.put(key, request.body, u'/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets') + return u"ok" + else: + # Request for result data from test page + value = request.server.stash.take(key, u'/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets') + return value |