@@ -100,7 +100,7 @@ import { type LoadedSettings } from '../config/settings.js';
100100import { createMockSettings } from '../test-utils/settings.js' ;
101101import type { InitializationResult } from '../core/initializer.js' ;
102102import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.js' ;
103- import { StreamingState } from './types.js' ;
103+ import { StreamingState , MessageType } from './types.js' ;
104104import { UIStateContext , type UIState } from './contexts/UIStateContext.js' ;
105105import {
106106 UIActionsContext ,
@@ -3576,4 +3576,65 @@ describe('AppContainer State Management', () => {
35763576 unmount ( ) ;
35773577 } ) ;
35783578 } ) ;
3579+
3580+ describe ( 'Compression Queuing' , ( ) => {
3581+ beforeEach ( async ( ) => {
3582+ const { checkPermissions } = await import (
3583+ './hooks/atCommandProcessor.js'
3584+ ) ;
3585+ vi . mocked ( checkPermissions ) . mockResolvedValue ( [ ] ) ;
3586+
3587+ vi . spyOn ( mockConfig , 'isModelSteeringEnabled' ) . mockReturnValue ( true ) ;
3588+
3589+ const actual = await vi . importActual ( './hooks/useMessageQueue.js' ) ;
3590+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3591+ const { useMessageQueue : realUseMessageQueue } = actual as any ;
3592+ mockedUseMessageQueue . mockImplementation ( realUseMessageQueue ) ;
3593+
3594+ // Start compression by mocking pendingHistoryItems to include a pending compression
3595+ mockedUseGeminiStream . mockImplementation ( ( ) => ( {
3596+ ...DEFAULT_GEMINI_STREAM_MOCK ,
3597+ pendingHistoryItems : [
3598+ {
3599+ type : MessageType . COMPRESSION ,
3600+ compression : {
3601+ isPending : true ,
3602+ originalTokenCount : null ,
3603+ newTokenCount : null ,
3604+ compressionStatus : null ,
3605+ } ,
3606+ } ,
3607+ ] ,
3608+ } ) ) ;
3609+ } ) ;
3610+
3611+ it ( 'queues messages during compression instead of handling as steering hints' , async ( ) => {
3612+ const { unmount } = await act ( async ( ) => renderAppContainer ( ) ) ;
3613+
3614+ // Verify state isolation
3615+ expect ( capturedUIState . streamingState ) . toBe ( StreamingState . Idle ) ;
3616+
3617+ // Submit a message
3618+ await act ( async ( ) =>
3619+ capturedUIActions . handleFinalSubmit ( 'follow up message' ) ,
3620+ ) ;
3621+
3622+ // Verify it was queued, not submitted as steering hint
3623+ expect ( capturedUIState . messageQueue ) . toContain ( 'follow up message' ) ;
3624+
3625+ unmount ( ) ;
3626+ } ) ;
3627+
3628+ it ( 'executes slash commands immediately during compression' , async ( ) => {
3629+ const { unmount } = await act ( async ( ) => renderAppContainer ( ) ) ;
3630+
3631+ // Submit a slash command
3632+ await act ( async ( ) => capturedUIActions . handleFinalSubmit ( '/help' ) ) ;
3633+
3634+ // Verify it was NOT queued
3635+ expect ( capturedUIState . messageQueue ) . not . toContain ( '/help' ) ;
3636+
3637+ unmount ( ) ;
3638+ } ) ;
3639+ } ) ;
35793640} ) ;
0 commit comments