@@ -29,6 +29,7 @@ const deleteSessionIfEmpty = vi.hoisted(() => vi.fn());
2929const appendMessage = vi . hoisted ( ( ) => vi . fn ( ) ) ;
3030const updateSessionModel = vi . hoisted ( ( ) => vi . fn ( ) ) ;
3131const saveConfig = vi . hoisted ( ( ) => vi . fn ( ) ) ;
32+ const checkHealth = vi . hoisted ( ( ) => vi . fn ( ) ) ;
3233const listModels = vi . hoisted ( ( ) => vi . fn ( ) ) ;
3334
3435vi . mock ( '@/utils' , async ( ) => ( {
@@ -46,6 +47,7 @@ vi.mock('@/utils', async () => ({
4647 saveConfig,
4748 } ,
4849 ollama : {
50+ checkHealth,
4951 listModels,
5052 } ,
5153 screen : {
@@ -217,9 +219,11 @@ vi.mock('./ReadinessCheck', async () => {
217219 ? 'Select or download a model'
218220 : setupState === 'no-installed-models'
219221 ? 'Download a model'
220- : errorMessage
221- ? `Unable to load models: ${ errorMessage } `
222- : setupState ;
222+ : setupState === 'server-unavailable'
223+ ? 'Run ollama serve'
224+ : errorMessage
225+ ? `Unable to load models: ${ errorMessage } `
226+ : setupState ;
223227 return < Text > { `Setup Required ${ message } ` } </ Text > ;
224228 } ,
225229 } ;
@@ -254,7 +258,9 @@ describe('App', () => {
254258 appendMessage . mockReset ( ) ;
255259 updateSessionModel . mockReset ( ) ;
256260 saveConfig . mockReset ( ) ;
261+ checkHealth . mockReset ( ) ;
257262 listModels . mockReset ( ) ;
263+ checkHealth . mockResolvedValue ( true ) ;
258264 listModels . mockResolvedValue ( [ 'gemma4' ] ) ;
259265
260266 let counter = 0 ;
@@ -542,6 +548,7 @@ describe('App', () => {
542548 expect ( lastFrame ( ) ) . toContain ( 'Setup Required' ) ;
543549 expect ( lastFrame ( ) ) . toContain ( 'Select or download a model' ) ;
544550 expect ( lastFrame ( ) ) . not . toContain ( 'session:' ) ;
551+ expect ( checkHealth ) . not . toHaveBeenCalled ( ) ;
545552 expect ( listModels ) . not . toHaveBeenCalled ( ) ;
546553 } ) ;
547554
@@ -557,6 +564,31 @@ describe('App', () => {
557564 expect ( lastFrame ( ) ) . not . toContain ( 'session:' ) ;
558565 } ) ;
559566
567+ it ( 'renders setup-needed content when Ollama is unreachable' , async ( ) => {
568+ checkHealth . mockResolvedValueOnce ( false ) ;
569+
570+ const { lastFrame } = render ( < App /> ) ;
571+ await time . tick ( ) ;
572+ await time . tick ( ) ;
573+
574+ expect ( lastFrame ( ) ) . toContain ( 'Setup Required' ) ;
575+ expect ( lastFrame ( ) ) . toContain ( 'Run ollama serve' ) ;
576+ expect ( lastFrame ( ) ) . not . toContain ( 'session:' ) ;
577+ expect ( listModels ) . not . toHaveBeenCalled ( ) ;
578+ } ) ;
579+
580+ it ( 'renders model-load error content when listing models fails' , async ( ) => {
581+ listModels . mockRejectedValueOnce ( new Error ( 'boom' ) ) ;
582+
583+ const { lastFrame } = render ( < App /> ) ;
584+ await time . tick ( ) ;
585+ await time . tick ( ) ;
586+
587+ expect ( lastFrame ( ) ) . toContain ( 'Setup Required' ) ;
588+ expect ( lastFrame ( ) ) . toContain ( 'Unable to load models: boom' ) ;
589+ expect ( lastFrame ( ) ) . not . toContain ( 'session:' ) ;
590+ } ) ;
591+
560592 it ( 'routes to ModelManager from setup-needed state' , async ( ) => {
561593 const { config } = await import ( '@/utils' ) ;
562594 vi . mocked ( config . loadConfig ) . mockReturnValueOnce ( {
0 commit comments