123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- // @ts-nocheck
- import { nextTick, ref } from 'vue'
- import { mount } from '@vue/test-utils'
- import {
- afterAll,
- afterEach,
- beforeAll,
- describe,
- expect,
- test,
- vi,
- } from 'vitest'
- import defineGetter from '@element-plus/test-utils/define-getter'
- import makeScroll from '@element-plus/test-utils/make-scroll'
- import tick from '@element-plus/test-utils/tick'
- import InfiniteScroll, { DEFAULT_DELAY, SCOPE } from '../src'
- vi.mock('lodash-unified', () => {
- return {
- throttle: vi.fn((fn) => {
- fn.cancel = vi.fn()
- fn.flush = vi.fn()
- return fn
- }),
- }
- })
- const CONTAINER_HEIGHT = 200
- const ITEM_HEIGHT = 100
- const CONTAINER_STYLE = `overflow-y: auto;`
- const LIST_ITEM_CLASS = 'list-item'
- const LIST_ITEM_STYLE = `height: ${ITEM_HEIGHT}px;`
- const INITIAL_VALUE = 3
- // INITIAL_TICK = INITIAL_VALUE * MOUNT_ONE_NEED_TICKS + INITIAL_TICK
- const INITIAL_TICK = INITIAL_VALUE * 2 + 1
- const CUSTOM_DELAY = 0
- const CUSTOM_DISTANCE = 10
- let clientHeightRestore = null
- let scrollHeightRestore = null
- const _mount = (options: Record<string, unknown>) =>
- mount(
- {
- ...options,
- template: `
- <ul v-infinite-scroll="load" ${options.extraAttrs} ref="ulRef">
- <li
- v-for="i in count"
- :key="i"
- class="${LIST_ITEM_CLASS}"
- style="${LIST_ITEM_STYLE}"
- >{{ i }}</li>
- </ul>
- `,
- directives: {
- InfiniteScroll,
- },
- },
- { attachTo: document.body }
- )
- const setup = function () {
- const count = ref(0)
- const load = () => {
- count.value += 1
- }
- return { count, load }
- }
- const countListItem = (wrapper: any) =>
- wrapper.findAll(`.${LIST_ITEM_CLASS}`).length
- beforeAll(() => {
- clientHeightRestore = defineGetter(
- window.HTMLElement.prototype,
- 'clientHeight',
- CONTAINER_HEIGHT,
- 0
- )
- scrollHeightRestore = defineGetter(
- window.HTMLElement.prototype,
- 'scrollHeight',
- function () {
- return (
- // eslint-disable-next-line unicorn/prefer-query-selector
- Array.from(this.getElementsByClassName(LIST_ITEM_CLASS)).length *
- ITEM_HEIGHT
- )
- },
- 0
- )
- })
- afterAll(() => {
- clientHeightRestore()
- scrollHeightRestore()
- })
- afterEach(() => {
- const app = document.querySelector('[data-v-app]')
- document.body.removeChild(app)
- })
- describe('InfiniteScroll', () => {
- test('scrollable container is the element to which the directive is bound', async () => {
- const wrapper = _mount({
- extraAttrs: `style="${CONTAINER_STYLE}"`,
- setup,
- })
- const el = wrapper.element
- // wait to ensure initial full check has finished
- await tick(INITIAL_TICK)
- expect(el[SCOPE].container).toEqual(el)
- expect(el[SCOPE].containerEl).toEqual(el)
- expect(el[SCOPE].delay).toEqual(DEFAULT_DELAY)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- // ensure observer has been destroyed, otherwise will cause memory leak
- expect(el[SCOPE].observer).toBeUndefined()
- // won't trigger load when not reach the bottom distance
- await makeScroll(el, 'scrollTop', ITEM_HEIGHT - 1)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- await makeScroll(el, 'scrollTop', ITEM_HEIGHT)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- // won't trigger load when scroll back
- await makeScroll(el, 'scrollTop', 0)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- })
- test('custom scroll delay', async () => {
- const wrapper = _mount({
- extraAttrs: `infinite-scroll-delay="${CUSTOM_DELAY}" style="${CONTAINER_STYLE}"`,
- setup,
- })
- const el = wrapper.element
- await nextTick()
- expect(el[SCOPE].delay).toBe(CUSTOM_DELAY)
- })
- test('custom scroll distance', async () => {
- const wrapper = _mount({
- extraAttrs: `infinite-scroll-distance="${CUSTOM_DISTANCE}" style="${CONTAINER_STYLE}"`,
- setup,
- })
- const el = wrapper.element
- // wait to ensure initial full check has finished
- await tick(INITIAL_TICK)
- await makeScroll(el, 'scrollTop', ITEM_HEIGHT - CUSTOM_DISTANCE)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- })
- test('turn off immediate check', async () => {
- const wrapper = _mount({
- extraAttrs: `infinite-scroll-immediate="false" style="${CONTAINER_STYLE}"`,
- setup,
- })
- await tick(INITIAL_TICK)
- expect(countListItem(wrapper)).toBe(0)
- })
- test('limited scroll with `disabled` option', async () => {
- const wrapper = _mount({
- extraAttrs: `infinite-scroll-disabled="disabled" style="${CONTAINER_STYLE}"`,
- setup() {
- const count = ref(0)
- const disabled = ref(false)
- const load = () => {
- count.value += 1
- disabled.value = count.value >= INITIAL_VALUE + 1
- }
- return { count, load, disabled }
- },
- })
- const el = wrapper.element
- // wait to ensure initial full check has finished
- await tick(INITIAL_TICK)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- await makeScroll(el, 'scrollTop', ITEM_HEIGHT)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- // no more items are loaded since `disabled = true`
- await makeScroll(el, 'scrollTop', ITEM_HEIGHT + 1)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- })
- test('scrollable container is document.documentElement', async () => {
- const wrapper = _mount({
- setup,
- })
- const el = wrapper.element
- const { documentElement } = document
- // wait to ensure initial full check has finished
- await tick(INITIAL_TICK)
- expect(el[SCOPE].container).toEqual(window)
- expect(el[SCOPE].containerEl).toEqual(documentElement)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- // won't trigger load when not reach the bottom distance
- await makeScroll(documentElement, 'scrollTop', ITEM_HEIGHT - 1)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- await makeScroll(documentElement, 'scrollTop', ITEM_HEIGHT)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- // won't trigger load when scroll back
- await makeScroll(documentElement, 'scrollTop', 0)
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
- })
- test('callback will not be triggered infinitely', async () => {
- const restoreClientHeight = defineGetter(
- window.HTMLElement.prototype,
- 'clientHeight',
- 0,
- CONTAINER_HEIGHT
- )
- const restoreScrollHeight = defineGetter(
- window.HTMLElement.prototype,
- 'scrollHeight',
- 0,
- function () {
- return (
- // eslint-disable-next-line unicorn/prefer-query-selector
- Array.from(this.getElementsByClassName(LIST_ITEM_CLASS)).length *
- ITEM_HEIGHT
- )
- }
- )
- const wrapper = _mount({
- extraAttrs: `style="${CONTAINER_STYLE}"`,
- setup,
- })
- await tick(INITIAL_TICK)
- expect(countListItem(wrapper)).toBe(0)
- restoreClientHeight()
- restoreScrollHeight()
- wrapper.vm.$refs.ulRef.ElInfiniteScroll.instance.count++
- await nextTick()
- expect(countListItem(wrapper)).toBe(INITIAL_VALUE)
- })
- })
|