UNPKG

@better-scroll/wheel

Version:

a BetterScroll plugin to imitate IOS Picker

412 lines (365 loc) 11.7 kB
import BScroll, { Boundary } from '@better-scroll/core' import Wheel from '../index' jest.mock('@better-scroll/core') const createWheel = (wheelOptions: Object) => { const wrapper = document.createElement('div') const content = document.createElement('div') wrapper.appendChild(content) const scroll = new BScroll(wrapper, { wheel: wheelOptions }) const wheel = new Wheel(scroll) return { scroll, wheel } } const addPropertiesToWheel = <T extends Object>(wheel: Wheel, obj: T) => { for (const key in obj) { ;(wheel as any)[key] = obj[key] } return wheel } describe('wheel plugin tests', () => { let scroll: BScroll let wheel: Wheel beforeEach(() => { const created = createWheel({}) // create DOM wheel = created.wheel scroll = created.scroll }) afterEach(() => { jest.clearAllMocks() }) it('should proxy properties to BScroll instance', () => { expect(scroll.proxy).toBeCalled() expect(scroll.proxy).toHaveBeenLastCalledWith([ { key: 'wheelTo', sourceKey: 'plugins.wheel.wheelTo' }, { key: 'getSelectedIndex', sourceKey: 'plugins.wheel.getSelectedIndex' }, { key: 'restorePosition', sourceKey: 'plugins.wheel.restorePosition' } ]) }) it('should handle options', () => { expect(wheel.options.rotate).toBe(25) expect(wheel.options.adjustTime).toBe(400) expect(wheel.options.selectedIndex).toBe(0) expect(wheel.options.wheelWrapperClass).toBe('wheel-scroll') expect(wheel.options.wheelItemClass).toBe('wheel-item') expect(wheel.options.wheelDisabledItemClass).toBe('wheel-disabled-item') }) it('should refresh BehaviorX and BehaviorY boundary', () => { const { scrollBehaviorX, scrollBehaviorY } = scroll.scroller expect(scrollBehaviorX.refresh).toBeCalled() expect(scrollBehaviorY.refresh).toBeCalled() }) it('should handle selectedIndex', () => { // default expect(wheel.selectedIndex).toBe(0) // specified const { wheel: wheel2 } = createWheel({ selectedIndex: 2 }) expect(wheel2.selectedIndex).toBe(2) }) it('should trigger scroll.scrollTo when invoking wheelTo method', () => { addPropertiesToWheel(wheel, { itemHeight: 40 }) wheel.wheelTo(0) expect(scroll.scrollTo).toBeCalled() expect(scroll.scrollTo).toHaveBeenLastCalledWith(0, -0, 0, undefined) }) it('should return seletedIndex when invoking getSelectedIndex', () => { const { wheel: wheel2 } = createWheel({ selectedIndex: 2 }) expect(wheel2.getSelectedIndex()).toBe(2) }) it('should support scrollTo somewhere by selectedIndex when initialized', () => { addPropertiesToWheel(wheel, { selectedIndex: 1, itemHeight: 50 }) const postion = { x: 100, y: 100 } // manually trigger scroll.hooks.trigger(scroll.hooks.eventTypes.beforeInitialScrollTo, postion) expect(postion).toMatchObject({ x: 0, y: -50 }) }) it('should invoke wheelTo when scroll.scroller trigger checkClick hook', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], target: div, wheelTo: jest.fn() }) scroll.scroller.hooks.trigger('checkClick') expect(wheel.wheelTo).toBeCalled() expect(wheel.wheelTo).toHaveBeenCalledWith(0, 400, expect.anything()) // if target element is not found addPropertiesToWheel(wheel, { items: [div], target: null, wheelTo: jest.fn() }) let ret = scroll.scroller.hooks.trigger('checkClick') expect(ret).toBe(true) }) it('should invoke findNearestValidWheel when scroll.scroller trigger scrollTo hook', () => { let endPoint = { x: 0, y: -20 } let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], target: div, itemHeight: 40, wheelTo: jest.fn() }) scroll.scroller.hooks.trigger('scrollTo', endPoint) expect(endPoint.y).toBe(-0) }) it('should change position when scroll.scroller trigger scrollToElement hook', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], target: div, itemHeight: 40 }) let pos = { top: -20, left: 0 } div.className = 'wheel-item' scroll.scroller.hooks.trigger('scrollToElement', div, pos) expect(pos).toEqual({ top: -0, left: 0 }) // mismatch target element let div1 = document.createElement('div') let pos1 = { top: -40, left: 0 } addPropertiesToWheel(wheel, { items: [div1], target: div1, itemHeight: 40 }) let ret = scroll.scroller.hooks.trigger('scrollToElement', div1, pos1) expect(ret).toBe(true) expect(pos1).toMatchObject({ top: -40, left: 0 }) }) it('should change target when scroll.scroller.actionsHandler trigger beforeStart hook', () => { let e = {} as any let div = document.createElement('div') e.target = div scroll.scroller.actionsHandler.hooks.trigger('beforeStart', e) expect(wheel.target).toEqual(div) }) it('should modify boundary when scrollBehaviorY or scrollBehaviorX computedBoundary', () => { let div = document.createElement('div') let cachedXBoundary = {} as Boundary let cachedYBoundary = {} as Boundary addPropertiesToWheel(wheel, { items: [div, div], itemHight: 50 }) const { scrollBehaviorX, scrollBehaviorY } = scroll.scroller // append two element scroll.scroller.content.appendChild(document.createElement('div')) scroll.scroller.content.appendChild(document.createElement('div')) scrollBehaviorY.contentSize = 100 // manually trigger scrollBehaviorX.hooks.trigger( scrollBehaviorX.hooks.eventTypes.computeBoundary, cachedXBoundary ) scrollBehaviorY.hooks.trigger( scrollBehaviorY.hooks.eventTypes.computeBoundary, cachedYBoundary ) expect(cachedXBoundary).toMatchObject({ minScrollPos: 0, maxScrollPos: 0 }) expect(cachedYBoundary).toMatchObject({ minScrollPos: 0, maxScrollPos: -50 }) }) it('should change momentumInfo when scroll.scroller.scrollBehaviorY trigger momentum or end hook', () => { let momentumInfo = { destination: 0, rate: 15 } let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], target: div, itemHeight: 40 }) scroll.scroller.scrollBehaviorY.hooks.trigger('momentum', momentumInfo) expect(momentumInfo).toEqual({ destination: -0, rate: 4 }) scroll.scroller.scrollBehaviorY.currentPos = -20 scroll.scroller.scrollBehaviorY.hooks.trigger('end', momentumInfo) expect(momentumInfo).toEqual({ destination: -0, rate: 4, duration: 400 }) scroll.scroller.scrollBehaviorY.hooks.trigger('momentum', momentumInfo, 800) expect(momentumInfo).toEqual({ destination: -0, rate: 4, duration: 400 }) }) it('scroll.hooks.refresh ', () => { let newContent = document.createElement('p') let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], target: div, itemHeight: 40 }) wheel.options.selectedIndex = 1 scroll.hooks.trigger(scroll.hooks.eventTypes.refresh, newContent) expect(scroll.scrollTo).toBeCalledWith(0, -40, 0, undefined) }) it('scroll.scroller.animater.hooks.time ', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div] }) const animater = scroll.scroller.animater animater.hooks.trigger(animater.hooks.eventTypes.time, 100) expect(div.style.transitionDuration).toBe('100ms') }) it('scroll.scroller.animater.hooks.timeFunction ', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div] }) const animater = scroll.scroller.animater animater.hooks.trigger( animater.hooks.eventTypes.timeFunction, 'cubic-bezier(0.23, 1, 0.32, 1)' ) expect(div.style.transitionTimingFunction).toBe( 'cubic-bezier(0.23, 1, 0.32, 1)' ) }) it('scroll.scroller.animater.hooks.callStop', () => { let div1 = document.createElement('div') let div2 = document.createElement('div') addPropertiesToWheel(wheel, { items: [div1, div2], itemHeight: 40, wheelItemsAllDisabled: false }) scroll.y = -41 scroll.maxScrollY = -80 scroll.scroller.animater.hooks.trigger('callStop') expect(scroll.scrollTo).toBeCalledWith(0, -40, 0, undefined) }) it('scroll.scroller.animater.translater.hooks.translate', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div], itemHeight: 40, wheelItemsAllDisabled: false }) const translater = scroll.scroller.animater.translater translater.hooks.trigger(translater.hooks.eventTypes.translate, { x: 0, y: -20 }) expect(wheel.selectedIndex).toEqual(0) }) it('scroll.scroller.hooks.minDistanceScroll ', () => { let div = document.createElement('div') addPropertiesToWheel(wheel, { items: [div] }) const scroller = scroll.scroller scroller.animater.forceStopped = true scroller.hooks.trigger(scroller.hooks.eventTypes.minDistanceScroll) expect(scroller.animater.forceStopped).toBe(false) }) it('scrollEnd event', () => { let div1 = document.createElement('div') let div2 = document.createElement('div') addPropertiesToWheel(wheel, { itemHeight: 40, items: [div1, div2] }) scroll.maxScrollY = -80 scroll.scroller.animater.forceStopped = true // stopped from an animation, // prevent user's scrollEnd callback triggered twice const ret = scroll.trigger(scroll.eventTypes.scrollEnd, { y: 0 }) expect(ret).toBe(true) wheel.isAdjustingPosition = true // update selectedIndex scroll.trigger(scroll.eventTypes.scrollEnd, { y: -41 }) expect(wheel.getSelectedIndex()).toBe(1) expect(wheel.isAdjustingPosition).toBe(false) }) it('wheel.restorePosition()', () => { addPropertiesToWheel(wheel, { itemHeight: 40 }) // simulate bs is scrolling scroll.pending = true wheel.restorePosition() expect(scroll.scroller.animater.clearTimer).toBeCalled() expect(scroll.scrollTo).toBeCalledWith(0, -0, 0, undefined) }) it('should support disable wheel items', () => { let div1 = document.createElement('div') let div2 = document.createElement('div') const scroller = scroll.scroller const position = { y: -41 } addPropertiesToWheel(wheel, { items: [div1, div2], itemHeight: 40, wheelItemsAllDisabled: false }) scroll.y = -41 scroll.maxScrollY = -80 div2.className = 'wheel-disabled-item' scroller.hooks.trigger(scroller.hooks.eventTypes.scrollTo, position) expect(position.y).toBe(-0) div1.className = 'wheel-disabled-item' wheel.wheelItemsAllDisabled = true scroller.hooks.trigger(scroller.hooks.eventTypes.scrollTo, position) expect(position.y).toBe(-0) let div3 = document.createElement('div') let position3 = { y: -39 } addPropertiesToWheel(wheel, { items: [div1, div2, div3], itemHeight: 40, wheelItemsAllDisabled: false }) scroller.hooks.trigger(scroller.hooks.eventTypes.scrollTo, position3) expect(position3.y).toBe(-80) }) })