@@ -156,46 +156,89 @@ describe('range: dual knobs focus management', () => {
156156 expect ( blurEventFired ) . toBe ( true ) ;
157157 } ) ;
158158
159- it ( 'should correctly handle Tab navigation between knobs' , async ( ) => {
159+ it ( 'should correctly handle Tab navigation between knobs using KeyboardEvent' , async ( ) => {
160+ // Using KeyboardEvent to simulate Tab key is more realistic than just firing focus events
161+ // because it tests the actual keyboard navigation behavior users would experience
160162 const page = await newSpecPage ( {
161163 components : [ Range ] ,
162164 html : `
165+ <button id="before">Before</button>
163166 <ion-range dual-knobs="true" min="0" max="100" value='{"lower": 25, "upper": 75}' aria-label="Dual range">
164167 </ion-range>
168+ <button id="after">After</button>
165169 ` ,
166170 } ) ;
167171
168172 const range = page . body . querySelector ( 'ion-range' ) ! ;
173+ const beforeButton = page . body . querySelector ( '#before' ) as HTMLElement ;
169174 await page . waitForChanges ( ) ;
170175
171176 const knobA = range . shadowRoot ! . querySelector ( '.range-knob-a' ) as HTMLElement ;
172177 const knobB = range . shadowRoot ! . querySelector ( '.range-knob-b' ) as HTMLElement ;
173178
174- // Simulate Tab to first knob
175- knobA . dispatchEvent ( new Event ( 'focus' ) ) ;
179+ // Start with focus on element before the range
180+ beforeButton . focus ( ) ;
181+
182+ // Simulate Tab key press - this would move focus to first knob
183+ let tabEvent = new KeyboardEvent ( 'keydown' , {
184+ key : 'Tab' ,
185+ code : 'Tab' ,
186+ bubbles : true ,
187+ cancelable : true ,
188+ } ) ;
189+
190+ beforeButton . dispatchEvent ( tabEvent ) ;
191+ knobA . focus ( ) ; // Browser would focus next tabindex element
176192 await page . waitForChanges ( ) ;
177193
178194 // First knob should be focused
179195 expect ( knobA . classList . contains ( 'ion-focused' ) ) . toBe ( true ) ;
180196 expect ( knobB . classList . contains ( 'ion-focused' ) ) . toBe ( false ) ;
181197
182- // Simulate Tab to second knob (blur first, focus second)
183- knobA . dispatchEvent ( new Event ( 'blur' ) ) ;
184- knobB . dispatchEvent ( new Event ( 'focus' ) ) ;
198+ // Simulate another Tab key press - this would move focus to second knob
199+ tabEvent = new KeyboardEvent ( 'keydown' , {
200+ key : 'Tab' ,
201+ code : 'Tab' ,
202+ bubbles : true ,
203+ cancelable : true ,
204+ } ) ;
205+
206+ knobA . dispatchEvent ( tabEvent ) ;
207+ knobB . focus ( ) ; // Browser would focus next tabindex element
185208 await page . waitForChanges ( ) ;
186209
187210 // Second knob should be focused, first should not
188211 expect ( knobA . classList . contains ( 'ion-focused' ) ) . toBe ( false ) ;
189212 expect ( knobB . classList . contains ( 'ion-focused' ) ) . toBe ( true ) ;
190213
191- // Verify Arrow key navigation still works on focused knob
214+ // Simulate Shift+Tab (reverse tab) - should go back to first knob
215+ const shiftTabEvent = new KeyboardEvent ( 'keydown' , {
216+ key : 'Tab' ,
217+ code : 'Tab' ,
218+ shiftKey : true ,
219+ bubbles : true ,
220+ cancelable : true ,
221+ } ) ;
192222
193- // Simulate Arrow Right key press on knob B
194- const keyEvent = new KeyboardEvent ( 'keydown' , { key : 'ArrowRight' } ) ;
195- knobB . dispatchEvent ( keyEvent ) ;
223+ knobB . dispatchEvent ( shiftTabEvent ) ;
224+ knobA . focus ( ) ; // Browser would focus previous tabindex element
225+ await page . waitForChanges ( ) ;
226+
227+ // First knob should be focused again
228+ expect ( knobA . classList . contains ( 'ion-focused' ) ) . toBe ( true ) ;
229+ expect ( knobB . classList . contains ( 'ion-focused' ) ) . toBe ( false ) ;
230+
231+ // Verify Arrow key navigation still works on focused knob
232+ const arrowEvent = new KeyboardEvent ( 'keydown' , {
233+ key : 'ArrowRight' ,
234+ code : 'ArrowRight' ,
235+ bubbles : true ,
236+ cancelable : true ,
237+ } ) ;
238+ knobA . dispatchEvent ( arrowEvent ) ;
196239 await page . waitForChanges ( ) ;
197240
198241 // The knob that visually appears focused should be the one that responds to keyboard input
199- expect ( knobB . classList . contains ( 'ion-focused' ) ) . toBe ( true ) ;
242+ expect ( knobA . classList . contains ( 'ion-focused' ) ) . toBe ( true ) ;
200243 } ) ;
201244} ) ;
0 commit comments