@@ -9,7 +9,7 @@ const BASIC_OPTIONS = [
99 { id : 'foo' , text : 'Foo Option' } ,
1010 { id : 'bar' , text : 'Bar Option' } ,
1111 { id : 'baz' , text : 'Baz Option' } ,
12- { id : 'boop ' , text : 'Boop Option' } ,
12+ { id : 'buzz ' , text : 'Buzz Option' } ,
1313] ;
1414
1515describe ( 'IA Combo Box' , ( ) => {
@@ -112,12 +112,12 @@ describe('IA Combo Box', () => {
112112 > </ ia-combo-box >
113113 ` ) ;
114114
115- const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
115+ const textInput = el . shadowRoot ?. querySelector (
116+ '#text-input' ,
117+ ) as HTMLInputElement ;
116118 expect ( textInput ) . to . exist ;
117119 expect ( textInput . readOnly ) . to . be . true ;
118120 } ) ;
119-
120- // TODO ...
121121 } ) ;
122122
123123 describe ( 'List behavior' , ( ) => {
@@ -134,12 +134,12 @@ describe('IA Combo Box', () => {
134134 < ia-combo-box behavior ="list " .options =${ BASIC_OPTIONS } > </ ia-combo-box >
135135 ` ) ;
136136
137- const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
137+ const textInput = el . shadowRoot ?. querySelector (
138+ '#text-input' ,
139+ ) as HTMLInputElement ;
138140 expect ( textInput ) . to . exist ;
139141 expect ( textInput . readOnly ) . to . be . false ;
140142 } ) ;
141-
142- // TODO ...
143143 } ) ;
144144
145145 describe ( 'Freeform behavior' , ( ) => {
@@ -151,12 +151,12 @@ describe('IA Combo Box', () => {
151151 > </ ia-combo-box >
152152 ` ) ;
153153
154- const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
154+ const textInput = el . shadowRoot ?. querySelector (
155+ '#text-input' ,
156+ ) as HTMLInputElement ;
155157 expect ( textInput ) . to . exist ;
156158 expect ( textInput . readOnly ) . to . be . false ;
157159 } ) ;
158-
159- // TODO ...
160160 } ) ;
161161
162162 describe ( 'Filtering presets' , ( ) => {
@@ -165,7 +165,89 @@ describe('IA Combo Box', () => {
165165 expect ( el . filter ) . to . equal ( 'substring' ) ;
166166 } ) ;
167167
168- // TODO ...
168+ test ( '"all" filtering preset turns off filtering entirely' , async ( ) => {
169+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } filter ="all"> </ ia-combo-box > ` ) ;
170+
171+ const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
172+ expect ( textInput ) . to . exist ;
173+
174+ textInput . value = 'b' ;
175+ textInput . dispatchEvent ( new InputEvent ( 'input' ) ) ;
176+ await el . updateComplete ;
177+
178+ // Options were not filtered
179+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
180+ expect ( allOptionElmts ?. length ) . to . equal ( 4 ) ;
181+ } ) ;
182+
183+ test ( '"prefix" filtering preset works correctly' , async ( ) => {
184+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } filter ="prefix"> </ ia-combo-box > ` ) ;
185+
186+ const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
187+ expect ( textInput ) . to . exist ;
188+
189+ textInput . value = 'b' ;
190+ textInput . dispatchEvent ( new InputEvent ( 'input' ) ) ;
191+ await el . updateComplete ;
192+
193+ // Filtered options are 'Bar', 'Baz', and 'Buzz'
194+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
195+ expect ( allOptionElmts ?. length ) . to . equal ( 3 ) ;
196+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Bar' ) ;
197+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
198+ expect ( allOptionElmts ?. [ 2 ] . textContent . trim ( ) ) . to . equal ( 'Buzz' ) ;
199+ } ) ;
200+
201+ test ( '"suffix" filtering preset works correctly' , async ( ) => {
202+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } filter ="suffix"> </ ia-combo-box > ` ) ;
203+
204+ const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
205+ expect ( textInput ) . to . exist ;
206+
207+ textInput . value = 'b' ;
208+ textInput . dispatchEvent ( new InputEvent ( 'input' ) ) ;
209+ await el . updateComplete ;
210+
211+ // Filtered options are 'Baz' and 'Buzz'
212+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
213+ expect ( allOptionElmts ?. length ) . to . equal ( 2 ) ;
214+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
215+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Buzz' ) ;
216+ } ) ;
217+
218+ test ( '"substring" filtering preset works correctly' , async ( ) => {
219+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } filter ="substring"> </ ia-combo-box > ` ) ;
220+
221+ const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
222+ expect ( textInput ) . to . exist ;
223+
224+ textInput . value = 'a' ;
225+ textInput . dispatchEvent ( new InputEvent ( 'input' ) ) ;
226+ await el . updateComplete ;
227+
228+ // Filtered options are 'Bar' and 'Baz'
229+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
230+ expect ( allOptionElmts ?. length ) . to . equal ( 2 ) ;
231+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Bar' ) ;
232+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
233+ } ) ;
234+
235+ test ( '"subsequence" filtering preset works correctly' , async ( ) => {
236+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } filter ="subsequence"> </ ia-combo-box > ` ) ;
237+
238+ const textInput = el . shadowRoot ?. querySelector ( '#text-input' ) as HTMLInputElement ;
239+ expect ( textInput ) . to . exist ;
240+
241+ textInput . value = 'bz' ;
242+ textInput . dispatchEvent ( new InputEvent ( 'input' ) ) ;
243+ await el . updateComplete ;
244+
245+ // Filtered options are 'Baz' and 'Buzz'
246+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
247+ expect ( allOptionElmts ?. length ) . to . equal ( 2 ) ;
248+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
249+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Buzz' ) ;
250+ } ) ;
169251 } ) ;
170252
171253 describe ( 'Sorting behavior' , ( ) => {
@@ -174,11 +256,31 @@ describe('IA Combo Box', () => {
174256 expect ( el . sort ) . to . be . false ;
175257 } ) ;
176258
177- // TODO ...
259+ test ( 'shows options in provided order when sort=false' , async ( ) => {
260+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } open > </ ia-combo-box > ` ) ;
261+
262+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
263+ expect ( allOptionElmts ?. length ) . to . equal ( 4 ) ;
264+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Foo' ) ;
265+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Bar' ) ;
266+ expect ( allOptionElmts ?. [ 2 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
267+ expect ( allOptionElmts ?. [ 3 ] . textContent . trim ( ) ) . to . equal ( 'Buzz' ) ;
268+ } ) ;
269+
270+ test ( 'shows options in lexicographic order when sort=true' , async ( ) => {
271+ const el = await fixture < IAComboBox > ( html `< ia-combo-box .options =${ BASIC_OPTIONS } sort open > </ ia-combo-box > ` ) ;
272+
273+ const allOptionElmts = el . shadowRoot ?. querySelectorAll ( '.option' ) ;
274+ expect ( allOptionElmts ?. length ) . to . equal ( 4 ) ;
275+ expect ( allOptionElmts ?. [ 0 ] . textContent . trim ( ) ) . to . equal ( 'Bar' ) ;
276+ expect ( allOptionElmts ?. [ 1 ] . textContent . trim ( ) ) . to . equal ( 'Baz' ) ;
277+ expect ( allOptionElmts ?. [ 2 ] . textContent . trim ( ) ) . to . equal ( 'Buzz' ) ;
278+ expect ( allOptionElmts ?. [ 3 ] . textContent . trim ( ) ) . to . equal ( 'Foo' ) ;
279+ } ) ;
178280 } ) ;
179281
180- describe ( 'Keyboard navigation' , ( ) => {
181- test ( 'Enter key opens options list' , async ( ) => {
282+ describe ( 'Common keyboard navigation' , ( ) => {
283+ test ( 'Enter key opens options list w/o highlight ' , async ( ) => {
182284 const el = await fixture < IAComboBox > ( html `
183285 < ia-combo-box .options =${ BASIC_OPTIONS } > </ ia-combo-box >
184286 ` ) ;
@@ -190,13 +292,74 @@ describe('IA Combo Box', () => {
190292
191293 textInput . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Enter' } ) ) ;
192294 await el . updateComplete ;
295+ expect ( el . open ) . to . be . true ;
193296
297+ // No option highlighted
298+ expect ( el . shadowRoot ?. querySelector ( '.highlight' ) ) . not . to . exist ;
299+ } ) ;
300+
301+ test ( 'Alt + Down key combo opens options list w/o highlight' , async ( ) => {
302+ const el = await fixture < IAComboBox > ( html `
303+ < ia-combo-box .options =${ BASIC_OPTIONS } > </ ia-combo-box >
304+ ` ) ;
305+
306+ const textInput = el . shadowRoot ?. querySelector (
307+ '#text-input' ,
308+ ) as HTMLInputElement ;
309+ expect ( textInput ) . to . exist ;
310+
311+ textInput . dispatchEvent (
312+ new KeyboardEvent ( 'keydown' , { key : 'ArrowDown' , altKey : true } ) ,
313+ ) ;
314+ await el . updateComplete ;
194315 expect ( el . open ) . to . be . true ;
195316
196317 // No option highlighted
197318 expect ( el . shadowRoot ?. querySelector ( '.highlight' ) ) . not . to . exist ;
198319 } ) ;
199320
321+ test ( 'Down arrow opens options list and highlights first option' , async ( ) => {
322+ const el = await fixture < IAComboBox > ( html `
323+ < ia-combo-box .options =${ BASIC_OPTIONS } > </ ia-combo-box >
324+ ` ) ;
325+
326+ const textInput = el . shadowRoot ?. querySelector (
327+ '#text-input' ,
328+ ) as HTMLInputElement ;
329+ expect ( textInput ) . to . exist ;
330+
331+ textInput . dispatchEvent (
332+ new KeyboardEvent ( 'keydown' , { key : 'ArrowDown' } ) ,
333+ ) ;
334+ await el . updateComplete ;
335+ expect ( el . open ) . to . be . true ;
336+
337+ // Only the first option is highlighted
338+ const firstOption = el . shadowRoot ?. querySelector ( '.option' ) ;
339+ expect ( firstOption ?. classList . contains ( 'highlight' ) ) . to . be . true ;
340+ expect ( el . shadowRoot ?. querySelectorAll ( '.highlight' ) . length ) . to . equal ( 1 ) ;
341+ } ) ;
342+
343+ test ( 'Up arrow opens options list and highlights last option' , async ( ) => {
344+ const el = await fixture < IAComboBox > ( html `
345+ < ia-combo-box .options =${ BASIC_OPTIONS } > </ ia-combo-box >
346+ ` ) ;
347+
348+ const textInput = el . shadowRoot ?. querySelector (
349+ '#text-input' ,
350+ ) as HTMLInputElement ;
351+ expect ( textInput ) . to . exist ;
352+
353+ textInput . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'ArrowUp' } ) ) ;
354+ await el . updateComplete ;
355+ expect ( el . open ) . to . be . true ;
356+
357+ // Only the last option is highlighted
358+ const lastOption = el . shadowRoot ?. querySelector ( '.option:last-of-type' ) ;
359+ expect ( lastOption ?. classList . contains ( 'highlight' ) ) . to . be . true ;
360+ expect ( el . shadowRoot ?. querySelectorAll ( '.highlight' ) . length ) . to . equal ( 1 ) ;
361+ } ) ;
362+
200363 test ( 'Escape key closes options list' , async ( ) => {
201364 const el = await fixture < IAComboBox > ( html `
202365 < ia-combo-box .options =${ BASIC_OPTIONS } open > </ ia-combo-box >
@@ -209,10 +372,24 @@ describe('IA Combo Box', () => {
209372
210373 textInput . dispatchEvent ( new KeyboardEvent ( 'keydown' , { key : 'Escape' } ) ) ;
211374 await el . updateComplete ;
212-
213375 expect ( el . open ) . to . be . false ;
214376 } ) ;
215377
216- // TODO ...
378+ test ( 'Alt + Up key combo closes options list' , async ( ) => {
379+ const el = await fixture < IAComboBox > ( html `
380+ < ia-combo-box .options =${ BASIC_OPTIONS } open > </ ia-combo-box >
381+ ` ) ;
382+
383+ const textInput = el . shadowRoot ?. querySelector (
384+ '#text-input' ,
385+ ) as HTMLInputElement ;
386+ expect ( textInput ) . to . exist ;
387+
388+ textInput . dispatchEvent (
389+ new KeyboardEvent ( 'keydown' , { key : 'ArrowUp' , altKey : true } ) ,
390+ ) ;
391+ await el . updateComplete ;
392+ expect ( el . open ) . to . be . false ;
393+ } ) ;
217394 } ) ;
218395} ) ;
0 commit comments