@@ -693,3 +693,86 @@ describe("runProviderSetup paste", () => {
693693 expect ( values ?. apiKey ) . toBe ( key )
694694 } )
695695} )
696+
697+ describe ( "runProviderSetup pick-list height cap" , ( ) => {
698+ // Every terminal size gets a bounded frame — no chrome row overlaps
699+ // another (the header/intro/step/instruction rows used to compress into
700+ // each other when the flex column ran out of room), and the picker never
701+ // paints past the terminal's own row count.
702+ for ( const height of [ 24 , 16 , 12 , 8 , 6 ] ) {
703+ test ( `stays within a ${ height } -row terminal with no overlapping chrome` , async ( ) => {
704+ const harness = await createHarness ( { width : 80 , height } )
705+ runProviderSetup ( {
706+ onSubmit : async ( ) => { } ,
707+ showTelemetryNotice : false ,
708+ createRenderer : async ( ) => harness . renderer ,
709+ } )
710+ await harness . renderOnce ( )
711+ await harness . renderOnce ( )
712+ const lines = harness . captureCharFrame ( ) . split ( "\n" )
713+ expect ( lines . length ) . toBeLessThanOrEqual ( height + 1 )
714+ // The garbled-overlap bug glued the step line and the intro line
715+ // together on one row; each survives as its own line, or is clipped
716+ // entirely, but never merges into the other.
717+ const stepLine = lines . find ( ( l ) => l . includes ( "step 1 of 3" ) )
718+ if ( stepLine !== undefined ) {
719+ expect ( stepLine ) . not . toContain ( "connect an inference provider" )
720+ }
721+ } )
722+ }
723+
724+ test ( "keyboard navigation scrolls a long provider list and keeps the active row visible" , async ( ) => {
725+ const harness = await createHarness ( { width : 80 , height : 16 } )
726+ runProviderSetup ( {
727+ onSubmit : async ( ) => { } ,
728+ showTelemetryNotice : false ,
729+ createRenderer : async ( ) => harness . renderer ,
730+ } )
731+ await harness . renderOnce ( )
732+ await harness . renderOnce ( )
733+ const ids = providerChoiceRows ( providerChoices ( ) ) . map ( ( r ) => r . id )
734+ for ( let i = 0 ; i < ids . length - 1 ; i ++ ) harness . pressKey ( "ARROW_DOWN" )
735+ await harness . renderOnce ( )
736+ const frame = harness . captureCharFrame ( )
737+ const last = providerChoiceRows ( providerChoices ( ) ) . at ( - 1 )
738+ expect ( last ) . toBeDefined ( )
739+ expect ( frame ) . toContain ( last ! . label . slice ( 0 , 20 ) )
740+ } )
741+
742+ // statusLine and guidance are both blank on the first screen these tests
743+ // exercised — the garbling only showed up once a failed connection test
744+ // populates both of them at once, so walk the flow there instead of
745+ // stopping at the provider pick-list.
746+ test ( "a failed connection test at a short terminal shows status and guidance on their own lines" , async ( ) => {
747+ const harness = await createHarness ( { width : 80 , height : 16 } )
748+ runProviderSetup ( {
749+ onSubmit : async ( _values , _setPhase , opts ) => {
750+ if ( ! opts . skipValidation ) throw new Error ( "connection refused" )
751+ } ,
752+ showTelemetryNotice : false ,
753+ createRenderer : async ( ) => harness . renderer ,
754+ } )
755+ await harness . renderOnce ( )
756+ await harness . renderOnce ( )
757+ await pickRow ( harness , PROVIDER_IDS , "openai" )
758+ type ( harness , "sk-key" )
759+ harness . pressKey ( "Enter" )
760+ await harness . renderOnce ( )
761+ harness . pressKey ( "Enter" )
762+ await harness . renderOnce ( )
763+ await new Promise ( ( r ) => setTimeout ( r , 0 ) )
764+ await harness . renderOnce ( )
765+
766+ const lines = harness . captureCharFrame ( ) . split ( "\n" )
767+ expect ( lines . length ) . toBeLessThanOrEqual ( 17 )
768+ const statusRow = lines . find ( ( l ) => l . includes ( "connection refused" ) )
769+ const guidanceRow = lines . find ( ( l ) => l . includes ( "esc to re-enter" ) )
770+ expect ( statusRow ) . toBeDefined ( )
771+ expect ( guidanceRow ) . toBeDefined ( )
772+ // The garbling bug glued these two rows together; each must survive as
773+ // its own line, never merged into the other.
774+ expect ( statusRow ) . not . toBe ( guidanceRow )
775+ expect ( statusRow ) . not . toContain ( "esc to re-enter" )
776+ expect ( guidanceRow ) . not . toContain ( "connection refused" )
777+ } )
778+ } )
0 commit comments