90 lines
3.4 KiB
TypeScript
90 lines
3.4 KiB
TypeScript
import type { BlockBox } from './scrollPosition'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { anchorAt, blockForLine, holdAt, scrollTopFor } from './scrollPosition'
|
|
|
|
// 页面上的块:顶部有 20px 工具栏,块与块之间 8px 间距
|
|
const boxes: BlockBox[] = [
|
|
{ line: 0, top: 20, bottom: 60 },
|
|
{ line: 3, top: 68, bottom: 108 },
|
|
{ line: 4, top: 116, bottom: 196 },
|
|
{ line: 10, top: 204, bottom: 244 },
|
|
]
|
|
|
|
describe('anchorAt:视口顶部那块', () => {
|
|
it('视口顶部落在块中间:记这块的起始行和块内偏移', () => {
|
|
expect(anchorAt(boxes, 150)).toEqual({ line: 4, offset: 34, scrollTop: 150 })
|
|
})
|
|
|
|
it('视口顶部落在块间空隙:取下面那块,偏移为负', () => {
|
|
expect(anchorAt(boxes, 110)).toEqual({ line: 4, offset: -6, scrollTop: 110 })
|
|
})
|
|
|
|
it('还在最顶上:取第一块', () => {
|
|
expect(anchorAt(boxes, 0)).toEqual({ line: 0, offset: -20, scrollTop: 0 })
|
|
})
|
|
|
|
it('所有块都滚过去了:取最后一块', () => {
|
|
expect(anchorAt(boxes, 300)).toEqual({ line: 10, offset: 96, scrollTop: 300 })
|
|
})
|
|
|
|
it('没有块:没有位置可记', () => {
|
|
expect(anchorAt([], 50)).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('holdAt:页面变了也钉住不动的那块', () => {
|
|
it('视口顶部落在块中间:钉这块', () => {
|
|
expect(holdAt(boxes, 150)).toEqual({ line: 4, offset: 34, scrollTop: 150 })
|
|
})
|
|
|
|
it('视口顶部落在块间空隙(或上面那块的问答区)里:钉上面那块,下面那块长高不牵动视口', () => {
|
|
expect(holdAt(boxes, 110)).toEqual({ line: 3, offset: 42, scrollTop: 110 })
|
|
})
|
|
|
|
it('还在所有块上面:不钉', () => {
|
|
expect(holdAt(boxes, 0)).toBeUndefined()
|
|
})
|
|
|
|
it('起始行相同的外层块和第一个子块:钉靠前的那块,按起始行找回来还是原处', () => {
|
|
const nested = [{ line: 0, top: 20, bottom: 60 }, { line: 4, top: 68, bottom: 100 }, { line: 4, top: 108, bottom: 200 }]
|
|
const anchor = holdAt(nested, 150)!
|
|
expect(anchor).toEqual({ line: 4, offset: 82, scrollTop: 150 })
|
|
expect(scrollTopFor(nested, anchor)).toBe(150)
|
|
})
|
|
})
|
|
|
|
describe('scrollTopFor:按记下的位置恢复', () => {
|
|
it('内容没变:回到原来的 scrollTop', () => {
|
|
expect(scrollTopFor(boxes, anchorAt(boxes, 150)!)).toBe(150)
|
|
})
|
|
|
|
it('隐藏期间上面多了一块:跟着那块走,而不是停在原来的像素', () => {
|
|
const anchor = anchorAt(boxes, 150)!
|
|
const edited = [{ line: 0, top: 20, bottom: 60 }, { line: 1, top: 68, bottom: 108 }, ...boxes.slice(1).map(b => ({ ...b, top: b.top + 48, bottom: b.bottom + 48 }))]
|
|
expect(scrollTopFor(edited, anchor)).toBe(198)
|
|
})
|
|
|
|
it('那一行已经没有块了:退回原来的 scrollTop', () => {
|
|
expect(scrollTopFor(boxes, { line: 7, offset: 12, scrollTop: 140 })).toBe(140)
|
|
})
|
|
})
|
|
|
|
describe('blockForLine:包含某行的块', () => {
|
|
it('正好是块的起始行', () => {
|
|
expect(blockForLine(boxes, 4)?.line).toBe(4)
|
|
})
|
|
|
|
it('落在块中间或块后面的空行:取之前最近的块', () => {
|
|
expect(blockForLine(boxes, 8)?.line).toBe(4)
|
|
expect(blockForLine(boxes, 99)?.line).toBe(10)
|
|
})
|
|
|
|
it('在所有块之前:取第一块', () => {
|
|
expect(blockForLine([{ line: 5, top: 20, bottom: 60 }, { line: 9, top: 68, bottom: 108 }], 2)?.line).toBe(5)
|
|
})
|
|
|
|
it('没有块:找不到', () => {
|
|
expect(blockForLine([], 3)).toBeUndefined()
|
|
})
|
|
})
|