delayed-presence.test.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { expect, jest, test } from "bun:test"
  2. import { createRoot, createSignal } from "solid-js"
  3. import { createDelayedPresence } from "../../src/util/delayed-presence"
  4. test("shows only after the same value remains present for the delay", async () => {
  5. jest.useFakeTimers()
  6. const scope = createRoot((dispose) => {
  7. const [value, setValue] = createSignal<string>()
  8. return { dispose, setValue, visible: createDelayedPresence(value, 1_000) }
  9. })
  10. try {
  11. scope.setValue("first")
  12. await Promise.resolve()
  13. jest.advanceTimersByTime(500)
  14. expect(scope.visible()).toBe(false)
  15. scope.setValue("second")
  16. await Promise.resolve()
  17. jest.advanceTimersByTime(999)
  18. expect(scope.visible()).toBe(false)
  19. jest.advanceTimersByTime(1)
  20. expect(scope.visible()).toBe(true)
  21. } finally {
  22. scope.dispose()
  23. jest.useRealTimers()
  24. }
  25. })
  26. test("cancels the delay when the value disappears or the owner is disposed", async () => {
  27. jest.useFakeTimers()
  28. const scope = createRoot((dispose) => {
  29. const [value, setValue] = createSignal<string>()
  30. return { dispose, setValue, visible: createDelayedPresence(value, 1_000) }
  31. })
  32. try {
  33. scope.setValue("running")
  34. await Promise.resolve()
  35. jest.advanceTimersByTime(500)
  36. scope.setValue(undefined)
  37. await Promise.resolve()
  38. jest.advanceTimersByTime(1_000)
  39. expect(scope.visible()).toBe(false)
  40. scope.setValue("running")
  41. await Promise.resolve()
  42. scope.dispose()
  43. jest.advanceTimersByTime(1_000)
  44. expect(scope.visible()).toBe(false)
  45. } finally {
  46. scope.dispose()
  47. jest.useRealTimers()
  48. }
  49. })
  50. test("uses the remaining delay for the current value", async () => {
  51. jest.useFakeTimers()
  52. const scope = createRoot((dispose) => {
  53. const [value, setValue] = createSignal<{ age: number }>()
  54. return {
  55. dispose,
  56. setValue,
  57. visible: createDelayedPresence(value, (current) => Math.max(0, 1_000 - current.age)),
  58. }
  59. })
  60. try {
  61. scope.setValue({ age: 400 })
  62. await Promise.resolve()
  63. jest.advanceTimersByTime(599)
  64. expect(scope.visible()).toBe(false)
  65. jest.advanceTimersByTime(1)
  66. expect(scope.visible()).toBe(true)
  67. scope.setValue({ age: 1_000 })
  68. await Promise.resolve()
  69. expect(scope.visible()).toBe(true)
  70. } finally {
  71. scope.dispose()
  72. jest.useRealTimers()
  73. }
  74. })
  75. test("does not restart the delay for an equivalent value", async () => {
  76. jest.useFakeTimers()
  77. const scope = createRoot((dispose) => {
  78. const [value, setValue] = createSignal<{ id: string }>()
  79. return {
  80. dispose,
  81. setValue,
  82. visible: createDelayedPresence(value, 1_000, (previous, next) => previous.id === next.id),
  83. }
  84. })
  85. try {
  86. scope.setValue({ id: "first" })
  87. await Promise.resolve()
  88. jest.advanceTimersByTime(500)
  89. scope.setValue({ id: "first" })
  90. await Promise.resolve()
  91. jest.advanceTimersByTime(499)
  92. expect(scope.visible()).toBe(false)
  93. jest.advanceTimersByTime(1)
  94. expect(scope.visible()).toBe(true)
  95. scope.setValue({ id: "second" })
  96. await Promise.resolve()
  97. expect(scope.visible()).toBe(false)
  98. } finally {
  99. scope.dispose()
  100. jest.useRealTimers()
  101. }
  102. })