@@ -3,7 +3,9 @@ import { nextTick } from 'vue';
33import { createI18n } from 'vue-i18n' ;
44import { afterEach , describe , expect , it , vi } from 'vitest' ;
55
6+ import App from '../src/App.vue' ;
67import type { AppConfig , AppConnector , AppModel , AppSession , AppSkill } from '../src/api/types' ;
8+ import ConversationPane from '../src/components/ConversationPane.vue' ;
79import SettingsNav from '../src/components/settings/SettingsNav.vue' ;
810import SettingsPane from '../src/components/settings/SettingsPane.vue' ;
911import { messages } from '../src/i18n/locales' ;
@@ -82,9 +84,6 @@ vi.mock('../src/composables/usePythinkerWebClient', async () => {
8284 } ;
8385} ) ;
8486
85- import App from '../src/App.vue' ;
86- import ConversationPane from '../src/components/ConversationPane.vue' ;
87-
8887const i18n = createI18n ( {
8988 legacy : false ,
9089 locale : 'en' ,
@@ -240,6 +239,35 @@ describe('settings navigation', () => {
240239 setTab ( 'subagents' ) ;
241240 expect ( onLoadSubagents ) . toHaveBeenCalledOnce ( ) ;
242241 } ) ;
242+
243+ it ( 'reloads subagents even when a list is already cached' , ( ) => {
244+ // The cached list belongs to whichever session was active when it loaded,
245+ // so a non-empty count must not suppress the refetch.
246+ const onLoadSubagents = vi . fn ( ) ;
247+ const { setTab } = useSettingsNav ( {
248+ counts : { connectors : 0 , plugins : 0 , subagents : 3 } ,
249+ onLoadConnectors : vi . fn ( ) ,
250+ onLoadPlugins : vi . fn ( ) ,
251+ onLoadSubagents,
252+ } ) ;
253+
254+ setTab ( 'subagents' ) ;
255+ expect ( onLoadSubagents ) . toHaveBeenCalledOnce ( ) ;
256+ } ) ;
257+
258+ it ( 'reloads the persisted tab when the settings route reopens' , ( ) => {
259+ const onLoadSubagents = vi . fn ( ) ;
260+ const { setTab, refreshActiveTab } = useSettingsNav ( {
261+ counts : { connectors : 0 , plugins : 0 , subagents : 3 } ,
262+ onLoadConnectors : vi . fn ( ) ,
263+ onLoadPlugins : vi . fn ( ) ,
264+ onLoadSubagents,
265+ } ) ;
266+
267+ setTab ( 'subagents' ) ;
268+ refreshActiveTab ( ) ;
269+ expect ( onLoadSubagents ) . toHaveBeenCalledTimes ( 2 ) ;
270+ } ) ;
243271} ) ;
244272
245273describe ( 'SettingsPane config controls' , ( ) => {
@@ -297,6 +325,19 @@ describe('SettingsPane desktop updates', () => {
297325 } ) ;
298326} ) ;
299327
328+ describe ( 'SettingsPane agent page' , ( ) => {
329+ it ( 'keeps a configured default the catalog no longer offers' , ( ) => {
330+ // Without a matching option the browser shows its first one, which reads
331+ // as a saved default that was never chosen.
332+ const wrapper = mountPane ( 'agent' , { config : { ...config , defaultModel : 'retired/model' } } ) ;
333+ const select = wrapper . get ( '#settings-panel-agent select.select-field' ) ;
334+
335+ expect ( select . findAll ( 'option' ) . map ( ( option ) => option . attributes ( 'value' ) ) )
336+ . toContain ( 'retired/model' ) ;
337+ expect ( ( select . element as HTMLSelectElement ) . value ) . toBe ( 'retired/model' ) ;
338+ } ) ;
339+ } ) ;
340+
300341describe ( 'SettingsPane skills page' , ( ) => {
301342 it ( 'groups skills by source and marks the slash-only ones' , ( ) => {
302343 const panel = mountPane ( 'skills' , { skills } ) . get ( '#settings-panel-skills' ) ;
@@ -309,6 +350,23 @@ describe('SettingsPane skills page', () => {
309350 it ( 'says so when no skill is available' , ( ) => {
310351 expect ( mountPane ( 'skills' ) . get ( '#settings-panel-skills' ) . text ( ) ) . toContain ( 'No skills are available' ) ;
311352 } ) ;
353+
354+ it ( 'reads a disabled name that is cased differently as off, and clears it once' , async ( ) => {
355+ // The core lowercases disabled names, so a config entry cased differently
356+ // from the catalog still disables the skill and the page has to agree.
357+ const wrapper = mountPane ( 'skills' , {
358+ skills,
359+ config : { ...config , disabledSkills : [ 'Gen-Changesets' ] } ,
360+ } ) ;
361+ const row = wrapper . get ( '#settings-panel-skills' ) . findAll ( '.listing-row' )
362+ . find ( ( candidate ) => candidate . text ( ) . includes ( 'gen-changesets' ) ) ;
363+
364+ expect ( row ?. classes ( ) ) . toContain ( 'off' ) ;
365+
366+ await row ?. get ( 'button.switch' ) . trigger ( 'click' ) ;
367+
368+ expect ( wrapper . emitted ( 'updateConfig' ) ?. at ( - 1 ) ) . toEqual ( [ { disabledSkills : [ ] } ] ) ;
369+ } ) ;
312370} ) ;
313371
314372describe ( 'SettingsPane connectors page' , ( ) => {
0 commit comments