solid-virtual.test.ts 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { expect, test } from "bun:test"
  2. import { createVirtualizer, defaultRangeExtractor } from "@tanstack/solid-virtual"
  3. import { createRoot, createSignal } from "solid-js"
  4. import { filterVirtualIndexes } from "@/pages/session/timeline/virtual-items"
  5. test("reactive count updates preserve measured row sizes", () => {
  6. createRoot((dispose) => {
  7. const [count, setCount] = createSignal(2)
  8. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  9. get count() {
  10. return count()
  11. },
  12. getScrollElement: () => null,
  13. estimateSize: () => 60,
  14. initialRect: { width: 800, height: 600 },
  15. })
  16. expect(virtualizer.getTotalSize()).toBe(120)
  17. virtualizer.resizeItem(0, 100)
  18. expect(virtualizer.getTotalSize()).toBe(160)
  19. setCount(3)
  20. expect(virtualizer.itemSizeCache.get(0)).toBe(100)
  21. expect(virtualizer.getTotalSize()).toBe(220)
  22. dispose()
  23. })
  24. })
  25. test("initial rect projects rows before a scroll element connects", () => {
  26. createRoot((dispose) => {
  27. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  28. count: 100,
  29. getScrollElement: () => null,
  30. estimateSize: () => 28,
  31. initialRect: { width: 0, height: 600 },
  32. overscan: 10,
  33. })
  34. expect(virtualizer.getVirtualItems().length).toBeGreaterThan(0)
  35. dispose()
  36. })
  37. })
  38. test("logical scroll offset includes pending measurement adjustments", () => {
  39. createRoot((dispose) => {
  40. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  41. count: 2,
  42. getScrollElement: () => null,
  43. estimateSize: () => 60,
  44. initialOffset: 100,
  45. initialRect: { width: 800, height: 60 },
  46. })
  47. virtualizer.getTotalSize()
  48. virtualizer.resizeItem(0, 100)
  49. expect(virtualizer.scrollOffset).toBe(100)
  50. expect(virtualizer.getLogicalScrollOffset()).toBe(140)
  51. dispose()
  52. })
  53. })
  54. test("stale pinned indexes do not produce missing virtual items after count shrinks", () => {
  55. createRoot((dispose) => {
  56. const [count, setCount] = createSignal(2)
  57. const pinned = [1]
  58. const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
  59. get count() {
  60. return count()
  61. },
  62. getScrollElement: () => null,
  63. estimateSize: () => 60,
  64. initialRect: { width: 800, height: 600 },
  65. rangeExtractor: (range) =>
  66. filterVirtualIndexes([...new Set([...defaultRangeExtractor(range), ...pinned])], range.count),
  67. })
  68. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([0, 1])
  69. setCount(1)
  70. expect(virtualizer.getVirtualItems().map((item) => item.index)).toEqual([0])
  71. expect(() => new Map(virtualizer.getVirtualItems().map((item) => [item.key, item]))).not.toThrow()
  72. dispose()
  73. })
  74. })