@@ -22,6 +22,27 @@ import { render, fireEvent, within } from '@testing-library/svelte';
2222import ModelSelect from '/@/lib/select/ModelSelect.svelte' ;
2323import type { ModelInfo } from '@shared/models/IModelInfo' ;
2424import { InferenceType } from '@shared/models/IInference' ;
25+ import { writable , type Writable } from 'svelte/store' ;
26+ import type { ExtensionConfiguration } from '@shared/models/IExtensionConfiguration' ;
27+ import { configuration } from '/@/stores/extensionConfiguration' ;
28+
29+ vi . mock ( '../../stores/extensionConfiguration' , ( ) => ( {
30+ configuration : {
31+ subscribe : vi . fn ( ) ,
32+ unsubscribe : vi . fn ( ) ,
33+ } ,
34+ } ) ) ;
35+
36+ const mockConfiguration : Writable < ExtensionConfiguration > = writable ( {
37+ inferenceRuntime : 'llama-cpp' ,
38+ experimentalGPU : false ,
39+ showGPUPromotion : false ,
40+ modelUploadDisabled : false ,
41+ modelsPath : '' ,
42+ experimentalTuning : false ,
43+ apiPort : - 1 ,
44+ appearance : 'dark' ,
45+ } ) ;
2546
2647const fakeRecommendedModel : ModelInfo = {
2748 id : 'dummy-model-1' ,
@@ -45,9 +66,39 @@ const fakeRecommendedRemoteModel: ModelInfo = {
4566 name : 'Dummy Model 3' ,
4667} as unknown as ModelInfo ;
4768
69+ const fakeRemoteModelWhisper : ModelInfo = {
70+ id : 'dummy-model-4' ,
71+ backend : InferenceType . WHISPER_CPP ,
72+ name : 'Dummy Model 4' ,
73+ } as unknown as ModelInfo ;
74+
75+ const fakeRemoteModelNone : ModelInfo = {
76+ id : 'dummy-model-5' ,
77+ backend : InferenceType . NONE ,
78+ name : 'Dummy Model 5' ,
79+ } as unknown as ModelInfo ;
80+
81+ vi . mock ( '/@/utils/client' , async ( ) => {
82+ return {
83+ studioClient : {
84+ updateExtensionConfiguration : vi . fn ( ) ,
85+ telemetryLogUsage : vi . fn ( ) ,
86+ } ,
87+ } ;
88+ } ) ;
89+
90+ vi . mock ( '../../stores/extensionConfiguration' , ( ) => ( {
91+ configuration : {
92+ subscribe : vi . fn ( ) ,
93+ unsubscribe : vi . fn ( ) ,
94+ } ,
95+ } ) ) ;
96+
4897beforeEach ( ( ) => {
98+ vi . resetAllMocks ( ) ;
4999 // mock scrollIntoView
50100 window . HTMLElement . prototype . scrollIntoView = vi . fn ( ) ;
101+ vi . mocked ( configuration ) . subscribe . mockImplementation ( run => mockConfiguration . subscribe ( run ) ) ;
51102} ) ;
52103
53104test ( 'ModelSelect should list all models provided' , async ( ) => {
@@ -70,6 +121,26 @@ test('ModelSelect should list all models provided', async () => {
70121 expect ( items [ 1 ] ) . toHaveTextContent ( fakeRemoteModel . name ) ;
71122} ) ;
72123
124+ test ( 'ModelSelect should list all models based on selected runtime' , async ( ) => {
125+ const { container } = render ( ModelSelect , {
126+ value : undefined ,
127+ disabled : undefined ,
128+ models : [ fakeRecommendedModel , fakeRemoteModelWhisper , fakeRemoteModel , fakeRemoteModelNone ] ,
129+ recommended : [ ] ,
130+ } ) ;
131+
132+ // first get the select input
133+ const input = within ( container ) . getByLabelText ( 'Select Model' ) ;
134+ await fireEvent . pointerUp ( input ) ; // they are using the pointer up event instead of click.
135+
136+ // get all options available
137+ const items = container . querySelectorAll ( 'div[class~="list-item"]' ) ;
138+ // ensure we have two options
139+ expect ( items . length ) . toBe ( 2 ) ;
140+ expect ( items [ 0 ] ) . toHaveTextContent ( fakeRecommendedModel . name ) ;
141+ expect ( items [ 1 ] ) . toHaveTextContent ( fakeRemoteModel . name ) ;
142+ } ) ;
143+
73144test ( 'ModelSelect should set star icon next to recommended model' , async ( ) => {
74145 const { container } = render ( ModelSelect , {
75146 value : undefined ,
@@ -110,3 +181,30 @@ test('models should be sorted', async () => {
110181 expect ( items [ 1 ] ) . toHaveTextContent ( fakeRecommendedRemoteModel . name ) ;
111182 expect ( items [ 2 ] ) . toHaveTextContent ( fakeRemoteModel . name ) ;
112183} ) ;
184+
185+ test ( 'ModelSelect should filter out models based on selected default runtime' , async ( ) => {
186+ const { container } = render ( ModelSelect , {
187+ value : undefined ,
188+ disabled : undefined ,
189+ models : [
190+ fakeRecommendedModel ,
191+ fakeRemoteModel ,
192+ fakeRemoteModelNone ,
193+ fakeRemoteModelWhisper ,
194+ fakeRecommendedRemoteModel ,
195+ ] ,
196+ recommended : [ ] ,
197+ } ) ;
198+
199+ // first get the select input
200+ const input = within ( container ) . getByLabelText ( 'Select Model' ) ;
201+ await fireEvent . pointerUp ( input ) ; // they are using the pointer up event instead of click.
202+
203+ // get all options available
204+ const items = container . querySelectorAll ( 'div[class~="list-item"]' ) ;
205+ // ensure we have two options
206+ expect ( items . length ) . toBe ( 3 ) ;
207+ expect ( items [ 0 ] ) . toHaveTextContent ( fakeRecommendedModel . name ) ;
208+ expect ( items [ 1 ] ) . toHaveTextContent ( fakeRemoteModel . name ) ;
209+ expect ( items [ 2 ] ) . toHaveTextContent ( fakeRecommendedRemoteModel . name ) ;
210+ } ) ;
0 commit comments