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