2020-09-10 19:07:24 +08:00
|
|
|
import { ref, nextTick } from 'vue'
|
2021-09-17 15:27:31 +08:00
|
|
|
import { mount } from '@vue/test-utils'
|
2020-09-10 19:07:24 +08:00
|
|
|
import { tick, defineGetter, makeScroll } from '@element-plus/test-utils'
|
|
|
|
import InfiniteScroll, { SCOPE, DEFAULT_DELAY } from '../src/index'
|
2020-09-07 16:48:11 +08:00
|
|
|
|
|
|
|
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
|
2021-03-03 11:43:31 +08:00
|
|
|
// INITIAL_TICK = INITIAL_VALUE * MOUNT_ONE_NEED_TICKS + INITIAL_TICK
|
|
|
|
const INITIAL_TICK = INITIAL_VALUE * 2 + 1
|
2020-09-07 16:48:11 +08:00
|
|
|
const CUSTOM_DELAY = 0
|
|
|
|
const CUSTOM_DISTANCE = 10
|
|
|
|
|
|
|
|
let clientHeightRestore = null
|
|
|
|
let scrollHeightRestore = null
|
|
|
|
|
2021-09-04 19:29:28 +08:00
|
|
|
const _mount = (options: Record<string, unknown>) =>
|
|
|
|
mount(
|
|
|
|
{
|
|
|
|
...options,
|
|
|
|
template: `
|
2020-09-07 16:48:11 +08:00
|
|
|
<ul v-infinite-scroll="load" ${options.extraAttrs}>
|
|
|
|
<li
|
|
|
|
v-for="i in count"
|
|
|
|
:key="i"
|
|
|
|
class="${LIST_ITEM_CLASS}"
|
|
|
|
style="${LIST_ITEM_STYLE}"
|
|
|
|
>{{ i }}</li>
|
|
|
|
</ul>
|
|
|
|
`,
|
2021-09-04 19:29:28 +08:00
|
|
|
directives: {
|
|
|
|
InfiniteScroll,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{ attachTo: document.body }
|
|
|
|
)
|
2020-09-07 16:48:11 +08:00
|
|
|
|
|
|
|
const setup = function () {
|
|
|
|
const count = ref(0)
|
|
|
|
const load = () => {
|
|
|
|
count.value += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return { count, load }
|
|
|
|
}
|
|
|
|
|
2021-09-04 19:29:28 +08:00
|
|
|
const countListItem = (wrapper: any) =>
|
|
|
|
wrapper.findAll(`.${LIST_ITEM_CLASS}`).length
|
2020-09-07 16:48:11 +08:00
|
|
|
|
|
|
|
beforeAll(() => {
|
2021-09-04 19:29:28 +08:00
|
|
|
clientHeightRestore = defineGetter(
|
|
|
|
window.HTMLElement.prototype,
|
|
|
|
'clientHeight',
|
|
|
|
CONTAINER_HEIGHT,
|
|
|
|
0
|
|
|
|
)
|
|
|
|
scrollHeightRestore = defineGetter(
|
|
|
|
window.HTMLElement.prototype,
|
|
|
|
'scrollHeight',
|
|
|
|
function () {
|
|
|
|
return (
|
|
|
|
Array.from(this.getElementsByClassName(LIST_ITEM_CLASS)).length *
|
|
|
|
ITEM_HEIGHT
|
|
|
|
)
|
|
|
|
},
|
|
|
|
0
|
|
|
|
)
|
2020-09-07 16:48:11 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
afterAll(() => {
|
|
|
|
clientHeightRestore()
|
|
|
|
scrollHeightRestore()
|
|
|
|
})
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
const app = document.querySelector('#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
|
|
|
|
|
2020-09-10 19:07:24 +08:00
|
|
|
// wait to ensure initial full check has finished
|
2020-09-24 15:05:19 +08:00
|
|
|
await tick(INITIAL_TICK)
|
2020-09-07 16:48:11 +08:00
|
|
|
expect(el[SCOPE].container).toEqual(el)
|
|
|
|
expect(el[SCOPE].containerEl).toEqual(el)
|
2020-09-10 19:07:24 +08:00
|
|
|
expect(el[SCOPE].delay).toEqual(DEFAULT_DELAY)
|
2020-09-07 16:48:11 +08:00
|
|
|
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
|
|
|
|
|
2020-09-10 19:07:24 +08:00
|
|
|
await nextTick()
|
|
|
|
expect(el[SCOPE].delay).toBe(CUSTOM_DELAY)
|
2020-09-07 16:48:11 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
test('custom scroll distance', async () => {
|
|
|
|
const wrapper = _mount({
|
2020-09-10 19:07:24 +08:00
|
|
|
extraAttrs: `infinite-scroll-distance="${CUSTOM_DISTANCE}" style="${CONTAINER_STYLE}"`,
|
2020-09-07 16:48:11 +08:00
|
|
|
setup,
|
|
|
|
})
|
|
|
|
|
|
|
|
const el = wrapper.element
|
|
|
|
|
2020-09-10 19:07:24 +08:00
|
|
|
// wait to ensure initial full check has finished
|
2020-09-24 15:05:19 +08:00
|
|
|
await tick(INITIAL_TICK)
|
2020-09-07 16:48:11 +08:00
|
|
|
await makeScroll(el, 'scrollTop', ITEM_HEIGHT - CUSTOM_DISTANCE)
|
|
|
|
expect(countListItem(wrapper)).toBe(INITIAL_VALUE + 1)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('turn off immediate check', async () => {
|
|
|
|
const wrapper = _mount({
|
2020-09-10 19:07:24 +08:00
|
|
|
extraAttrs: `infinite-scroll-immediate="false" style="${CONTAINER_STYLE}"`,
|
2020-09-07 16:48:11 +08:00
|
|
|
setup,
|
|
|
|
})
|
|
|
|
|
2020-09-24 15:05:19 +08:00
|
|
|
await tick(INITIAL_TICK)
|
2020-09-07 16:48:11 +08:00
|
|
|
expect(countListItem(wrapper)).toBe(0)
|
|
|
|
})
|
|
|
|
|
|
|
|
test('limited scroll with `disabled` option', async () => {
|
|
|
|
const wrapper = _mount({
|
2020-09-10 19:07:24 +08:00
|
|
|
extraAttrs: `infinite-scroll-disabled="disabled" style="${CONTAINER_STYLE}"`,
|
2020-09-07 16:48:11 +08:00
|
|
|
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
|
|
|
|
|
2020-09-10 19:07:24 +08:00
|
|
|
// wait to ensure initial full check has finished
|
2020-09-24 15:05:19 +08:00
|
|
|
await tick(INITIAL_TICK)
|
2020-09-07 16:48:11 +08:00
|
|
|
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
|
|
|
|
|
2020-09-10 19:07:24 +08:00
|
|
|
// wait to ensure initial full check has finished
|
2020-09-24 15:05:19 +08:00
|
|
|
await tick(INITIAL_TICK)
|
2020-09-07 16:48:11 +08:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
})
|