scroll-view.test.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { describe, expect, test } from "bun:test"
  2. import { canScrollKey, scrollKey, scrollTopFromThumbPointer } from "./scroll-view"
  3. describe("scrollKey", () => {
  4. test("maps plain navigation keys", () => {
  5. expect(scrollKey({ key: "PageDown", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe(
  6. "page-down",
  7. )
  8. expect(scrollKey({ key: "ArrowUp", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe("up")
  9. })
  10. test("ignores modified keybinds", () => {
  11. expect(
  12. scrollKey({ key: "ArrowDown", altKey: false, ctrlKey: false, metaKey: true, shiftKey: false }),
  13. ).toBeUndefined()
  14. expect(scrollKey({ key: "PageUp", altKey: false, ctrlKey: true, metaKey: false, shiftKey: false })).toBeUndefined()
  15. expect(scrollKey({ key: "End", altKey: false, ctrlKey: false, metaKey: false, shiftKey: true })).toBeUndefined()
  16. })
  17. test("maps space and shift-space directions", () => {
  18. expect(scrollKey({ key: " ", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe("page-down")
  19. expect(scrollKey({ key: " ", altKey: false, ctrlKey: false, metaKey: false, shiftKey: true })).toBe("page-up")
  20. })
  21. })
  22. describe("canScrollKey", () => {
  23. const element = (scrollTop: number, clientHeight = 100, scrollHeight = 300) =>
  24. ({ scrollTop, clientHeight, scrollHeight }) as HTMLElement
  25. test("owns upward keys only above the top boundary", () => {
  26. expect(canScrollKey(element(50), "page-up")).toBe(true)
  27. expect(canScrollKey(element(0), "page-up")).toBe(false)
  28. })
  29. test("owns downward keys only before the bottom boundary", () => {
  30. expect(canScrollKey(element(50), "page-down")).toBe(true)
  31. expect(canScrollKey(element(200), "page-down")).toBe(false)
  32. expect(canScrollKey(element(0, 100, 100), "page-down")).toBe(false)
  33. })
  34. })
  35. describe("scrollTopFromThumbPointer", () => {
  36. test("keeps downward thumb movement monotonic when content height changes", () => {
  37. const first = scrollTopFromThumbPointer({
  38. pointer: 300,
  39. viewportTop: 100,
  40. grabOffset: 12,
  41. clientHeight: 600,
  42. scrollHeight: 6_000,
  43. thumbHeight: 60,
  44. })
  45. const second = scrollTopFromThumbPointer({
  46. pointer: 320,
  47. viewportTop: 100,
  48. grabOffset: 12,
  49. clientHeight: 600,
  50. scrollHeight: 60_000,
  51. thumbHeight: 32,
  52. })
  53. expect(second).toBeGreaterThan(first)
  54. })
  55. test("clamps pointer positions to the scroll range", () => {
  56. const input = {
  57. viewportTop: 100,
  58. grabOffset: 12,
  59. clientHeight: 600,
  60. scrollHeight: 6_000,
  61. thumbHeight: 60,
  62. }
  63. expect(scrollTopFromThumbPointer({ ...input, pointer: 0 })).toBe(0)
  64. expect(scrollTopFromThumbPointer({ ...input, pointer: 1_000 })).toBe(5_400)
  65. })
  66. })