UNPKG

element-plus

Version:

A Component Library for Vue3.0

378 lines (302 loc) 10 kB
import { nextTick } from 'vue' import makeMount from '@element-plus/test-utils/make-mount' import makeScroll from '@element-plus/test-utils/make-scroll' import setupMock from '../setup-mock' import { RTL, HORIZONTAL, CENTERED_ALIGNMENT, START_ALIGNMENT, END_ALIGNMENT, SMART_ALIGNMENT, } from '../src/defaults' import { FixedSizeList } from '..' import type { ListExposes } from '../src/types' type ListRef = ListExposes const onItemRendered = jest.fn() const WINDOW_KLS = 'window' const WINDOW_SELECTOR = `.${WINDOW_KLS}` const ITEM_KLS = 'item' const ITEM_SELECTOR = `.${ITEM_KLS}` const mount = makeMount( { template: `<fixed-size-list v-bind="$attrs" ref="listRef"> <template #default="{index, style}"> <div class="${ITEM_KLS}" :style="style">item {{ index }}</div> </template> </fixed-size-list>`, components: { FixedSizeList, }, }, { props: { cache: 3, className: WINDOW_KLS, height: 100, total: 100, itemSize: 25, width: 50, onItemRendered, }, }, ) let cleanup: () => void describe('<fixed-size-list />', () => { beforeAll(() => { cleanup = setupMock() }) afterAll(() => { cleanup() }) beforeEach(() => { onItemRendered.mockClear() }) it('should render correctly', async () => { const wrapper = mount() await nextTick() // due to the default layout is vertical, so we use height to calc // because the height is 100 item size is 25 so we have visible // item 4 // then we added cache as 3 (because we are currently at the top // which means we do not have cache before the items) // so we have cache of 3 // the total of items should be 4 + 3 = 7 expect(wrapper.findAll(`.${ITEM_KLS}`)).toHaveLength(7) expect( wrapper .find(WINDOW_SELECTOR) .element.firstElementChild.getAttribute('style'), ).toBe('height: 2500px; width: 100%;') expect(onItemRendered).toHaveBeenCalledTimes(1) }) it('should render 0 item when total is 0', async () => { const wrapper = mount({ props: { total: 0, }, }) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(0) }) it('should early terminate scroll handler when the scrollTo equals to current offset', async () => { const wrapper = mount() await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(0) await makeScroll( (wrapper.vm.$refs.listRef as ListRef).windowRef, 'scrollTop', 0, ) expect(wrapper.find(ITEM_SELECTOR).text()).toContain(0) await wrapper.setProps({ layout: HORIZONTAL, }) await makeScroll( (wrapper.vm.$refs.listRef as ListRef).windowRef, 'scrollLeft', 0, ) expect(wrapper.find(ITEM_SELECTOR).text()).toContain(0) }) it('should render correct items to the dom', async () => { const wrapper = mount() await nextTick() // window ref has onScroll handler so we trigger scroll on windowRef const { windowRef } = wrapper.vm.$refs.listRef as ListRef expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) expect(onItemRendered).toHaveBeenCalledTimes(1) makeScroll(windowRef, 'scrollTop', 100) await nextTick() // from index 3(item 4) + 4 visible items + 3 cache items = index 10 // the total items rendered is 3 + 4 + 1 (index 3) inclusive // so the total number is 10 expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(8) }) it('should set initial offset', async () => { const wrapper = mount({ props: { initScrollOffset: 100, }, }) await nextTick() // 10 items = 3 backward invisible items + 4 visible items + 3 forward invisible items expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(10) expect(onItemRendered).toHaveBeenLastCalledWith(1, 10, 4, 7) }) it('should render horizontal list', async () => { const wrapper = mount({ props: { layout: HORIZONTAL, }, }) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(5) expect( wrapper .find(WINDOW_SELECTOR) .element.firstElementChild.getAttribute('style'), ).toBe('height: 100%; width: 2500px;') }) it('should handle horizontal scroll correctly', async () => { const wrapper = mount({ props: { layout: HORIZONTAL, }, }) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(5) const { windowRef } = wrapper.vm.$refs.listRef as ListRef makeScroll(windowRef, 'scrollLeft', 100) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(6) expect(wrapper.find(ITEM_SELECTOR).text()).toContain(3) }) it('should render rtl direction', async () => { const wrapper = mount({ props: { direction: RTL, }, }) await nextTick() expect( wrapper .find(WINDOW_SELECTOR) .element.getAttribute('style') .includes(`direction: ${RTL}`), ).toBe(true) const style = wrapper.find(ITEM_SELECTOR).element.getAttribute('style') expect(style).toContain('right') expect(style).not.toContain('left') }) it('should update rendered items when cache changes', async () => { const wrapper = mount() await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) await wrapper.setProps({ cache: 4, }) expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(8) }) it('should update rendered items when item size changed', async () => { const wrapper = mount() await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) await wrapper.setProps({ itemSize: 50, }) expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(5) }) describe('scrollTo', () => { it('should correctly scroll vertically', async () => { const wrapper = mount() await nextTick() const listRef = wrapper.vm.$refs.listRef as ListExposes expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) listRef.scrollTo(100) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(10) listRef.scrollTo(200) expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(10) }) it('should correctly scroll horizontally', async () => { const wrapper = mount({ props: { layout: HORIZONTAL, }, }) await nextTick() const listRef = wrapper.vm.$refs.listRef as ListExposes expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(5) listRef.scrollTo(100) await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(8) listRef.scrollTo(200) expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(8) }) it('should not scroll out of the boundary', async () => { const wrapper = mount({ props: { total: 10, }, }) await nextTick() const listRef = wrapper.vm.$refs.listRef as ListExposes expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) // item size is 25 total number is 10 so the boundary is offset 250 listRef.scrollTo(275) await nextTick() // when it reaches the boundary, it should only render visible ones. expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(4) }) }) describe('scrollToItem', () => { it('should scrollToItem correctly', async () => { // auto alignment const wrapper = mount() await nextTick() expect(wrapper.findAll(ITEM_SELECTOR)).toHaveLength(7) const listRef = wrapper.vm.$refs.listRef as ListExposes listRef.scrollToItem(10) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(4) listRef.scrollToItem(20) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(14) // out bounds listRef.scrollToItem(101) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(93) // start alignment listRef.scrollToItem(10, START_ALIGNMENT) await nextTick() // 10 - 3 (cache) expect(wrapper.find(ITEM_SELECTOR).text()).toContain(7) // center alignment listRef.scrollToItem(10, CENTERED_ALIGNMENT) await nextTick() // 10th item should be positioned in the middle, at position 3 // so there were 2 items left in the viewport // also we have 3 cache items. // so that we get the first item: 10 - 2 - 3 = 5th item expect(wrapper.find(ITEM_SELECTOR).text()).toContain(5) // centered alignment nearing the left boundary listRef.scrollToItem(1, CENTERED_ALIGNMENT) await nextTick() // centered alignment nearing the right boundary listRef.scrollToItem(101, CENTERED_ALIGNMENT) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(93) // end alignment listRef.scrollToItem(10, END_ALIGNMENT) await nextTick() // 10th item should be positioned at the end of the viewport // the viewport is size of 4, so there were 3 items left // and we have cache of 3, so the first item should be // 10 - 3 - 3 = 4th item expect(wrapper.find(ITEM_SELECTOR).text()).toContain(4) // smart alignment listRef.scrollToItem(10, SMART_ALIGNMENT) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(4) listRef.scrollToItem(100, SMART_ALIGNMENT) await nextTick() expect(wrapper.find(ITEM_SELECTOR).text()).toContain(93) }) }) describe('to throw', () => { it('should throw when layout is invalid', () => { try { const wrapper = mount({ props: { width: '100', height: '100', }, }) ;(wrapper.vm.$refs.listRef as ListRef).scrollToItem(10) } catch (e) { expect(e).toBeInstanceOf(Error) } }) }) })