solid-virtual.test.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { expect, test } from "bun:test"
  2. import { createVirtualizer, defaultRangeExtractor, Virtualizer } from "@tanstack/solid-virtual"
  3. import { createRoot, createSignal } from "solid-js"
  4. import { filterVirtualIndexes } from "@/pages/session/timeline/virtual-items"
  5. test("end anchoring survives consecutive resizes when the first scroll write is clamped", () => {
  6. const writes: { offset: number; adjustments?: number }[] = []
  7. const virtualizer = new Virtualizer<HTMLDivElement, HTMLDivElement>({
  8. count: 5,
  9. estimateSize: () => 50,
  10. initialOffset: 50,
  11. initialRect: { width: 400, height: 200 },
  12. anchorTo: "end",
  13. scrollEndThreshold: 1,
  14. getScrollElement: () => null,
  15. scrollToFn: (offset, options) => writes.push({ offset, adjustments: options.adjustments }),
  16. observeElementRect: () => {},
  17. observeElementOffset: () => {},
  18. })
  19. virtualizer.getTotalSize()
  20. virtualizer.resizeItem(4, 120)
  21. expect(writes).toEqual([{ offset: 50, adjustments: 70 }])
  22. writes.length = 0
  23. virtualizer.resizeItem(4, 200)
  24. expect(writes).toEqual([{ offset: 120, adjustments: 80 }])
  25. })
  26. test("reactive count updates preserve measured row sizes", () => {
  27. createRoot((dispose) => {
  28. const [count, setCount] = createSignal(2)
  29. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  30. get count() {
  31. return count()
  32. },
  33. getScrollElement: () => null,
  34. estimateSize: () => 60,
  35. initialRect: { width: 800, height: 600 },
  36. })
  37. expect(virtualizer.getTotalSize()).toBe(120)
  38. virtualizer.resizeItem(0, 100)
  39. expect(virtualizer.getTotalSize()).toBe(160)
  40. setCount(3)
  41. expect(virtualizer.itemSizeCache.get(0)).toBe(100)
  42. expect(virtualizer.getTotalSize()).toBe(220)
  43. dispose()
  44. })
  45. })
  46. test("initial rect projects rows before a scroll element connects", () => {
  47. createRoot((dispose) => {
  48. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  49. count: 100,
  50. getScrollElement: () => null,
  51. estimateSize: () => 28,
  52. initialRect: { width: 0, height: 600 },
  53. overscan: 10,
  54. })
  55. expect(virtualizer.getVirtualItems().length).toBeGreaterThan(0)
  56. dispose()
  57. })
  58. })
  59. test("clamps oversized offsets with scroll margin and padding changes", () => {
  60. const options = (paddingEnd: number) => ({
  61. count: 20,
  62. estimateSize: () => 60,
  63. initialOffset: Number.MAX_SAFE_INTEGER,
  64. initialRect: { width: 800, height: 600 },
  65. scrollMargin: 64,
  66. paddingEnd,
  67. overscan: 1,
  68. getScrollElement: () => null,
  69. scrollToFn: () => {},
  70. observeElementRect: () => {},
  71. observeElementOffset: () => {},
  72. })
  73. const virtualizer = new Virtualizer<HTMLDivElement, HTMLDivElement>(options(64))
  74. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
  75. virtualizer.setOptions(options(600))
  76. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([18, 19])
  77. })
  78. test("stale pinned indexes do not produce missing virtual items after count shrinks", () => {
  79. createRoot((dispose) => {
  80. const [count, setCount] = createSignal(2)
  81. const pinned = [1]
  82. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  83. get count() {
  84. return count()
  85. },
  86. getScrollElement: () => null,
  87. estimateSize: () => 60,
  88. initialRect: { width: 800, height: 600 },
  89. rangeExtractor: (range) =>
  90. filterVirtualIndexes([...new Set([...defaultRangeExtractor(range), ...pinned])], range.count),
  91. })
  92. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([0, 1])
  93. setCount(1)
  94. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([0])
  95. expect(() => new Map(virtualizer.getVirtualItems().map((item) => [item.key, item]))).not.toThrow()
  96. dispose()
  97. })
  98. })