@google/gemini-cli 0.15.0-nightly.20251111.51f952e7 → 0.15.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +2 -2
- package/dist/src/config/config.d.ts +3 -0
- package/dist/src/config/config.js +31 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +20 -0
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.js +13 -1
- package/dist/src/config/extension-manager.js.map +1 -1
- package/dist/src/config/extension.test.js +65 -0
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +10 -1
- package/dist/src/config/settingsSchema.js +10 -1
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/gemini.d.ts +2 -2
- package/dist/src/gemini.js +35 -4
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +14 -7
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.d.ts +3 -2
- package/dist/src/nonInteractiveCli.js +6 -1
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +1 -0
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/test-utils/render.d.ts +2 -1
- package/dist/src/test-utils/render.js +13 -3
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/ui/App.js +9 -1
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/App.test.js +25 -1
- package/dist/src/ui/App.test.js.map +1 -1
- package/dist/src/ui/AppContainer.d.ts +2 -3
- package/dist/src/ui/AppContainer.js +22 -7
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +349 -46
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.js +4 -1
- package/dist/src/ui/commands/toolsCommand.js.map +1 -1
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.d.ts +6 -0
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.js +24 -0
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.js.map +1 -0
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.d.ts +6 -0
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +101 -0
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +1 -0
- package/dist/src/ui/components/Composer.js +11 -4
- package/dist/src/ui/components/Composer.js.map +1 -1
- package/dist/src/ui/components/CopyModeWarning.d.ts +7 -0
- package/dist/src/ui/components/CopyModeWarning.js +12 -0
- package/dist/src/ui/components/CopyModeWarning.js.map +1 -0
- package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
- package/dist/src/ui/components/Header.js +11 -1
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/Header.test.js +69 -14
- package/dist/src/ui/components/Header.test.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.test.js +43 -41
- package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.d.ts +2 -0
- package/dist/src/ui/components/InputPrompt.js +14 -8
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/MainContent.js +52 -15
- package/dist/src/ui/components/MainContent.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.test.js +1 -0
- package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
- package/dist/src/ui/components/StickyHeader.d.ts +11 -0
- package/dist/src/ui/components/StickyHeader.js +5 -0
- package/dist/src/ui/components/StickyHeader.js.map +1 -0
- package/dist/src/ui/components/StickyHeader.test.d.ts +6 -0
- package/dist/src/ui/components/StickyHeader.test.js +17 -0
- package/dist/src/ui/components/StickyHeader.test.js.map +1 -0
- package/dist/src/ui/components/ThemeDialog.js +11 -3
- package/dist/src/ui/components/ThemeDialog.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.js +129 -89
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js +107 -115
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
- package/dist/src/ui/components/messages/GeminiMessage.js +3 -1
- package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -1
- package/dist/src/ui/components/messages/GeminiMessageContent.js +3 -1
- package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +152 -121
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.js +5 -7
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +1 -5
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.js +39 -16
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js +33 -4
- package/dist/src/ui/components/messages/ToolMessageRawMarkdown.test.js.map +1 -1
- package/dist/src/ui/components/messages/UserMessage.d.ts +1 -0
- package/dist/src/ui/components/messages/UserMessage.js +2 -2
- package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
- package/dist/src/ui/components/shared/ScrollableList.test.js +61 -24
- package/dist/src/ui/components/shared/ScrollableList.test.js.map +1 -1
- package/dist/src/ui/components/shared/VirtualizedList.js +1 -1
- package/dist/src/ui/components/shared/VirtualizedList.js.map +1 -1
- package/dist/src/ui/constants.d.ts +1 -0
- package/dist/src/ui/constants.js +5 -0
- package/dist/src/ui/constants.js.map +1 -1
- package/dist/src/ui/contexts/UIStateContext.d.ts +1 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAlternateBuffer.d.ts +6 -0
- package/dist/src/ui/hooks/useAlternateBuffer.js +11 -0
- package/dist/src/ui/hooks/useAlternateBuffer.js.map +1 -0
- package/dist/src/ui/hooks/useGeminiStream.test.js +4 -0
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/usePromptCompletion.js +2 -9
- package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSessionBrowser.d.ts +18 -0
- package/dist/src/ui/hooks/useSessionBrowser.js +152 -0
- package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -0
- package/dist/src/ui/hooks/useSessionBrowser.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSessionBrowser.test.js +544 -0
- package/dist/src/ui/hooks/useSessionBrowser.test.js.map +1 -0
- package/dist/src/ui/hooks/useSessionResume.d.ts +30 -0
- package/dist/src/ui/hooks/useSessionResume.js +56 -0
- package/dist/src/ui/hooks/useSessionResume.js.map +1 -0
- package/dist/src/ui/hooks/useSessionResume.test.d.ts +6 -0
- package/dist/src/ui/hooks/useSessionResume.test.js +325 -0
- package/dist/src/ui/hooks/useSessionResume.test.js.map +1 -0
- package/dist/src/ui/hooks/useToolScheduler.test.js +1 -0
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/layouts/DefaultAppLayout.js +9 -3
- package/dist/src/ui/layouts/DefaultAppLayout.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.d.ts +11 -3
- package/dist/src/ui/utils/CodeColorizer.js +18 -9
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +32 -6
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/ui-sizing.js +9 -3
- package/dist/src/ui/utils/ui-sizing.js.map +1 -1
- package/dist/src/utils/cleanup.test.js +1 -1
- package/dist/src/utils/cleanup.test.js.map +1 -1
- package/dist/src/utils/sessionCleanup.test.js +76 -0
- package/dist/src/utils/sessionCleanup.test.js.map +1 -1
- package/dist/src/utils/sessionUtils.d.ts +54 -0
- package/dist/src/utils/sessionUtils.js +141 -1
- package/dist/src/utils/sessionUtils.js.map +1 -1
- package/dist/src/utils/sessionUtils.test.d.ts +6 -0
- package/dist/src/utils/sessionUtils.test.js +260 -0
- package/dist/src/utils/sessionUtils.test.js.map +1 -0
- package/dist/src/utils/sessions.d.ts +8 -0
- package/dist/src/utils/sessions.js +64 -0
- package/dist/src/utils/sessions.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/google-gemini-cli-0.15.0-nightly.20251107.b8eeb553.tgz +0 -0
|
@@ -9,6 +9,7 @@ import { render } from '../test-utils/render.js';
|
|
|
9
9
|
import { cleanup } from 'ink-testing-library';
|
|
10
10
|
import { act, useContext } from 'react';
|
|
11
11
|
import { AppContainer } from './AppContainer.js';
|
|
12
|
+
import { SettingsContext } from './contexts/SettingsContext.js';
|
|
12
13
|
import { makeFakeConfig, CoreEvent, } from '@google/gemini-cli-core';
|
|
13
14
|
// Mock coreEvents
|
|
14
15
|
const mockCoreEvents = vi.hoisted(() => ({
|
|
@@ -116,6 +117,10 @@ describe('AppContainer State Management', () => {
|
|
|
116
117
|
let mockSettings;
|
|
117
118
|
let mockInitResult;
|
|
118
119
|
let mockExtensionManager;
|
|
120
|
+
// Helper to generate the AppContainer JSX for render and rerender
|
|
121
|
+
const getAppContainer = ({ settings = mockSettings, config = mockConfig, version = '1.0.0', initResult = mockInitResult, startupWarnings, resumedSessionData, } = {}) => (_jsx(SettingsContext.Provider, { value: settings, children: _jsx(AppContainer, { config: config, version: version, initializationResult: initResult, startupWarnings: startupWarnings, resumedSessionData: resumedSessionData }) }));
|
|
122
|
+
// Helper to render the AppContainer
|
|
123
|
+
const renderAppContainer = (props) => render(getAppContainer(props));
|
|
119
124
|
// Create typed mocks for all hooks
|
|
120
125
|
const mockedUseQuotaAndFallback = useQuotaAndFallback;
|
|
121
126
|
const mockedUseHistory = useHistory;
|
|
@@ -270,6 +275,7 @@ describe('AppContainer State Management', () => {
|
|
|
270
275
|
showStatusInTitle: false,
|
|
271
276
|
hideWindowTitle: false,
|
|
272
277
|
},
|
|
278
|
+
useAlternateBuffer: false,
|
|
273
279
|
},
|
|
274
280
|
};
|
|
275
281
|
// Mock InitializationResult
|
|
@@ -285,7 +291,7 @@ describe('AppContainer State Management', () => {
|
|
|
285
291
|
});
|
|
286
292
|
describe('Basic Rendering', () => {
|
|
287
293
|
it('renders without crashing with minimal props', async () => {
|
|
288
|
-
const { unmount } =
|
|
294
|
+
const { unmount } = renderAppContainer();
|
|
289
295
|
await act(async () => {
|
|
290
296
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
291
297
|
});
|
|
@@ -293,7 +299,7 @@ describe('AppContainer State Management', () => {
|
|
|
293
299
|
});
|
|
294
300
|
it('renders with startup warnings', async () => {
|
|
295
301
|
const startupWarnings = ['Warning 1', 'Warning 2'];
|
|
296
|
-
const { unmount } =
|
|
302
|
+
const { unmount } = renderAppContainer({ startupWarnings });
|
|
297
303
|
await act(async () => {
|
|
298
304
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
299
305
|
});
|
|
@@ -306,7 +312,9 @@ describe('AppContainer State Management', () => {
|
|
|
306
312
|
...mockInitResult,
|
|
307
313
|
themeError: 'Failed to load theme',
|
|
308
314
|
};
|
|
309
|
-
const { unmount } =
|
|
315
|
+
const { unmount } = renderAppContainer({
|
|
316
|
+
initResult: initResultWithError,
|
|
317
|
+
});
|
|
310
318
|
await act(async () => {
|
|
311
319
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
312
320
|
});
|
|
@@ -316,13 +324,13 @@ describe('AppContainer State Management', () => {
|
|
|
316
324
|
const debugConfig = makeFakeConfig();
|
|
317
325
|
vi.spyOn(debugConfig, 'getDebugMode').mockReturnValue(true);
|
|
318
326
|
expect(() => {
|
|
319
|
-
|
|
327
|
+
renderAppContainer({ config: debugConfig });
|
|
320
328
|
}).not.toThrow();
|
|
321
329
|
});
|
|
322
330
|
});
|
|
323
331
|
describe('Context Providers', () => {
|
|
324
332
|
it('provides AppContext with correct values', async () => {
|
|
325
|
-
const { unmount } =
|
|
333
|
+
const { unmount } = renderAppContainer({ version: '2.0.0' });
|
|
326
334
|
await act(async () => {
|
|
327
335
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
328
336
|
});
|
|
@@ -330,21 +338,21 @@ describe('AppContainer State Management', () => {
|
|
|
330
338
|
expect(() => unmount()).not.toThrow();
|
|
331
339
|
});
|
|
332
340
|
it('provides UIStateContext with state management', async () => {
|
|
333
|
-
const { unmount } =
|
|
341
|
+
const { unmount } = renderAppContainer();
|
|
334
342
|
await act(async () => {
|
|
335
343
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
336
344
|
});
|
|
337
345
|
unmount();
|
|
338
346
|
});
|
|
339
347
|
it('provides UIActionsContext with action handlers', async () => {
|
|
340
|
-
const { unmount } =
|
|
348
|
+
const { unmount } = renderAppContainer();
|
|
341
349
|
await act(async () => {
|
|
342
350
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
343
351
|
});
|
|
344
352
|
unmount();
|
|
345
353
|
});
|
|
346
354
|
it('provides ConfigContext with config object', async () => {
|
|
347
|
-
const { unmount } =
|
|
355
|
+
const { unmount } = renderAppContainer();
|
|
348
356
|
await act(async () => {
|
|
349
357
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
350
358
|
});
|
|
@@ -361,7 +369,7 @@ describe('AppContainer State Management', () => {
|
|
|
361
369
|
showMemoryUsage: false,
|
|
362
370
|
},
|
|
363
371
|
};
|
|
364
|
-
const { unmount } =
|
|
372
|
+
const { unmount } = renderAppContainer({ settings: settingsAllHidden });
|
|
365
373
|
await act(async () => {
|
|
366
374
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
367
375
|
});
|
|
@@ -376,7 +384,7 @@ describe('AppContainer State Management', () => {
|
|
|
376
384
|
showMemoryUsage: true,
|
|
377
385
|
},
|
|
378
386
|
};
|
|
379
|
-
const { unmount } =
|
|
387
|
+
const { unmount } = renderAppContainer({ settings: settingsWithMemory });
|
|
380
388
|
await act(async () => {
|
|
381
389
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
382
390
|
});
|
|
@@ -385,7 +393,7 @@ describe('AppContainer State Management', () => {
|
|
|
385
393
|
});
|
|
386
394
|
describe('Version Handling', () => {
|
|
387
395
|
it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', async (version) => {
|
|
388
|
-
const { unmount } =
|
|
396
|
+
const { unmount } = renderAppContainer({ version });
|
|
389
397
|
await act(async () => {
|
|
390
398
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
391
399
|
});
|
|
@@ -399,7 +407,7 @@ describe('AppContainer State Management', () => {
|
|
|
399
407
|
throw new Error('Config error');
|
|
400
408
|
});
|
|
401
409
|
// Should still render without crashing - errors should be handled internally
|
|
402
|
-
const { unmount } =
|
|
410
|
+
const { unmount } = renderAppContainer({ config: errorConfig });
|
|
403
411
|
await act(async () => {
|
|
404
412
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
405
413
|
});
|
|
@@ -409,7 +417,7 @@ describe('AppContainer State Management', () => {
|
|
|
409
417
|
const undefinedSettings = {
|
|
410
418
|
merged: {},
|
|
411
419
|
};
|
|
412
|
-
const { unmount } =
|
|
420
|
+
const { unmount } = renderAppContainer({ settings: undefinedSettings });
|
|
413
421
|
await act(async () => {
|
|
414
422
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
415
423
|
});
|
|
@@ -420,14 +428,294 @@ describe('AppContainer State Management', () => {
|
|
|
420
428
|
it('establishes correct provider nesting order', () => {
|
|
421
429
|
// This tests that all the context providers are properly nested
|
|
422
430
|
// and that the component tree can be built without circular dependencies
|
|
423
|
-
const { unmount } =
|
|
431
|
+
const { unmount } = renderAppContainer();
|
|
424
432
|
expect(() => unmount()).not.toThrow();
|
|
425
433
|
});
|
|
426
434
|
});
|
|
435
|
+
describe('Session Resumption', () => {
|
|
436
|
+
it('handles resumed session data correctly', async () => {
|
|
437
|
+
const mockResumedSessionData = {
|
|
438
|
+
conversation: {
|
|
439
|
+
sessionId: 'test-session-123',
|
|
440
|
+
projectHash: 'test-project-hash',
|
|
441
|
+
startTime: '2024-01-01T00:00:00Z',
|
|
442
|
+
lastUpdated: '2024-01-01T00:00:01Z',
|
|
443
|
+
messages: [
|
|
444
|
+
{
|
|
445
|
+
id: 'msg-1',
|
|
446
|
+
type: 'user',
|
|
447
|
+
content: 'Hello',
|
|
448
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
id: 'msg-2',
|
|
452
|
+
type: 'gemini',
|
|
453
|
+
content: 'Hi there!',
|
|
454
|
+
role: 'model',
|
|
455
|
+
parts: [{ text: 'Hi there!' }],
|
|
456
|
+
timestamp: '2024-01-01T00:00:01Z',
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
},
|
|
460
|
+
filePath: '/tmp/test-session.json',
|
|
461
|
+
};
|
|
462
|
+
let unmount;
|
|
463
|
+
await act(async () => {
|
|
464
|
+
const result = renderAppContainer({
|
|
465
|
+
config: mockConfig,
|
|
466
|
+
settings: mockSettings,
|
|
467
|
+
version: '1.0.0',
|
|
468
|
+
initResult: mockInitResult,
|
|
469
|
+
resumedSessionData: mockResumedSessionData,
|
|
470
|
+
});
|
|
471
|
+
unmount = result.unmount;
|
|
472
|
+
});
|
|
473
|
+
await act(async () => {
|
|
474
|
+
unmount();
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
it('renders without resumed session data', async () => {
|
|
478
|
+
let unmount;
|
|
479
|
+
await act(async () => {
|
|
480
|
+
const result = renderAppContainer({
|
|
481
|
+
config: mockConfig,
|
|
482
|
+
settings: mockSettings,
|
|
483
|
+
version: '1.0.0',
|
|
484
|
+
initResult: mockInitResult,
|
|
485
|
+
resumedSessionData: undefined,
|
|
486
|
+
});
|
|
487
|
+
unmount = result.unmount;
|
|
488
|
+
});
|
|
489
|
+
await act(async () => {
|
|
490
|
+
unmount();
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
it('initializes chat recording service when config has it', () => {
|
|
494
|
+
const mockChatRecordingService = {
|
|
495
|
+
initialize: vi.fn(),
|
|
496
|
+
recordMessage: vi.fn(),
|
|
497
|
+
recordMessageTokens: vi.fn(),
|
|
498
|
+
recordToolCalls: vi.fn(),
|
|
499
|
+
};
|
|
500
|
+
const mockGeminiClient = {
|
|
501
|
+
isInitialized: vi.fn(() => true),
|
|
502
|
+
resumeChat: vi.fn(),
|
|
503
|
+
getUserTier: vi.fn(),
|
|
504
|
+
getChatRecordingService: vi.fn(() => mockChatRecordingService),
|
|
505
|
+
};
|
|
506
|
+
const configWithRecording = {
|
|
507
|
+
...mockConfig,
|
|
508
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
509
|
+
};
|
|
510
|
+
expect(() => {
|
|
511
|
+
renderAppContainer({
|
|
512
|
+
config: configWithRecording,
|
|
513
|
+
settings: mockSettings,
|
|
514
|
+
version: '1.0.0',
|
|
515
|
+
initResult: mockInitResult,
|
|
516
|
+
});
|
|
517
|
+
}).not.toThrow();
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
describe('Session Recording Integration', () => {
|
|
521
|
+
it('provides chat recording service configuration', () => {
|
|
522
|
+
const mockChatRecordingService = {
|
|
523
|
+
initialize: vi.fn(),
|
|
524
|
+
recordMessage: vi.fn(),
|
|
525
|
+
recordMessageTokens: vi.fn(),
|
|
526
|
+
recordToolCalls: vi.fn(),
|
|
527
|
+
getSessionId: vi.fn(() => 'test-session-123'),
|
|
528
|
+
getCurrentConversation: vi.fn(),
|
|
529
|
+
};
|
|
530
|
+
const mockGeminiClient = {
|
|
531
|
+
isInitialized: vi.fn(() => true),
|
|
532
|
+
resumeChat: vi.fn(),
|
|
533
|
+
getUserTier: vi.fn(),
|
|
534
|
+
getChatRecordingService: vi.fn(() => mockChatRecordingService),
|
|
535
|
+
setHistory: vi.fn(),
|
|
536
|
+
};
|
|
537
|
+
const configWithRecording = {
|
|
538
|
+
...mockConfig,
|
|
539
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
540
|
+
getSessionId: vi.fn(() => 'test-session-123'),
|
|
541
|
+
};
|
|
542
|
+
expect(() => {
|
|
543
|
+
renderAppContainer({
|
|
544
|
+
config: configWithRecording,
|
|
545
|
+
settings: mockSettings,
|
|
546
|
+
version: '1.0.0',
|
|
547
|
+
initResult: mockInitResult,
|
|
548
|
+
});
|
|
549
|
+
}).not.toThrow();
|
|
550
|
+
// Verify the recording service structure is correct
|
|
551
|
+
expect(configWithRecording.getGeminiClient).toBeDefined();
|
|
552
|
+
expect(mockGeminiClient.getChatRecordingService).toBeDefined();
|
|
553
|
+
expect(mockChatRecordingService.initialize).toBeDefined();
|
|
554
|
+
expect(mockChatRecordingService.recordMessage).toBeDefined();
|
|
555
|
+
});
|
|
556
|
+
it('handles session recording when messages are added', () => {
|
|
557
|
+
const mockRecordMessage = vi.fn();
|
|
558
|
+
const mockRecordMessageTokens = vi.fn();
|
|
559
|
+
const mockChatRecordingService = {
|
|
560
|
+
initialize: vi.fn(),
|
|
561
|
+
recordMessage: mockRecordMessage,
|
|
562
|
+
recordMessageTokens: mockRecordMessageTokens,
|
|
563
|
+
recordToolCalls: vi.fn(),
|
|
564
|
+
getSessionId: vi.fn(() => 'test-session-123'),
|
|
565
|
+
};
|
|
566
|
+
const mockGeminiClient = {
|
|
567
|
+
isInitialized: vi.fn(() => true),
|
|
568
|
+
getChatRecordingService: vi.fn(() => mockChatRecordingService),
|
|
569
|
+
getUserTier: vi.fn(),
|
|
570
|
+
};
|
|
571
|
+
const configWithRecording = {
|
|
572
|
+
...mockConfig,
|
|
573
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
574
|
+
};
|
|
575
|
+
renderAppContainer({
|
|
576
|
+
config: configWithRecording,
|
|
577
|
+
settings: mockSettings,
|
|
578
|
+
version: '1.0.0',
|
|
579
|
+
initResult: mockInitResult,
|
|
580
|
+
});
|
|
581
|
+
// The actual recording happens through the useHistory hook
|
|
582
|
+
// which would be triggered by user interactions
|
|
583
|
+
expect(mockChatRecordingService.initialize).toBeDefined();
|
|
584
|
+
expect(mockChatRecordingService.recordMessage).toBeDefined();
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
describe('Session Resume Flow', () => {
|
|
588
|
+
it('accepts resumed session data', () => {
|
|
589
|
+
const mockResumeChat = vi.fn();
|
|
590
|
+
const mockGeminiClient = {
|
|
591
|
+
isInitialized: vi.fn(() => true),
|
|
592
|
+
resumeChat: mockResumeChat,
|
|
593
|
+
getUserTier: vi.fn(),
|
|
594
|
+
getChatRecordingService: vi.fn(() => ({
|
|
595
|
+
initialize: vi.fn(),
|
|
596
|
+
recordMessage: vi.fn(),
|
|
597
|
+
recordMessageTokens: vi.fn(),
|
|
598
|
+
recordToolCalls: vi.fn(),
|
|
599
|
+
})),
|
|
600
|
+
};
|
|
601
|
+
const configWithClient = {
|
|
602
|
+
...mockConfig,
|
|
603
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
604
|
+
};
|
|
605
|
+
const resumedData = {
|
|
606
|
+
conversation: {
|
|
607
|
+
sessionId: 'resumed-session-456',
|
|
608
|
+
projectHash: 'project-hash',
|
|
609
|
+
startTime: '2024-01-01T00:00:00Z',
|
|
610
|
+
lastUpdated: '2024-01-01T00:01:00Z',
|
|
611
|
+
messages: [
|
|
612
|
+
{
|
|
613
|
+
id: 'msg-1',
|
|
614
|
+
type: 'user',
|
|
615
|
+
content: 'Previous question',
|
|
616
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
id: 'msg-2',
|
|
620
|
+
type: 'gemini',
|
|
621
|
+
content: 'Previous answer',
|
|
622
|
+
role: 'model',
|
|
623
|
+
parts: [{ text: 'Previous answer' }],
|
|
624
|
+
timestamp: '2024-01-01T00:00:30Z',
|
|
625
|
+
tokenCount: { input: 10, output: 20 },
|
|
626
|
+
},
|
|
627
|
+
],
|
|
628
|
+
},
|
|
629
|
+
filePath: '/tmp/resumed-session.json',
|
|
630
|
+
};
|
|
631
|
+
expect(() => {
|
|
632
|
+
renderAppContainer({
|
|
633
|
+
config: configWithClient,
|
|
634
|
+
settings: mockSettings,
|
|
635
|
+
version: '1.0.0',
|
|
636
|
+
initResult: mockInitResult,
|
|
637
|
+
resumedSessionData: resumedData,
|
|
638
|
+
});
|
|
639
|
+
}).not.toThrow();
|
|
640
|
+
// Verify the resume functionality structure is in place
|
|
641
|
+
expect(mockGeminiClient.resumeChat).toBeDefined();
|
|
642
|
+
expect(resumedData.conversation.messages).toHaveLength(2);
|
|
643
|
+
});
|
|
644
|
+
it('does not attempt resume when client is not initialized', () => {
|
|
645
|
+
const mockResumeChat = vi.fn();
|
|
646
|
+
const mockGeminiClient = {
|
|
647
|
+
isInitialized: vi.fn(() => false), // Not initialized
|
|
648
|
+
resumeChat: mockResumeChat,
|
|
649
|
+
getUserTier: vi.fn(),
|
|
650
|
+
getChatRecordingService: vi.fn(),
|
|
651
|
+
};
|
|
652
|
+
const configWithClient = {
|
|
653
|
+
...mockConfig,
|
|
654
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
655
|
+
};
|
|
656
|
+
const resumedData = {
|
|
657
|
+
conversation: {
|
|
658
|
+
sessionId: 'test-session',
|
|
659
|
+
projectHash: 'project-hash',
|
|
660
|
+
startTime: '2024-01-01T00:00:00Z',
|
|
661
|
+
lastUpdated: '2024-01-01T00:01:00Z',
|
|
662
|
+
messages: [],
|
|
663
|
+
},
|
|
664
|
+
filePath: '/tmp/session.json',
|
|
665
|
+
};
|
|
666
|
+
renderAppContainer({
|
|
667
|
+
config: configWithClient,
|
|
668
|
+
settings: mockSettings,
|
|
669
|
+
version: '1.0.0',
|
|
670
|
+
initResult: mockInitResult,
|
|
671
|
+
resumedSessionData: resumedData,
|
|
672
|
+
});
|
|
673
|
+
// Should not call resumeChat when client is not initialized
|
|
674
|
+
expect(mockResumeChat).not.toHaveBeenCalled();
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
describe('Token Counting from Session Stats', () => {
|
|
678
|
+
it('tracks token counts from session messages', () => {
|
|
679
|
+
// Session stats are provided through the SessionStatsProvider context
|
|
680
|
+
// in the real app, not through the config directly
|
|
681
|
+
const mockChatRecordingService = {
|
|
682
|
+
initialize: vi.fn(),
|
|
683
|
+
recordMessage: vi.fn(),
|
|
684
|
+
recordMessageTokens: vi.fn(),
|
|
685
|
+
recordToolCalls: vi.fn(),
|
|
686
|
+
getSessionId: vi.fn(() => 'test-session-123'),
|
|
687
|
+
getCurrentConversation: vi.fn(() => ({
|
|
688
|
+
sessionId: 'test-session-123',
|
|
689
|
+
messages: [],
|
|
690
|
+
totalInputTokens: 150,
|
|
691
|
+
totalOutputTokens: 350,
|
|
692
|
+
})),
|
|
693
|
+
};
|
|
694
|
+
const mockGeminiClient = {
|
|
695
|
+
isInitialized: vi.fn(() => true),
|
|
696
|
+
getChatRecordingService: vi.fn(() => mockChatRecordingService),
|
|
697
|
+
getUserTier: vi.fn(),
|
|
698
|
+
};
|
|
699
|
+
const configWithRecording = {
|
|
700
|
+
...mockConfig,
|
|
701
|
+
getGeminiClient: vi.fn(() => mockGeminiClient),
|
|
702
|
+
};
|
|
703
|
+
renderAppContainer({
|
|
704
|
+
config: configWithRecording,
|
|
705
|
+
settings: mockSettings,
|
|
706
|
+
version: '1.0.0',
|
|
707
|
+
initResult: mockInitResult,
|
|
708
|
+
});
|
|
709
|
+
// In the actual app, these stats would be displayed in components
|
|
710
|
+
// and updated as messages are processed through the recording service
|
|
711
|
+
expect(mockChatRecordingService.recordMessageTokens).toBeDefined();
|
|
712
|
+
expect(mockChatRecordingService.getCurrentConversation).toBeDefined();
|
|
713
|
+
});
|
|
714
|
+
});
|
|
427
715
|
describe('Quota and Fallback Integration', () => {
|
|
428
716
|
it('passes a null proQuotaRequest to UIStateContext by default', async () => {
|
|
429
717
|
// The default mock from beforeEach already sets proQuotaRequest to null
|
|
430
|
-
const { unmount } =
|
|
718
|
+
const { unmount } = renderAppContainer();
|
|
431
719
|
await act(async () => {
|
|
432
720
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
433
721
|
});
|
|
@@ -447,7 +735,7 @@ describe('AppContainer State Management', () => {
|
|
|
447
735
|
handleProQuotaChoice: vi.fn(),
|
|
448
736
|
});
|
|
449
737
|
// Act: Render the container
|
|
450
|
-
const { unmount } =
|
|
738
|
+
const { unmount } = renderAppContainer();
|
|
451
739
|
await act(async () => {
|
|
452
740
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
453
741
|
});
|
|
@@ -463,7 +751,7 @@ describe('AppContainer State Management', () => {
|
|
|
463
751
|
handleProQuotaChoice: mockHandler,
|
|
464
752
|
});
|
|
465
753
|
// Act: Render the container
|
|
466
|
-
const { unmount } =
|
|
754
|
+
const { unmount } = renderAppContainer();
|
|
467
755
|
await act(async () => {
|
|
468
756
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
469
757
|
});
|
|
@@ -496,7 +784,9 @@ describe('AppContainer State Management', () => {
|
|
|
496
784
|
},
|
|
497
785
|
};
|
|
498
786
|
// Act: Render the container
|
|
499
|
-
const { unmount } =
|
|
787
|
+
const { unmount } = renderAppContainer({
|
|
788
|
+
settings: mockSettingsWithShowStatusFalse,
|
|
789
|
+
});
|
|
500
790
|
// Assert: Check that no title-related writes occurred
|
|
501
791
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
502
792
|
expect(titleWrites).toHaveLength(0);
|
|
@@ -516,7 +806,9 @@ describe('AppContainer State Management', () => {
|
|
|
516
806
|
},
|
|
517
807
|
};
|
|
518
808
|
// Act: Render the container
|
|
519
|
-
const { unmount } =
|
|
809
|
+
const { unmount } = renderAppContainer({
|
|
810
|
+
settings: mockSettingsWithHideTitleTrue,
|
|
811
|
+
});
|
|
520
812
|
// Assert: Check that no title-related writes occurred
|
|
521
813
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
522
814
|
expect(titleWrites).toHaveLength(0);
|
|
@@ -546,7 +838,9 @@ describe('AppContainer State Management', () => {
|
|
|
546
838
|
cancelOngoingRequest: vi.fn(),
|
|
547
839
|
});
|
|
548
840
|
// Act: Render the container
|
|
549
|
-
const { unmount } =
|
|
841
|
+
const { unmount } = renderAppContainer({
|
|
842
|
+
settings: mockSettingsWithTitleEnabled,
|
|
843
|
+
});
|
|
550
844
|
// Assert: Check that title was updated with thought subject
|
|
551
845
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
552
846
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -576,7 +870,9 @@ describe('AppContainer State Management', () => {
|
|
|
576
870
|
cancelOngoingRequest: vi.fn(),
|
|
577
871
|
});
|
|
578
872
|
// Act: Render the container
|
|
579
|
-
const { unmount } =
|
|
873
|
+
const { unmount } = renderAppContainer({
|
|
874
|
+
settings: mockSettingsWithTitleEnabled,
|
|
875
|
+
});
|
|
580
876
|
// Assert: Check that title was updated with default Idle text
|
|
581
877
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
582
878
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -607,7 +903,9 @@ describe('AppContainer State Management', () => {
|
|
|
607
903
|
cancelOngoingRequest: vi.fn(),
|
|
608
904
|
});
|
|
609
905
|
// Act: Render the container
|
|
610
|
-
const { unmount } =
|
|
906
|
+
const { unmount } = renderAppContainer({
|
|
907
|
+
settings: mockSettingsWithTitleEnabled,
|
|
908
|
+
});
|
|
611
909
|
// Assert: Check that title was updated with confirmation text
|
|
612
910
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
613
911
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -638,7 +936,9 @@ describe('AppContainer State Management', () => {
|
|
|
638
936
|
cancelOngoingRequest: vi.fn(),
|
|
639
937
|
});
|
|
640
938
|
// Act: Render the container
|
|
641
|
-
const { unmount } =
|
|
939
|
+
const { unmount } = renderAppContainer({
|
|
940
|
+
settings: mockSettingsWithTitleEnabled,
|
|
941
|
+
});
|
|
642
942
|
// Assert: Check that title is padded to exactly 80 characters
|
|
643
943
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
644
944
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -674,7 +974,9 @@ describe('AppContainer State Management', () => {
|
|
|
674
974
|
cancelOngoingRequest: vi.fn(),
|
|
675
975
|
});
|
|
676
976
|
// Act: Render the container
|
|
677
|
-
const { unmount } =
|
|
977
|
+
const { unmount } = renderAppContainer({
|
|
978
|
+
settings: mockSettingsWithTitleEnabled,
|
|
979
|
+
});
|
|
678
980
|
// Assert: Check that the correct ANSI escape sequence is used
|
|
679
981
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
680
982
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -707,7 +1009,9 @@ describe('AppContainer State Management', () => {
|
|
|
707
1009
|
cancelOngoingRequest: vi.fn(),
|
|
708
1010
|
});
|
|
709
1011
|
// Act: Render the container
|
|
710
|
-
const { unmount } =
|
|
1012
|
+
const { unmount } = renderAppContainer({
|
|
1013
|
+
settings: mockSettingsWithTitleEnabled,
|
|
1014
|
+
});
|
|
711
1015
|
// Assert: Check that title was updated with CLI_TITLE value
|
|
712
1016
|
const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
|
|
713
1017
|
expect(titleWrites).toHaveLength(1);
|
|
@@ -723,7 +1027,7 @@ describe('AppContainer State Management', () => {
|
|
|
723
1027
|
vi.useRealTimers();
|
|
724
1028
|
});
|
|
725
1029
|
it('should set and clear the queue error message after a timeout', async () => {
|
|
726
|
-
const { rerender, unmount } =
|
|
1030
|
+
const { rerender, unmount } = renderAppContainer();
|
|
727
1031
|
await act(async () => {
|
|
728
1032
|
vi.advanceTimersByTime(0);
|
|
729
1033
|
});
|
|
@@ -731,24 +1035,24 @@ describe('AppContainer State Management', () => {
|
|
|
731
1035
|
act(() => {
|
|
732
1036
|
capturedUIActions.setQueueErrorMessage('Test error');
|
|
733
1037
|
});
|
|
734
|
-
rerender(
|
|
1038
|
+
rerender(getAppContainer());
|
|
735
1039
|
expect(capturedUIState.queueErrorMessage).toBe('Test error');
|
|
736
1040
|
act(() => {
|
|
737
1041
|
vi.advanceTimersByTime(3000);
|
|
738
1042
|
});
|
|
739
|
-
rerender(
|
|
1043
|
+
rerender(getAppContainer());
|
|
740
1044
|
expect(capturedUIState.queueErrorMessage).toBeNull();
|
|
741
1045
|
unmount();
|
|
742
1046
|
});
|
|
743
1047
|
it('should reset the timer if a new error message is set', async () => {
|
|
744
|
-
const { rerender, unmount } =
|
|
1048
|
+
const { rerender, unmount } = renderAppContainer();
|
|
745
1049
|
await act(async () => {
|
|
746
1050
|
vi.advanceTimersByTime(0);
|
|
747
1051
|
});
|
|
748
1052
|
act(() => {
|
|
749
1053
|
capturedUIActions.setQueueErrorMessage('First error');
|
|
750
1054
|
});
|
|
751
|
-
rerender(
|
|
1055
|
+
rerender(getAppContainer());
|
|
752
1056
|
expect(capturedUIState.queueErrorMessage).toBe('First error');
|
|
753
1057
|
act(() => {
|
|
754
1058
|
vi.advanceTimersByTime(1500);
|
|
@@ -756,18 +1060,18 @@ describe('AppContainer State Management', () => {
|
|
|
756
1060
|
act(() => {
|
|
757
1061
|
capturedUIActions.setQueueErrorMessage('Second error');
|
|
758
1062
|
});
|
|
759
|
-
rerender(
|
|
1063
|
+
rerender(getAppContainer());
|
|
760
1064
|
expect(capturedUIState.queueErrorMessage).toBe('Second error');
|
|
761
1065
|
act(() => {
|
|
762
1066
|
vi.advanceTimersByTime(2000);
|
|
763
1067
|
});
|
|
764
|
-
rerender(
|
|
1068
|
+
rerender(getAppContainer());
|
|
765
1069
|
expect(capturedUIState.queueErrorMessage).toBe('Second error');
|
|
766
1070
|
// 5. Advance time past the 3 second timeout from the second message
|
|
767
1071
|
act(() => {
|
|
768
1072
|
vi.advanceTimersByTime(1000);
|
|
769
1073
|
});
|
|
770
|
-
rerender(
|
|
1074
|
+
rerender(getAppContainer());
|
|
771
1075
|
expect(capturedUIState.queueErrorMessage).toBeNull();
|
|
772
1076
|
unmount();
|
|
773
1077
|
});
|
|
@@ -789,7 +1093,7 @@ describe('AppContainer State Management', () => {
|
|
|
789
1093
|
cancelOngoingRequest: vi.fn(),
|
|
790
1094
|
activePtyId: 'some-id',
|
|
791
1095
|
});
|
|
792
|
-
const { unmount } =
|
|
1096
|
+
const { unmount } = renderAppContainer();
|
|
793
1097
|
await act(async () => {
|
|
794
1098
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
795
1099
|
});
|
|
@@ -810,11 +1114,11 @@ describe('AppContainer State Management', () => {
|
|
|
810
1114
|
let unmount;
|
|
811
1115
|
// Helper function to reduce boilerplate in tests
|
|
812
1116
|
const setupKeypressTest = async () => {
|
|
813
|
-
const renderResult =
|
|
1117
|
+
const renderResult = renderAppContainer();
|
|
814
1118
|
await act(async () => {
|
|
815
1119
|
vi.advanceTimersByTime(0);
|
|
816
1120
|
});
|
|
817
|
-
rerender = () => renderResult.rerender(
|
|
1121
|
+
rerender = () => renderResult.rerender(getAppContainer());
|
|
818
1122
|
unmount = renderResult.unmount;
|
|
819
1123
|
};
|
|
820
1124
|
const pressKey = (key, times = 1) => {
|
|
@@ -949,11 +1253,11 @@ describe('AppContainer State Management', () => {
|
|
|
949
1253
|
},
|
|
950
1254
|
},
|
|
951
1255
|
};
|
|
952
|
-
const renderResult =
|
|
1256
|
+
const renderResult = renderAppContainer({ settings: testSettings });
|
|
953
1257
|
await act(async () => {
|
|
954
1258
|
vi.advanceTimersByTime(0);
|
|
955
1259
|
});
|
|
956
|
-
rerender = () => renderResult.rerender(
|
|
1260
|
+
rerender = () => renderResult.rerender(getAppContainer({ settings: testSettings }));
|
|
957
1261
|
unmount = renderResult.unmount;
|
|
958
1262
|
};
|
|
959
1263
|
beforeEach(() => {
|
|
@@ -1078,7 +1382,7 @@ describe('AppContainer State Management', () => {
|
|
|
1078
1382
|
openModelDialog: vi.fn(),
|
|
1079
1383
|
closeModelDialog: vi.fn(),
|
|
1080
1384
|
});
|
|
1081
|
-
const { unmount } =
|
|
1385
|
+
const { unmount } = renderAppContainer();
|
|
1082
1386
|
await act(async () => {
|
|
1083
1387
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1084
1388
|
});
|
|
@@ -1092,7 +1396,7 @@ describe('AppContainer State Management', () => {
|
|
|
1092
1396
|
openModelDialog: vi.fn(),
|
|
1093
1397
|
closeModelDialog: mockCloseModelDialog,
|
|
1094
1398
|
});
|
|
1095
|
-
const { unmount } =
|
|
1399
|
+
const { unmount } = renderAppContainer();
|
|
1096
1400
|
await act(async () => {
|
|
1097
1401
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1098
1402
|
});
|
|
@@ -1106,7 +1410,7 @@ describe('AppContainer State Management', () => {
|
|
|
1106
1410
|
});
|
|
1107
1411
|
describe('CoreEvents Integration', () => {
|
|
1108
1412
|
it('subscribes to UserFeedback and drains backlog on mount', async () => {
|
|
1109
|
-
const { unmount } =
|
|
1413
|
+
const { unmount } = renderAppContainer();
|
|
1110
1414
|
await act(async () => {
|
|
1111
1415
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1112
1416
|
});
|
|
@@ -1115,7 +1419,7 @@ describe('AppContainer State Management', () => {
|
|
|
1115
1419
|
unmount();
|
|
1116
1420
|
});
|
|
1117
1421
|
it('unsubscribes from UserFeedback on unmount', async () => {
|
|
1118
|
-
const { unmount } =
|
|
1422
|
+
const { unmount } = renderAppContainer();
|
|
1119
1423
|
await act(async () => {
|
|
1120
1424
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1121
1425
|
});
|
|
@@ -1123,7 +1427,7 @@ describe('AppContainer State Management', () => {
|
|
|
1123
1427
|
expect(mockCoreEvents.off).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
|
|
1124
1428
|
});
|
|
1125
1429
|
it('adds history item when UserFeedback event is received', async () => {
|
|
1126
|
-
const { unmount } =
|
|
1430
|
+
const { unmount } = renderAppContainer();
|
|
1127
1431
|
await act(async () => {
|
|
1128
1432
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1129
1433
|
});
|
|
@@ -1147,8 +1451,7 @@ describe('AppContainer State Management', () => {
|
|
|
1147
1451
|
it('updates currentModel when ModelChanged event is received', async () => {
|
|
1148
1452
|
// Arrange: Mock initial model
|
|
1149
1453
|
vi.spyOn(mockConfig, 'getModel').mockReturnValue('initial-model');
|
|
1150
|
-
const { unmount } =
|
|
1151
|
-
// Verify initial model
|
|
1454
|
+
const { unmount } = renderAppContainer();
|
|
1152
1455
|
await act(async () => {
|
|
1153
1456
|
await vi.waitFor(() => {
|
|
1154
1457
|
expect(capturedUIState?.currentModel).toBe('initial-model');
|
|
@@ -1183,7 +1486,7 @@ describe('AppContainer State Management', () => {
|
|
|
1183
1486
|
activePtyId: 'some-pty-id', // Make sure activePtyId is set
|
|
1184
1487
|
});
|
|
1185
1488
|
// The main assertion is that the render does not throw.
|
|
1186
|
-
const { unmount } =
|
|
1489
|
+
const { unmount } = renderAppContainer();
|
|
1187
1490
|
await act(async () => {
|
|
1188
1491
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1189
1492
|
});
|