@@ -11,6 +11,11 @@ import { useSelectedModel } from "@src/components/ui/hooks/useSelectedModel"
1111import ApiOptions from "../ApiOptions"
1212import { MODELS_BY_PROVIDER , PROVIDERS } from "../constants"
1313
14+ type ProviderOption = {
15+ value : string
16+ label : string
17+ }
18+
1419// Mock the extension state context
1520vi . mock ( "@src/context/ExtensionStateContext" , ( ) => ( {
1621 ExtensionStateContextProvider : ( { children } : any ) => children ,
@@ -113,6 +118,11 @@ describe("ApiOptions Provider Filtering", () => {
113118 return renderWithExtensionState ( < ApiOptions { ...props } /> )
114119 }
115120
121+ const getProviderOptions = ( ) : ProviderOption [ ] => {
122+ const selectElement = screen . getByTestId ( "provider-select" )
123+ return JSON . parse ( selectElement . getAttribute ( "data-options" ) || "[]" ) as ProviderOption [ ]
124+ }
125+
116126 beforeEach ( ( ) => {
117127 vi . clearAllMocks ( )
118128 vi . mocked ( useSelectedModel ) . mockReturnValue ( {
@@ -190,6 +200,64 @@ describe("ApiOptions Provider Filtering", () => {
190200 expect ( providerValues ) . toContain ( "ollama" ) // dynamic provider
191201 } )
192202
203+ it ( "pins Zoo Gateway first while preserving alphabetical order for the remaining providers" , ( ) => {
204+ renderWithProviders ( )
205+
206+ const options = getProviderOptions ( )
207+ const remainingLabels = options . slice ( 1 ) . map ( ( { label } ) => label )
208+
209+ expect ( options [ 0 ] ?. value ) . toBe ( providerIdentifiers . zooGateway )
210+ expect ( remainingLabels ) . toEqual ( [ ...remainingLabels ] . sort ( ( a , b ) => a . localeCompare ( b ) ) )
211+ } )
212+
213+ it ( "pins Zoo Gateway first and OpenRouter second in the welcome view" , ( ) => {
214+ renderWithProviders ( { ...defaultProps , fromWelcomeView : true } )
215+
216+ const providerValues = getProviderOptions ( ) . map ( ( { value } ) => value )
217+
218+ expect ( providerValues . slice ( 0 , 2 ) ) . toEqual ( [ providerIdentifiers . zooGateway , providerIdentifiers . openrouter ] )
219+ } )
220+
221+ it ( "does not reintroduce Zoo Gateway when an organization allow list excludes it" , ( ) => {
222+ vi . mocked ( useExtensionState ) . mockReturnValueOnce ( {
223+ ...useExtensionState ( ) ,
224+ organizationAllowList : {
225+ allowAll : false ,
226+ providers : {
227+ [ providerIdentifiers . anthropic ] : { allowAll : true } ,
228+ [ providerIdentifiers . openrouter ] : { allowAll : true } ,
229+ } ,
230+ } ,
231+ } )
232+
233+ renderWithProviders ( )
234+
235+ expect ( getProviderOptions ( ) . map ( ( { value } ) => value ) ) . toEqual ( [
236+ providerIdentifiers . anthropic ,
237+ providerIdentifiers . openrouter ,
238+ ] )
239+ } )
240+
241+ it ( "keeps Zoo Gateway first when an organization allow list includes it" , ( ) => {
242+ vi . mocked ( useExtensionState ) . mockReturnValueOnce ( {
243+ ...useExtensionState ( ) ,
244+ organizationAllowList : {
245+ allowAll : false ,
246+ providers : {
247+ [ providerIdentifiers . anthropic ] : { allowAll : true } ,
248+ [ providerIdentifiers . zooGateway ] : { allowAll : true } ,
249+ } ,
250+ } ,
251+ } )
252+
253+ renderWithProviders ( )
254+
255+ expect ( getProviderOptions ( ) . map ( ( { value } ) => value ) ) . toEqual ( [
256+ providerIdentifiers . zooGateway ,
257+ providerIdentifiers . anthropic ,
258+ ] )
259+ } )
260+
193261 it ( "should hide static providers with empty models" , ( ) => {
194262 // Mock MODELS_BY_PROVIDER to have an empty provider
195263 const _originalModels = { ...MODELS_BY_PROVIDER }
0 commit comments