summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js')
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js148
1 files changed, 148 insertions, 0 deletions
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
new file mode 100644
index 0000000000..6ceec9118c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js
@@ -0,0 +1,148 @@
+// Utility functions for scroll snap tests which verify User-Agents' snap point
+// selection logic when multiple snap targets are aligned.
+// It depends on methods in /resources/testdriver-actions.js and
+// /dom/event/scrolling/scroll_support.js so html files using these functions
+// should include those files as <script>s.
+
+// 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) {
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ }
+ assert_not_equals(target_offset_x || target_offset_y, null);
+
+ 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") {
+ assert_equals(scroller.scrollTop, target_offset_y, "vertical scroll done");
+ } else {
+ assert_equals(scroller.scrollLeft,target_offset_x, "horizontal scroll done");
+ }
+}
+
+// This function verifies the snap target that a scroller picked by triggerring
+// 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) {
+ // Save initial style.
+ const initial_left = getComputedStyle(expected_snap_target).left;
+ const initial_top = getComputedStyle(expected_snap_target).top;
+ if (axis == "y") {
+ // Move the expected snap target along the y 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");
+ } else {
+ // Move the expected snap target along the y 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");
+ }
+ // Undo style changes.
+ expected_snap_target.style.top = initial_top;
+ expected_snap_target.style.left = initial_left;
+}
+
+// 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) {
+ // 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);
+ });
+ scroller.scrollTo(initial_scroll_left, initial_scroll_top);
+ await scrollend_promise;
+}
+
+// This is a utility function for tests verifying that a layout shift does not
+// cause a scroller to change its selected snap target.
+// It assumes the element to be aligned have scroll-snap-align: start.
+// It tries to align the list of snap targets provided, |elements| with the
+// current snap target.
+function shiftLayoutToAlignElements(elements, target, axis) {
+ for (let element of elements) {
+ if (axis == "y") {
+ element.style.top = `${target.offsetTop}px`;
+ } else {
+ element.style.left = `${target.offsetLeft}px`;
+ }
+ }
+}
+
+// This is a utility function for tests verifying that a layout shift does not
+// cause a scroller to change its selected snap target.
+// It assumes scroll-snap-align: start alignment.
+async function runLayoutSnapSeletionVerificationTest(t, scroller, elements_to_align,
+ expected_target, axis) {
+ // Save initial scroll offsets and position.
+ const initial_scroll_left = scroller.scrollLeft;
+ const initial_scroll_top = scroller.scrollTop;
+ let initial_tops = [];
+ for (const element of elements_to_align) {
+ initial_tops.push(getComputedStyle(element).top);
+ }
+
+ shiftLayoutToAlignElements(elements_to_align, expected_target, axis);
+ verifySelectedSnapTarget(scroller, expected_target, axis);
+
+ // Restore initial scroll offset and position states.
+ let num_elements = initial_tops.length;
+ for (let i = 0; i < num_elements; i++) {
+ elements_to_align[i].style.top = initial_tops[i];
+ }
+ // Restore initial scroll offsets.
+ const scrollend_promise = new Promise((resolve) => {
+ scroller.addEventListener("scrollend", resolve);
+ });
+ scroller.scrollTo(initial_scroll_left, initial_scroll_top);
+ await scrollend_promise;
+}
+
+function focusAndAssert(element, preventScroll=false) {
+ element.focus({preventScroll: preventScroll});
+ assert_equals(document.activeElement, element);
+}