From 9405c4e38feee27378b4dd067def1d6560bd4345 Mon Sep 17 00:00:00 2001 From: sarayourfriend <24264157+sarayourfriend@users.noreply.github.com> Date: Thu, 28 Jul 2022 10:36:15 -0400 Subject: [PATCH] Add TS to useWindowScroll --- ...-window-scroll.js => use-window-scroll.ts} | 40 +++++++----- test/unit/.eslintrc.js | 1 + .../composables/use-window-scroll.spec.ts | 65 +++++++++++++++++++ 3 files changed, 89 insertions(+), 17 deletions(-) rename src/composables/{use-window-scroll.js => use-window-scroll.ts} (61%) create mode 100644 test/unit/specs/composables/use-window-scroll.spec.ts diff --git a/src/composables/use-window-scroll.js b/src/composables/use-window-scroll.ts similarity index 61% rename from src/composables/use-window-scroll.js rename to src/composables/use-window-scroll.ts index ff093926b1..f93e292291 100644 --- a/src/composables/use-window-scroll.js +++ b/src/composables/use-window-scroll.ts @@ -10,39 +10,45 @@ import { useEventListener } from '~/composables/use-event-listener' * * This global ref is SSR safe because it will only * change internal value based on client side interaction. - * - * @type {import('@nuxtjs/composition-api').Ref} */ const isScrolled = ref(false) -/** - * - * @param {object} options - * @param {Window} [options.window] - * @param {number} [options.throttleMs] - time to throttle the scroll handler. - * Set to 0 to remove throttling - */ +interface UseWindowScrollOptions { + /** + * Window from which to read and track scroll position + */ + window?: typeof defaultWindow | undefined + /** + * Time to throttle the scroll handler. + * Set to 0 to remove throttling. + */ + throttleMs?: number +} + export function useWindowScroll({ window = defaultWindow, throttleMs = 200, -} = {}) { +}: UseWindowScrollOptions = {}) { if (!window) { - return { + // In SSR, no need to track anything. + return Object.freeze({ x: ref(0), y: ref(0), isScrolled, - } + }) } - const x = ref(window.pageXOffset) - const y = ref(window.pageYOffset) + const x = ref(0) + const y = ref(0) const scrollHandler = () => { - x.value = window.pageXOffset - y.value = window.pageYOffset + x.value = window.scrollX + y.value = window.scrollY isScrolled.value = y.value > 0 } + scrollHandler() + const handler = throttleMs ? throttle(throttleMs, scrollHandler) : scrollHandler @@ -52,5 +58,5 @@ export function useWindowScroll({ passive: true, }) - return { x, y, isScrolled } + return Object.freeze({ x, y, isScrolled }) } diff --git a/test/unit/.eslintrc.js b/test/unit/.eslintrc.js index 5f20431e5a..57c65b31ba 100644 --- a/test/unit/.eslintrc.js +++ b/test/unit/.eslintrc.js @@ -3,5 +3,6 @@ module.exports = { env: { jest: true }, rules: { 'import/no-named-as-default-member': ['off'], + '@intlify/vue-i18n/no-raw-text': ['off'], }, } diff --git a/test/unit/specs/composables/use-window-scroll.spec.ts b/test/unit/specs/composables/use-window-scroll.spec.ts new file mode 100644 index 0000000000..541a51dd79 --- /dev/null +++ b/test/unit/specs/composables/use-window-scroll.spec.ts @@ -0,0 +1,65 @@ +import Vue from 'vue' +import { ref } from '@nuxtjs/composition-api' +import { render } from '@testing-library/vue' + +import { useWindowScroll } from '~/composables/use-window-scroll' + +const getMockWindow = (props: T) => + ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + ...props, + } as unknown as typeof window) + +const UseWindowScrollTestContainer = Vue.component( + 'UseWindowScrollTestContainer', + { + props: ['initX', 'initY', 'throttleMs'], + setup(props) { + return useWindowScroll({ + window: getMockWindow({ + scrollX: props.initX, + scrollY: props.initY, + }), + throttleMs: props.throttleMs as number | undefined, + }) + }, + template: '
x={{x}} y={{y}} isScrolled={{isScrolled}}
', + } +) + +describe('useWindowScroll', () => { + it('should return [0, 0] and false when no window', () => { + expect(useWindowScroll({})).toMatchObject({ + x: ref(0), + y: ref(0), + isScrolled: ref(false), + }) + }) + + it("should return the window's scroll position and not scrolled when y == 0", () => { + const { container } = render(UseWindowScrollTestContainer, { + props: { + initX: 10, + initY: 0, + }, + }) + + expect(container.firstChild?.textContent).toEqual( + 'x=10 y=0 isScrolled=false' + ) + }) + + it("should return the window's scroll position and scrolled when y != 0", () => { + const { container } = render(UseWindowScrollTestContainer, { + props: { + initX: 31, + initY: 1, + }, + }) + + expect(container.firstChild?.textContent).toEqual( + 'x=31 y=1 isScrolled=true' + ) + }) +})