11import { beforeEach , describe , expect , it , vi } from 'vitest'
22import { cleanup , fireEvent , render , screen , waitFor , within } from '@testing-library/react'
3+ import { readFileSync } from 'node:fs'
34import Sidebar from './Sidebar'
45import { useChatStore } from '@/stores/useChatStore'
56import { useGatewayStore } from '@/stores/useGatewayStore'
@@ -8,6 +9,7 @@ import { useUIStore } from '@/stores/useUIStore'
89import { useWorkspaceStore } from '@/stores/useWorkspaceStore'
910
1011let mockGatewayAPI : any = null
12+ const appCss = readFileSync ( 'src/index.css' , 'utf-8' )
1113
1214vi . mock ( '@/context/RuntimeProvider' , ( ) => ( {
1315 useGatewayAPI : ( ) => mockGatewayAPI ,
@@ -199,6 +201,48 @@ describe('Sidebar ProviderModal', () => {
199201 expect ( screen . getByText ( 'switch failed' ) ) . toBeInTheDocument ( )
200202 } )
201203
204+ it ( 'keeps provider models in a single scrollable row when there are many models' , async ( ) => {
205+ mockGatewayAPI . listProviders = vi . fn ( ) . mockResolvedValue ( {
206+ payload : {
207+ providers : [
208+ {
209+ id : 'ark' ,
210+ name : 'Ark' ,
211+ source : 'custom' ,
212+ selected : false ,
213+ models : Array . from ( { length : 16 } , ( _ , index ) => ( {
214+ id : `ark-code-${ index + 1 } ` ,
215+ name : `ark-code-${ index + 1 } ` ,
216+ } ) ) ,
217+ } ,
218+ ] ,
219+ } ,
220+ } )
221+ mockGatewayAPI . getSessionModel = vi . fn ( ) . mockResolvedValue ( {
222+ payload : {
223+ provider_id : 'openai' ,
224+ model_id : 'gpt-5.4' ,
225+ model_name : 'GPT-5.4' ,
226+ provider : 'openai' ,
227+ } ,
228+ } )
229+
230+ render ( < Sidebar /> )
231+ fireEvent . click ( screen . getByRole ( 'button' , { name : / 供 应 商 / i } ) )
232+ await screen . findByText ( 'Ark' )
233+
234+ const arkCard = providerCard ( 'Ark' )
235+ const models = arkCard . querySelector ( '.config-card-models' )
236+ expect ( models ) . toBeInstanceOf ( HTMLElement )
237+ const modelRule = appCss . match ( / \. c o n f i g - c a r d - m o d e l s \s * { (?< body > [ ^ } ] * ) } / ) ?. groups ?. body ?? ''
238+ expect ( modelRule ) . toContain ( 'flex-wrap: nowrap' )
239+ expect ( modelRule ) . toContain ( 'overflow-x: auto' )
240+ expect ( modelRule ) . toContain ( 'overflow-y: hidden' )
241+ expect ( models ?. querySelectorAll ( '.config-card-model-tag' ) ) . toHaveLength ( 16 )
242+ expect ( within ( arkCard ) . getByRole ( 'button' , { name : / 选 择 / i } ) ) . toBeTruthy ( )
243+ expect ( within ( arkCard ) . getByRole ( 'button' , { name : / 删 除 / i } ) ) . toBeTruthy ( )
244+ } )
245+
202246 it ( 'only shows the expanded workspace style on the current workspace' , async ( ) => {
203247 const switchWorkspace = vi . fn ( ) . mockResolvedValue ( undefined )
204248 useWorkspaceStore . setState ( {
0 commit comments