useLongPress.test.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * Tests for the useLongPress hook.
  3. */
  4. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
  5. import { renderHook, act } from '@testing-library/react';
  6. import { useLongPress } from '../../hooks/useLongPress';
  7. describe('useLongPress', () => {
  8. beforeEach(() => {
  9. vi.useFakeTimers();
  10. });
  11. afterEach(() => {
  12. vi.useRealTimers();
  13. });
  14. it('calls onLongPress after delay', () => {
  15. const onLongPress = vi.fn();
  16. const onClick = vi.fn();
  17. const { result } = renderHook(() =>
  18. useLongPress({ onLongPress, onClick, delay: 500 })
  19. );
  20. // Simulate mouse down
  21. act(() => {
  22. result.current.onMouseDown({} as React.MouseEvent);
  23. });
  24. // Fast forward past the delay
  25. act(() => {
  26. vi.advanceTimersByTime(600);
  27. });
  28. // Should trigger long press
  29. expect(onLongPress).toHaveBeenCalled();
  30. expect(onClick).not.toHaveBeenCalled();
  31. });
  32. it('calls onClick for short press', () => {
  33. const onLongPress = vi.fn();
  34. const onClick = vi.fn();
  35. const { result } = renderHook(() =>
  36. useLongPress({ onLongPress, onClick, delay: 500 })
  37. );
  38. // Simulate mouse down
  39. act(() => {
  40. result.current.onMouseDown({} as React.MouseEvent);
  41. });
  42. // Release before delay
  43. act(() => {
  44. vi.advanceTimersByTime(200);
  45. result.current.onMouseUp({} as React.MouseEvent);
  46. });
  47. // Should trigger click, not long press
  48. expect(onClick).toHaveBeenCalled();
  49. expect(onLongPress).not.toHaveBeenCalled();
  50. });
  51. it('cancels on mouse leave', () => {
  52. const onLongPress = vi.fn();
  53. const onClick = vi.fn();
  54. const { result } = renderHook(() =>
  55. useLongPress({ onLongPress, onClick, delay: 500 })
  56. );
  57. // Simulate mouse down
  58. act(() => {
  59. result.current.onMouseDown({} as React.MouseEvent);
  60. });
  61. // Mouse leaves before delay
  62. act(() => {
  63. vi.advanceTimersByTime(200);
  64. result.current.onMouseLeave({} as React.MouseEvent);
  65. });
  66. // Continue past delay
  67. act(() => {
  68. vi.advanceTimersByTime(400);
  69. });
  70. // Neither should be called
  71. expect(onLongPress).not.toHaveBeenCalled();
  72. expect(onClick).not.toHaveBeenCalled();
  73. });
  74. it('uses default delay of 500ms', () => {
  75. const onLongPress = vi.fn();
  76. const { result } = renderHook(() =>
  77. useLongPress({ onLongPress })
  78. );
  79. // Simulate mouse down
  80. act(() => {
  81. result.current.onMouseDown({} as React.MouseEvent);
  82. });
  83. // Just before default delay
  84. act(() => {
  85. vi.advanceTimersByTime(450);
  86. });
  87. expect(onLongPress).not.toHaveBeenCalled();
  88. // After default delay
  89. act(() => {
  90. vi.advanceTimersByTime(100);
  91. });
  92. expect(onLongPress).toHaveBeenCalled();
  93. });
  94. it('handles touch events', () => {
  95. const onLongPress = vi.fn();
  96. const { result } = renderHook(() =>
  97. useLongPress({ onLongPress, delay: 500 })
  98. );
  99. // Simulate touch start
  100. act(() => {
  101. result.current.onTouchStart({} as React.TouchEvent);
  102. });
  103. // Fast forward past the delay
  104. act(() => {
  105. vi.advanceTimersByTime(600);
  106. });
  107. expect(onLongPress).toHaveBeenCalled();
  108. });
  109. it('cancels on touch end', () => {
  110. const onLongPress = vi.fn();
  111. const onClick = vi.fn();
  112. const { result } = renderHook(() =>
  113. useLongPress({ onLongPress, onClick, delay: 500 })
  114. );
  115. // Simulate touch start
  116. act(() => {
  117. result.current.onTouchStart({} as React.TouchEvent);
  118. });
  119. // End touch before delay
  120. act(() => {
  121. vi.advanceTimersByTime(200);
  122. result.current.onTouchEnd({} as React.TouchEvent);
  123. });
  124. expect(onClick).toHaveBeenCalled();
  125. expect(onLongPress).not.toHaveBeenCalled();
  126. });
  127. });