Refactor scroll utils and improve test coverage
What does this MR do and why?
- Refactors
scroll_utils.js
to improve maintainability and testability. - Introduces
getScrollingElement
to abstract away the difference betweenwindow
and other scroll containers. - Updates
scrollToTargetOnResize
to use thescroll_utils
functions. - Adds more unit tests for
scroll_utils.js
.
References
Screenshots or screen recordings
No changes expected.
How to set up and validate locally
I created a tester component to run manual sanity checks, the following diff adds it to the job page to test scrolling:
Click to expand
diff --git a/app/assets/javascripts/ci/job_details/components/scroll_tester.vue b/app/assets/javascripts/ci/job_details/components/scroll_tester.vue
new file mode 100644
index 000000000000..080c23b192ac
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/scroll_tester.vue
@@ -0,0 +1,68 @@
+<script>
+/* eslint-disable */
+import {
+ getScrollingElement,
+ isScrolledToBottom,
+ isScrolledToTop,
+ scrollDown,
+ scrollUp,
+ smoothScrollTop,
+ scrollTo,
+ scrollToElement,
+} from '~/lib/utils/scroll_utils';
+import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
+
+export default {
+ name: 'ScrollTester',
+ methods: {
+ getScrollingElement() {
+ console.log('getScrollingElement()', getScrollingElement());
+ },
+ isScrolledToBottom(contextElement) {
+ console.log('isScrolledToBottom()', { contextElement }, isScrolledToBottom(contextElement));
+ },
+ isScrolledToTop(contextElement) {
+ console.log('isScrolledToTop(c)', { contextElement }, isScrolledToTop(contextElement));
+ },
+ scrollDown,
+ scrollUp,
+ smoothScrollTop,
+ scrollTo,
+ scrollToElement,
+ scrollToElementInSidebar() {
+ scrollToElement(
+ '[title="build-job-with-a-long-name-that-that-may-or-may-not-overflow 4/20 - passed"]',
+ { parent: '.sidebar-container' },
+ );
+ },
+ },
+ data() {
+ return { scrollToTargetOnResizeCleanup: null };
+ },
+ mounted() {
+ this.scrollToTargetOnResizeCleanup = scrollToTargetOnResize({ targetId: 'L101' });
+ },
+};
+</script>
+<template>
+ <div class="gl-fixed gl-bottom-[100px] gl-z-9999 gl-w-1/2 gl-bg-white gl-p-5">
+ <button @click="getScrollingElement()">getScrollContainer</button>
+ <button @click="isScrolledToBottom()">isScrolledToBottom</button>
+ <button @click="isScrolledToBottom(null)">isScrolledToBottom (window)</button>
+ <button @click="isScrolledToTop()">isScrolledToTop</button>
+ <button @click="scrollDown()">scrollDown</button>
+ <button @click="scrollUp()">scrollUp</button>
+ <button @click="smoothScrollTop()">smoothScrollTop</button>
+ <button @click="scrollTo({ top: 1000 })">scrollTo 1000px</button>
+ <button @click="scrollToElement('#L101')">scrollToElement L101</button>
+ <button @click="scrollToElementInSidebar()">scrollToElement sidebar 4/20</button>
+ <button
+ @click="
+ scrollToTargetOnResizeCleanup();
+ scrollToTargetOnResizeCleanup = null;
+ "
+ >
+ scrollToTargetOnResize is {{ scrollToTargetOnResizeCleanup ? 'active for line L101' : 'off' }}
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/job_app.vue b/app/assets/javascripts/ci/job_details/job_app.vue
index 0aa23e44011f..634b9583692e 100644
--- a/app/assets/javascripts/ci/job_details/job_app.vue
+++ b/app/assets/javascripts/ci/job_details/job_app.vue
@@ -19,6 +19,7 @@ import JobHeader from './components/job_header.vue';
import StuckBlock from './components/stuck_block.vue';
import UnmetPrerequisitesBlock from './components/unmet_prerequisites_block.vue';
import Sidebar from './components/sidebar/sidebar.vue';
+import ScrollTester from './components/scroll_tester.vue';
const STATIC_PANEL_WRAPPER_SELECTOR = '.js-static-panel-inner';
@@ -39,6 +40,7 @@ export default {
GlLoadingIcon,
SharedRunner: () => import('ee_component/ci/runner/components/shared_runner_limit_block.vue'),
GlAlert,
+ ScrollTester,
},
directives: {
SafeHtml,
@@ -235,6 +237,8 @@ export default {
<gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" />
<template v-else-if="shouldRenderContent">
+ <scroll-tester />
+
<div class="build-page" data-testid="job-content">
<!-- Header Section -->
<header>
This is the result of my manual tests
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #577063
Edited by Miguel Rincon