40ba9f13e0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
94 lines
3.0 KiB
TypeScript
94 lines
3.0 KiB
TypeScript
import {describe, expect, it} from 'vitest'
|
|
import {defineComponent, nextTick, ref} from 'vue'
|
|
import {mount} from '@vue/test-utils'
|
|
import {
|
|
CENTER_OFFSET,
|
|
VISIBLE_ROWS,
|
|
loopCorrection,
|
|
scrollTopForValueIndex,
|
|
useInfiniteWheel,
|
|
valueIndexFromScroll,
|
|
} from './useInfiniteWheel'
|
|
|
|
const H = 40 // itemHeight
|
|
const LEN = 24 // ex. heures
|
|
|
|
describe('useInfiniteWheel — math pure', () => {
|
|
it('expose 5 lignes visibles et un offset central de 2', () => {
|
|
expect(VISIBLE_ROWS).toBe(5)
|
|
expect(CENTER_OFFSET).toBe(2)
|
|
})
|
|
|
|
it('scrollTopForValueIndex et valueIndexFromScroll font un aller-retour', () => {
|
|
for (const index of [0, 1, 9, 23]) {
|
|
const top = scrollTopForValueIndex(index, H, LEN)
|
|
expect(valueIndexFromScroll(top, H, LEN)).toBe(index)
|
|
}
|
|
})
|
|
|
|
it('valueIndexFromScroll boucle en modulo', () => {
|
|
const top = scrollTopForValueIndex(0, H, LEN)
|
|
expect(valueIndexFromScroll(top + LEN * H, H, LEN)).toBe(0)
|
|
})
|
|
|
|
it('loopCorrection laisse le scroll de la copie du milieu inchangé', () => {
|
|
const top = scrollTopForValueIndex(12, H, LEN)
|
|
expect(loopCorrection(top, H, LEN)).toBe(top)
|
|
})
|
|
|
|
it('loopCorrection ramène vers le milieu quand on dérive vers le haut', () => {
|
|
const drifted = scrollTopForValueIndex(0, H, LEN) - LEN * H
|
|
expect(loopCorrection(drifted, H, LEN)).toBe(drifted + LEN * H)
|
|
})
|
|
|
|
it('loopCorrection ramène vers le milieu quand on dérive vers le bas', () => {
|
|
const drifted = scrollTopForValueIndex(0, H, LEN) + LEN * H
|
|
expect(loopCorrection(drifted, H, LEN)).toBe(drifted - LEN * H)
|
|
})
|
|
})
|
|
|
|
function mountWheelHarness(initialIndex: number, onChange: (i: number) => void) {
|
|
let api!: ReturnType<typeof useInfiniteWheel>
|
|
const Harness = defineComponent({
|
|
setup() {
|
|
const container = ref<HTMLElement | null>(null)
|
|
api = useInfiniteWheel(container, {
|
|
length: 24,
|
|
itemHeight: 40,
|
|
initialIndex: () => initialIndex,
|
|
onChange,
|
|
})
|
|
return {container}
|
|
},
|
|
template: '<div ref="container" style="height:200px;overflow:auto"><div style="height:2880px" /></div>',
|
|
})
|
|
const wrapper = mount(Harness, {attachTo: document.body})
|
|
return {wrapper, api: () => api}
|
|
}
|
|
|
|
describe('useInfiniteWheel — composable', () => {
|
|
it('step(+1) émet l\'index suivant', async () => {
|
|
const changes: number[] = []
|
|
const {api} = mountWheelHarness(9, (i) => changes.push(i))
|
|
await nextTick()
|
|
api().step(1)
|
|
expect(changes.at(-1)).toBe(10)
|
|
})
|
|
|
|
it('step boucle de 23 à 0', async () => {
|
|
const changes: number[] = []
|
|
const {api} = mountWheelHarness(23, (i) => changes.push(i))
|
|
await nextTick()
|
|
api().step(1)
|
|
expect(changes.at(-1)).toBe(0)
|
|
})
|
|
|
|
it('onKeydown ArrowUp décrémente (avec wrap)', async () => {
|
|
const changes: number[] = []
|
|
const {api} = mountWheelHarness(0, (i) => changes.push(i))
|
|
await nextTick()
|
|
api().onKeydown(new KeyboardEvent('keydown', {key: 'ArrowUp'}))
|
|
expect(changes.at(-1)).toBe(23)
|
|
})
|
|
})
|