@@ -439,6 +439,130 @@ describe('CommandPalette', () => {
439439 expect ( screen . queryByRole ( 'option' , { name : 'Action 6' } ) ) . not . toBeInTheDocument ( ) ;
440440 } ) ;
441441
442+ it ( 'limits static children when limit prop is set' , async ( ) => {
443+ render (
444+ < GlobalActionsComponent >
445+ < CMDKAction display = { { label : 'Static Group' } } limit = { 2 } >
446+ < CMDKAction display = { { label : 'Item 1' } } onAction = { jest . fn ( ) } />
447+ < CMDKAction display = { { label : 'Item 2' } } onAction = { jest . fn ( ) } />
448+ < CMDKAction display = { { label : 'Item 3' } } onAction = { jest . fn ( ) } />
449+ < CMDKAction display = { { label : 'Item 4' } } onAction = { jest . fn ( ) } />
450+ </ CMDKAction >
451+ </ GlobalActionsComponent >
452+ ) ;
453+
454+ await screen . findByRole ( 'option' , { name : 'Item 1' } ) ;
455+ const actionOptions = screen
456+ . getAllByRole ( 'option' )
457+ . filter ( el => ! el . hasAttribute ( 'aria-disabled' ) ) ;
458+ expect ( actionOptions ) . toHaveLength ( 2 ) ;
459+ expect ( screen . queryByRole ( 'option' , { name : 'Item 3' } ) ) . not . toBeInTheDocument ( ) ;
460+ expect ( screen . queryByRole ( 'option' , { name : 'Item 4' } ) ) . not . toBeInTheDocument ( ) ;
461+ } ) ;
462+
463+ it ( 'does not limit static children when limit prop is not set' , async ( ) => {
464+ render (
465+ < GlobalActionsComponent >
466+ < CMDKAction display = { { label : 'Static Group' } } >
467+ < CMDKAction display = { { label : 'Item 1' } } onAction = { jest . fn ( ) } />
468+ < CMDKAction display = { { label : 'Item 2' } } onAction = { jest . fn ( ) } />
469+ < CMDKAction display = { { label : 'Item 3' } } onAction = { jest . fn ( ) } />
470+ < CMDKAction display = { { label : 'Item 4' } } onAction = { jest . fn ( ) } />
471+ < CMDKAction display = { { label : 'Item 5' } } onAction = { jest . fn ( ) } />
472+ </ CMDKAction >
473+ </ GlobalActionsComponent >
474+ ) ;
475+
476+ await screen . findByRole ( 'option' , { name : 'Item 5' } ) ;
477+ const actionOptions = screen
478+ . getAllByRole ( 'option' )
479+ . filter ( el => ! el . hasAttribute ( 'aria-disabled' ) ) ;
480+ expect ( actionOptions ) . toHaveLength ( 5 ) ;
481+ } ) ;
482+
483+ it ( 'items beyond the limit are still searchable' , async ( ) => {
484+ render (
485+ < GlobalActionsComponent >
486+ < CMDKAction display = { { label : 'Static Group' } } limit = { 2 } >
487+ < CMDKAction display = { { label : 'Alpha 1' } } onAction = { jest . fn ( ) } />
488+ < CMDKAction display = { { label : 'Alpha 2' } } onAction = { jest . fn ( ) } />
489+ < CMDKAction display = { { label : 'Beta 3' } } onAction = { jest . fn ( ) } />
490+ < CMDKAction display = { { label : 'Beta 4' } } onAction = { jest . fn ( ) } />
491+ </ CMDKAction >
492+ </ GlobalActionsComponent >
493+ ) ;
494+
495+ // Without a query, only the first 2 items should be visible
496+ await screen . findByRole ( 'option' , { name : 'Alpha 1' } ) ;
497+ expect ( screen . queryByRole ( 'option' , { name : 'Beta 3' } ) ) . not . toBeInTheDocument ( ) ;
498+
499+ // Searching for "Beta" should surface items 3 and 4 even though they are
500+ // beyond the default limit — the limit must be applied after filtering,
501+ // not before, so it never hides matching results from the user.
502+ const input = screen . getByRole ( 'textbox' , { name : 'Search commands' } ) ;
503+ await userEvent . type ( input , 'Beta' ) ;
504+
505+ expect ( await screen . findByRole ( 'option' , { name : 'Beta 3' } ) ) . toBeInTheDocument ( ) ;
506+ expect ( screen . getByRole ( 'option' , { name : 'Beta 4' } ) ) . toBeInTheDocument ( ) ;
507+ } ) ;
508+
509+ it ( 'limit is applied after search — only top matches up to the limit are shown' , async ( ) => {
510+ render (
511+ < GlobalActionsComponent >
512+ < CMDKAction display = { { label : 'Static Group' } } limit = { 2 } >
513+ < CMDKAction display = { { label : 'Item 1' } } onAction = { jest . fn ( ) } />
514+ < CMDKAction display = { { label : 'Item 2' } } onAction = { jest . fn ( ) } />
515+ < CMDKAction display = { { label : 'Item 3' } } onAction = { jest . fn ( ) } />
516+ < CMDKAction display = { { label : 'Item 4' } } onAction = { jest . fn ( ) } />
517+ </ CMDKAction >
518+ </ GlobalActionsComponent >
519+ ) ;
520+
521+ const input = await screen . findByRole ( 'textbox' , { name : 'Search commands' } ) ;
522+ await userEvent . type ( input , 'Item' ) ;
523+
524+ expect ( await screen . findByRole ( 'option' , { name : 'Item 1' } ) ) . toBeInTheDocument ( ) ;
525+ expect ( screen . getByRole ( 'option' , { name : 'Item 2' } ) ) . toBeInTheDocument ( ) ;
526+ expect ( screen . queryByRole ( 'option' , { name : 'Item 3' } ) ) . not . toBeInTheDocument ( ) ;
527+ expect ( screen . queryByRole ( 'option' , { name : 'Item 4' } ) ) . not . toBeInTheDocument ( ) ;
528+ } ) ;
529+
530+ it ( 'limit is applied after search for async resource results' , async ( ) => {
531+ const actions = makeActions ( 6 ) ;
532+
533+ render (
534+ < GlobalActionsComponent >
535+ < CMDKAction
536+ display = { { label : 'Async Group' } }
537+ limit = { 2 }
538+ resource = { ( ) => ( {
539+ queryKey : [ 'test-resource-search-limit' ] ,
540+ queryFn : async ( ) => actions ,
541+ } ) }
542+ >
543+ { data =>
544+ data . map ( action =>
545+ 'to' in action ? (
546+ < CMDKAction
547+ key = { action . display . label }
548+ display = { action . display }
549+ to = { action . to }
550+ />
551+ ) : null
552+ )
553+ }
554+ </ CMDKAction >
555+ </ GlobalActionsComponent >
556+ ) ;
557+
558+ const input = await screen . findByRole ( 'textbox' , { name : 'Search commands' } ) ;
559+ await userEvent . type ( input , 'Action' ) ;
560+
561+ expect ( await screen . findByRole ( 'option' , { name : 'Action 1' } ) ) . toBeInTheDocument ( ) ;
562+ expect ( screen . getByRole ( 'option' , { name : 'Action 2' } ) ) . toBeInTheDocument ( ) ;
563+ expect ( screen . queryByRole ( 'option' , { name : 'Action 3' } ) ) . not . toBeInTheDocument ( ) ;
564+ } ) ;
565+
442566 it ( 'respects a custom limit prop' , async ( ) => {
443567 const actions = makeActions ( 6 ) ;
444568
0 commit comments