navigation.test.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { beforeEach, describe, expect, it, vi } from 'vitest'
  2. import { createNavigationHandler } from './navigation'
  3. describe('createNavigationHandler', () => {
  4. let mockRouter: any
  5. let mockWindowOpen: any
  6. beforeEach(() => {
  7. vi.clearAllMocks()
  8. // Mock router with push method
  9. mockRouter = {
  10. push: vi.fn(),
  11. }
  12. // Mock window.open
  13. mockWindowOpen = vi.fn()
  14. global.window.open = mockWindowOpen
  15. })
  16. describe('keyboard navigation', () => {
  17. it('should call router.push when Enter key is pressed without modifiers', () => {
  18. const handler = createNavigationHandler('/test-url', mockRouter)
  19. const event = {
  20. key: 'Enter',
  21. metaKey: false,
  22. ctrlKey: false,
  23. preventDefault: vi.fn(),
  24. } as unknown as React.KeyboardEvent
  25. handler(event)
  26. expect(event.preventDefault).toHaveBeenCalled()
  27. expect(mockRouter.push).toHaveBeenCalledWith('/test-url')
  28. expect(mockWindowOpen).not.toHaveBeenCalled()
  29. })
  30. it('should call router.push when Space key is pressed without modifiers', () => {
  31. const handler = createNavigationHandler('/test-url', mockRouter)
  32. const event = {
  33. key: ' ',
  34. metaKey: false,
  35. ctrlKey: false,
  36. preventDefault: vi.fn(),
  37. } as unknown as React.KeyboardEvent
  38. handler(event)
  39. expect(event.preventDefault).toHaveBeenCalled()
  40. expect(mockRouter.push).toHaveBeenCalledWith('/test-url')
  41. expect(mockWindowOpen).not.toHaveBeenCalled()
  42. })
  43. it('should open new tab when Enter key is pressed with metaKey', () => {
  44. const handler = createNavigationHandler('/test-url', mockRouter)
  45. const event = {
  46. key: 'Enter',
  47. metaKey: true,
  48. ctrlKey: false,
  49. preventDefault: vi.fn(),
  50. } as unknown as React.KeyboardEvent
  51. handler(event)
  52. expect(event.preventDefault).toHaveBeenCalled()
  53. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  54. expect(mockRouter.push).not.toHaveBeenCalled()
  55. })
  56. it('should open new tab when Enter key is pressed with ctrlKey', () => {
  57. const handler = createNavigationHandler('/test-url', mockRouter)
  58. const event = {
  59. key: 'Enter',
  60. metaKey: false,
  61. ctrlKey: true,
  62. preventDefault: vi.fn(),
  63. } as unknown as React.KeyboardEvent
  64. handler(event)
  65. expect(event.preventDefault).toHaveBeenCalled()
  66. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  67. expect(mockRouter.push).not.toHaveBeenCalled()
  68. })
  69. it('should open new tab when Space key is pressed with metaKey', () => {
  70. const handler = createNavigationHandler('/test-url', mockRouter)
  71. const event = {
  72. key: ' ',
  73. metaKey: true,
  74. ctrlKey: false,
  75. preventDefault: vi.fn(),
  76. } as unknown as React.KeyboardEvent
  77. handler(event)
  78. expect(event.preventDefault).toHaveBeenCalled()
  79. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  80. expect(mockRouter.push).not.toHaveBeenCalled()
  81. })
  82. it('should do nothing when other keys are pressed', () => {
  83. const handler = createNavigationHandler('/test-url', mockRouter)
  84. const event = {
  85. key: 'a',
  86. metaKey: false,
  87. ctrlKey: false,
  88. preventDefault: vi.fn(),
  89. } as unknown as React.KeyboardEvent
  90. handler(event)
  91. expect(event.preventDefault).not.toHaveBeenCalled()
  92. expect(mockRouter.push).not.toHaveBeenCalled()
  93. expect(mockWindowOpen).not.toHaveBeenCalled()
  94. })
  95. })
  96. describe('mouse navigation', () => {
  97. it('should call router.push on regular left click', () => {
  98. const handler = createNavigationHandler('/test-url', mockRouter)
  99. const event = {
  100. button: 0,
  101. metaKey: false,
  102. ctrlKey: false,
  103. preventDefault: vi.fn(),
  104. } as unknown as React.MouseEvent
  105. handler(event)
  106. expect(mockRouter.push).toHaveBeenCalledWith('/test-url')
  107. expect(mockWindowOpen).not.toHaveBeenCalled()
  108. })
  109. it('should open new tab on middle mouse button click', () => {
  110. const handler = createNavigationHandler('/test-url', mockRouter)
  111. const event = {
  112. button: 1, // Middle button
  113. metaKey: false,
  114. ctrlKey: false,
  115. preventDefault: vi.fn(),
  116. } as unknown as React.MouseEvent
  117. handler(event)
  118. expect(event.preventDefault).toHaveBeenCalled()
  119. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  120. expect(mockRouter.push).not.toHaveBeenCalled()
  121. })
  122. it('should open new tab on Cmd + left click', () => {
  123. const handler = createNavigationHandler('/test-url', mockRouter)
  124. const event = {
  125. button: 0,
  126. metaKey: true,
  127. ctrlKey: false,
  128. preventDefault: vi.fn(),
  129. } as unknown as React.MouseEvent
  130. handler(event)
  131. expect(event.preventDefault).toHaveBeenCalled()
  132. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  133. expect(mockRouter.push).not.toHaveBeenCalled()
  134. })
  135. it('should open new tab on Ctrl + left click', () => {
  136. const handler = createNavigationHandler('/test-url', mockRouter)
  137. const event = {
  138. button: 0,
  139. metaKey: false,
  140. ctrlKey: true,
  141. preventDefault: vi.fn(),
  142. } as unknown as React.MouseEvent
  143. handler(event)
  144. expect(event.preventDefault).toHaveBeenCalled()
  145. expect(mockWindowOpen).toHaveBeenCalledWith('/test-url', '_blank')
  146. expect(mockRouter.push).not.toHaveBeenCalled()
  147. })
  148. it('should handle right click without navigation', () => {
  149. const handler = createNavigationHandler('/test-url', mockRouter)
  150. const event = {
  151. button: 2, // Right button
  152. metaKey: false,
  153. ctrlKey: false,
  154. preventDefault: vi.fn(),
  155. } as unknown as React.MouseEvent
  156. handler(event)
  157. // Right click should trigger router.push (falls through to default case)
  158. expect(mockRouter.push).toHaveBeenCalledWith('/test-url')
  159. })
  160. })
  161. describe('URL handling', () => {
  162. it('should handle URLs with BASE_PATH correctly', () => {
  163. const handler = createNavigationHandler('/project/123/settings', mockRouter)
  164. const event = {
  165. button: 1, // Middle button to open in new tab
  166. metaKey: false,
  167. ctrlKey: false,
  168. preventDefault: vi.fn(),
  169. } as unknown as React.MouseEvent
  170. handler(event)
  171. // Should prepend BASE_PATH when opening new tab
  172. expect(mockWindowOpen).toHaveBeenCalledWith('/project/123/settings', '_blank')
  173. })
  174. it('should pass URL directly to router.push without BASE_PATH', () => {
  175. const handler = createNavigationHandler('/project/123/settings', mockRouter)
  176. const event = {
  177. button: 0,
  178. metaKey: false,
  179. ctrlKey: false,
  180. preventDefault: vi.fn(),
  181. } as unknown as React.MouseEvent
  182. handler(event)
  183. // router.push should receive URL without BASE_PATH
  184. expect(mockRouter.push).toHaveBeenCalledWith('/project/123/settings')
  185. })
  186. })
  187. })