@google/gemini-cli 0.12.0-preview.4 → 0.13.0-nightly.20251031.c89bc30d

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.
Files changed (254) hide show
  1. package/dist/google-gemini-cli-0.13.0-nightly.20251029.cca41edc.tgz +0 -0
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/extensions/install.js +2 -2
  4. package/dist/src/commands/extensions/install.js.map +1 -1
  5. package/dist/src/commands/extensions/install.test.js +27 -16
  6. package/dist/src/commands/extensions/install.test.js.map +1 -1
  7. package/dist/src/commands/extensions/link.js +2 -2
  8. package/dist/src/commands/extensions/link.js.map +1 -1
  9. package/dist/src/commands/extensions/update.js +3 -2
  10. package/dist/src/commands/extensions/update.js.map +1 -1
  11. package/dist/src/commands/extensions/validate.d.ts +12 -0
  12. package/dist/src/commands/extensions/validate.js +83 -0
  13. package/dist/src/commands/extensions/validate.js.map +1 -0
  14. package/dist/src/commands/extensions/validate.test.d.ts +6 -0
  15. package/dist/src/commands/extensions/validate.test.js +93 -0
  16. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  17. package/dist/src/commands/extensions.js +2 -0
  18. package/dist/src/commands/extensions.js.map +1 -1
  19. package/dist/src/config/auth.js +0 -5
  20. package/dist/src/config/auth.js.map +1 -1
  21. package/dist/src/config/auth.test.js +1 -3
  22. package/dist/src/config/auth.test.js.map +1 -1
  23. package/dist/src/config/config.js +2 -1
  24. package/dist/src/config/config.js.map +1 -1
  25. package/dist/src/config/config.test.js +6 -10
  26. package/dist/src/config/config.test.js.map +1 -1
  27. package/dist/src/config/extensions/update.d.ts +2 -2
  28. package/dist/src/config/extensions/update.js +28 -22
  29. package/dist/src/config/extensions/update.js.map +1 -1
  30. package/dist/src/config/sandboxConfig.d.ts +1 -1
  31. package/dist/src/config/sandboxConfig.js +6 -3
  32. package/dist/src/config/sandboxConfig.js.map +1 -1
  33. package/dist/src/config/settings.js +2 -2
  34. package/dist/src/config/settings.js.map +1 -1
  35. package/dist/src/config/settings.test.js +13 -53
  36. package/dist/src/config/settings.test.js.map +1 -1
  37. package/dist/src/config/settingsSchema.d.ts +25 -7
  38. package/dist/src/config/settingsSchema.js +24 -6
  39. package/dist/src/config/settingsSchema.js.map +1 -1
  40. package/dist/src/config/settingsSchema.test.js +2 -0
  41. package/dist/src/config/settingsSchema.test.js.map +1 -1
  42. package/dist/src/gemini.js +8 -1
  43. package/dist/src/gemini.js.map +1 -1
  44. package/dist/src/gemini.test.js +1 -0
  45. package/dist/src/gemini.test.js.map +1 -1
  46. package/dist/src/generated/git-commit.d.ts +2 -2
  47. package/dist/src/generated/git-commit.js +2 -2
  48. package/dist/src/generated/git-commit.js.map +1 -1
  49. package/dist/src/nonInteractiveCli.d.ts +9 -1
  50. package/dist/src/nonInteractiveCli.js +16 -1
  51. package/dist/src/nonInteractiveCli.js.map +1 -1
  52. package/dist/src/nonInteractiveCli.test.js +209 -103
  53. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  54. package/dist/src/test-utils/async.d.ts +9 -0
  55. package/dist/src/test-utils/async.js +29 -0
  56. package/dist/src/test-utils/async.js.map +1 -0
  57. package/dist/src/test-utils/render.d.ts +2 -1
  58. package/dist/src/test-utils/render.js +23 -1
  59. package/dist/src/test-utils/render.js.map +1 -1
  60. package/dist/src/test-utils/render.test.js +29 -4
  61. package/dist/src/test-utils/render.test.js.map +1 -1
  62. package/dist/src/ui/App.test.js +1 -1
  63. package/dist/src/ui/App.test.js.map +1 -1
  64. package/dist/src/ui/AppContainer.js +33 -4
  65. package/dist/src/ui/AppContainer.js.map +1 -1
  66. package/dist/src/ui/AppContainer.test.js +205 -99
  67. package/dist/src/ui/AppContainer.test.js.map +1 -1
  68. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  69. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  70. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  71. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  72. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  73. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  74. package/dist/src/ui/auth/AuthDialog.js +7 -3
  75. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  76. package/dist/src/ui/auth/AuthDialog.test.js +1 -1
  77. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  78. package/dist/src/ui/auth/useAuth.d.ts +2 -0
  79. package/dist/src/ui/auth/useAuth.js +31 -2
  80. package/dist/src/ui/auth/useAuth.js.map +1 -1
  81. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  82. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  83. package/dist/src/ui/components/Composer.test.js +1 -1
  84. package/dist/src/ui/components/Composer.test.js.map +1 -1
  85. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  86. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  87. package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
  88. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  89. package/dist/src/ui/components/DialogManager.js +4 -0
  90. package/dist/src/ui/components/DialogManager.js.map +1 -1
  91. package/dist/src/ui/components/FolderTrustDialog.test.js +4 -3
  92. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  93. package/dist/src/ui/components/Footer.js +3 -2
  94. package/dist/src/ui/components/Footer.js.map +1 -1
  95. package/dist/src/ui/components/Footer.test.js +59 -0
  96. package/dist/src/ui/components/Footer.test.js.map +1 -1
  97. package/dist/src/ui/components/Header.test.js +9 -5
  98. package/dist/src/ui/components/Header.test.js.map +1 -1
  99. package/dist/src/ui/components/Help.test.js +5 -3
  100. package/dist/src/ui/components/Help.test.js.map +1 -1
  101. package/dist/src/ui/components/InputPrompt.test.js +139 -111
  102. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  103. package/dist/src/ui/components/LoadingIndicator.test.js +27 -14
  104. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  105. package/dist/src/ui/components/ModelDialog.test.js +20 -10
  106. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  107. package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
  108. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
  109. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -10
  110. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  111. package/dist/src/ui/components/PrepareLabel.test.js +13 -7
  112. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  113. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  114. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  115. package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
  116. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  117. package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
  118. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
  119. package/dist/src/ui/components/SettingsDialog.test.js +438 -512
  120. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  121. package/dist/src/ui/components/StatsDisplay.test.js +1 -1
  122. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  123. package/dist/src/ui/components/ThemeDialog.test.js +3 -2
  124. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  125. package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
  126. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
  127. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  128. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  129. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  130. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  131. package/dist/src/ui/components/messages/Todo.js +27 -5
  132. package/dist/src/ui/components/messages/Todo.js.map +1 -1
  133. package/dist/src/ui/components/messages/Todo.test.js +20 -8
  134. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  135. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  136. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  137. package/dist/src/ui/components/shared/BaseSelectionList.test.js +12 -11
  138. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  139. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  140. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  141. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  142. package/dist/src/ui/components/shared/TextInput.js +38 -0
  143. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  144. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  145. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  146. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  147. package/dist/src/ui/components/shared/text-buffer.d.ts +8 -2
  148. package/dist/src/ui/components/shared/text-buffer.js +28 -13
  149. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  150. package/dist/src/ui/components/shared/text-buffer.test.js +137 -0
  151. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  152. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  153. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  154. package/dist/src/ui/components/views/ExtensionsList.js +1 -0
  155. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  156. package/dist/src/ui/components/views/ExtensionsList.test.js +13 -5
  157. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  158. package/dist/src/ui/components/views/McpStatus.test.js +23 -12
  159. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  160. package/dist/src/ui/contexts/KeypressContext.test.js +132 -252
  161. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  162. package/dist/src/ui/contexts/SessionContext.test.js +9 -5
  163. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  164. package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
  165. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  166. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  167. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  168. package/dist/src/ui/hooks/atCommandProcessor.js +29 -7
  169. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  170. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  171. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  172. package/dist/src/ui/hooks/shellCommandProcessor.test.js +47 -34
  173. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  174. package/dist/src/ui/hooks/slashCommandProcessor.test.js +141 -104
  175. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  176. package/dist/src/ui/hooks/useAtCompletion.test.js +23 -21
  177. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  178. package/dist/src/ui/hooks/useCommandCompletion.test.js +16 -15
  179. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  180. package/dist/src/ui/hooks/useConsoleMessages.test.js +1 -1
  181. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  182. package/dist/src/ui/hooks/useEditorSettings.test.js +1 -1
  183. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  184. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -1
  185. package/dist/src/ui/hooks/useExtensionUpdates.js +9 -3
  186. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  187. package/dist/src/ui/hooks/useExtensionUpdates.test.js +10 -9
  188. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  189. package/dist/src/ui/hooks/useFocus.test.js +1 -1
  190. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  191. package/dist/src/ui/hooks/useFolderTrust.test.js +7 -6
  192. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  193. package/dist/src/ui/hooks/useGeminiStream.test.js +39 -38
  194. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  195. package/dist/src/ui/hooks/useGitBranchName.test.js +5 -4
  196. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  197. package/dist/src/ui/hooks/useIdeTrustListener.test.js +25 -11
  198. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  199. package/dist/src/ui/hooks/useKeypress.test.js +1 -1
  200. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  201. package/dist/src/ui/hooks/useLoadingIndicator.test.js +1 -1
  202. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  203. package/dist/src/ui/hooks/useMemoryMonitor.test.js +1 -1
  204. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  205. package/dist/src/ui/hooks/useMessageQueue.test.js +5 -4
  206. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  207. package/dist/src/ui/hooks/useModelCommand.test.js +7 -4
  208. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  209. package/dist/src/ui/hooks/usePhraseCycler.test.js +46 -16
  210. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  211. package/dist/src/ui/hooks/usePrivacySettings.test.js +11 -7
  212. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  213. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +28 -14
  214. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  215. package/dist/src/ui/hooks/useSelectionList.test.js +116 -109
  216. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  217. package/dist/src/ui/hooks/useShellHistory.test.js +25 -17
  218. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  219. package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
  220. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  221. package/dist/src/ui/hooks/useSlashCompletion.test.js +244 -111
  222. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  223. package/dist/src/ui/hooks/useTimer.test.js +1 -1
  224. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  225. package/dist/src/ui/hooks/useToolScheduler.test.js +6 -2
  226. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  227. package/dist/src/ui/hooks/vim.test.js +6 -21
  228. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  229. package/dist/src/ui/state/extensions.d.ts +1 -0
  230. package/dist/src/ui/state/extensions.js +1 -0
  231. package/dist/src/ui/state/extensions.js.map +1 -1
  232. package/dist/src/ui/types.d.ts +1 -0
  233. package/dist/src/ui/types.js +2 -0
  234. package/dist/src/ui/types.js.map +1 -1
  235. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  236. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  237. package/dist/src/ui/utils/updateCheck.js +6 -3
  238. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  239. package/dist/src/ui/utils/updateCheck.test.js +5 -1
  240. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  241. package/dist/src/utils/commentJson.js +2 -2
  242. package/dist/src/utils/commentJson.js.map +1 -1
  243. package/dist/src/utils/commentJson.test.js +7 -6
  244. package/dist/src/utils/commentJson.test.js.map +1 -1
  245. package/dist/src/utils/version.js +6 -2
  246. package/dist/src/utils/version.js.map +1 -1
  247. package/dist/src/zed-integration/acp.js +2 -1
  248. package/dist/src/zed-integration/acp.js.map +1 -1
  249. package/dist/tsconfig.tsbuildinfo +1 -1
  250. package/package.json +3 -3
  251. package/dist/google-gemini-cli-0.12.0-preview.3.tgz +0 -0
  252. package/dist/src/utils/package.d.ts +0 -12
  253. package/dist/src/utils/package.js +0 -24
  254. package/dist/src/utils/package.js.map +0 -1
@@ -5,7 +5,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
5
5
  * SPDX-License-Identifier: Apache-2.0
6
6
  */
7
7
  import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
8
- import { render, cleanup } from 'ink-testing-library';
8
+ import { render } from '../test-utils/render.js';
9
+ import { cleanup } from 'ink-testing-library';
10
+ import { act, useContext } from 'react';
9
11
  import { AppContainer } from './AppContainer.js';
10
12
  import { makeFakeConfig, CoreEvent, } from '@google/gemini-cli-core';
11
13
  // Mock coreEvents
@@ -25,7 +27,6 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
25
27
  import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.js';
26
28
  import { UIStateContext } from './contexts/UIStateContext.js';
27
29
  import { UIActionsContext, } from './contexts/UIActionsContext.js';
28
- import { useContext } from 'react';
29
30
  // Mock useStdout to capture terminal title writes
30
31
  let mockStdout;
31
32
  vi.mock('ink', async (importOriginal) => {
@@ -277,27 +278,33 @@ describe('AppContainer State Management', () => {
277
278
  cleanup();
278
279
  });
279
280
  describe('Basic Rendering', () => {
280
- it('renders without crashing with minimal props', () => {
281
- expect(() => {
282
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
283
- }).not.toThrow();
281
+ it('renders without crashing with minimal props', async () => {
282
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
283
+ await act(async () => {
284
+ await new Promise((resolve) => setTimeout(resolve, 0));
285
+ });
286
+ unmount();
284
287
  });
285
- it('renders with startup warnings', () => {
288
+ it('renders with startup warnings', async () => {
286
289
  const startupWarnings = ['Warning 1', 'Warning 2'];
287
- expect(() => {
288
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, startupWarnings: startupWarnings, version: "1.0.0", initializationResult: mockInitResult }));
289
- }).not.toThrow();
290
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, startupWarnings: startupWarnings, version: "1.0.0", initializationResult: mockInitResult }));
291
+ await act(async () => {
292
+ await new Promise((resolve) => setTimeout(resolve, 0));
293
+ });
294
+ unmount();
290
295
  });
291
296
  });
292
297
  describe('State Initialization', () => {
293
- it('initializes with theme error from initialization result', () => {
298
+ it('initializes with theme error from initialization result', async () => {
294
299
  const initResultWithError = {
295
300
  ...mockInitResult,
296
301
  themeError: 'Failed to load theme',
297
302
  };
298
- expect(() => {
299
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: initResultWithError }));
300
- }).not.toThrow();
303
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: initResultWithError }));
304
+ await act(async () => {
305
+ await new Promise((resolve) => setTimeout(resolve, 0));
306
+ });
307
+ unmount();
301
308
  });
302
309
  it('handles debug mode state', () => {
303
310
  const debugConfig = makeFakeConfig();
@@ -308,29 +315,38 @@ describe('AppContainer State Management', () => {
308
315
  });
309
316
  });
310
317
  describe('Context Providers', () => {
311
- it('provides AppContext with correct values', () => {
318
+ it('provides AppContext with correct values', async () => {
312
319
  const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "2.0.0", initializationResult: mockInitResult }));
320
+ await act(async () => {
321
+ await new Promise((resolve) => setTimeout(resolve, 0));
322
+ });
313
323
  // Should render and unmount cleanly
314
324
  expect(() => unmount()).not.toThrow();
315
325
  });
316
- it('provides UIStateContext with state management', () => {
317
- expect(() => {
318
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
319
- }).not.toThrow();
326
+ it('provides UIStateContext with state management', async () => {
327
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
328
+ await act(async () => {
329
+ await new Promise((resolve) => setTimeout(resolve, 0));
330
+ });
331
+ unmount();
320
332
  });
321
- it('provides UIActionsContext with action handlers', () => {
322
- expect(() => {
323
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
324
- }).not.toThrow();
333
+ it('provides UIActionsContext with action handlers', async () => {
334
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
335
+ await act(async () => {
336
+ await new Promise((resolve) => setTimeout(resolve, 0));
337
+ });
338
+ unmount();
325
339
  });
326
- it('provides ConfigContext with config object', () => {
327
- expect(() => {
328
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
329
- }).not.toThrow();
340
+ it('provides ConfigContext with config object', async () => {
341
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
342
+ await act(async () => {
343
+ await new Promise((resolve) => setTimeout(resolve, 0));
344
+ });
345
+ unmount();
330
346
  });
331
347
  });
332
348
  describe('Settings Integration', () => {
333
- it('handles settings with all display options disabled', () => {
349
+ it('handles settings with all display options disabled', async () => {
334
350
  const settingsAllHidden = {
335
351
  merged: {
336
352
  hideBanner: true,
@@ -339,11 +355,13 @@ describe('AppContainer State Management', () => {
339
355
  showMemoryUsage: false,
340
356
  },
341
357
  };
342
- expect(() => {
343
- render(_jsx(AppContainer, { config: mockConfig, settings: settingsAllHidden, version: "1.0.0", initializationResult: mockInitResult }));
344
- }).not.toThrow();
358
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: settingsAllHidden, version: "1.0.0", initializationResult: mockInitResult }));
359
+ await act(async () => {
360
+ await new Promise((resolve) => setTimeout(resolve, 0));
361
+ });
362
+ unmount();
345
363
  });
346
- it('handles settings with memory usage enabled', () => {
364
+ it('handles settings with memory usage enabled', async () => {
347
365
  const settingsWithMemory = {
348
366
  merged: {
349
367
  hideBanner: false,
@@ -352,36 +370,44 @@ describe('AppContainer State Management', () => {
352
370
  showMemoryUsage: true,
353
371
  },
354
372
  };
355
- expect(() => {
356
- render(_jsx(AppContainer, { config: mockConfig, settings: settingsWithMemory, version: "1.0.0", initializationResult: mockInitResult }));
357
- }).not.toThrow();
373
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: settingsWithMemory, version: "1.0.0", initializationResult: mockInitResult }));
374
+ await act(async () => {
375
+ await new Promise((resolve) => setTimeout(resolve, 0));
376
+ });
377
+ unmount();
358
378
  });
359
379
  });
360
380
  describe('Version Handling', () => {
361
- it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', (version) => {
362
- expect(() => {
363
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: version, initializationResult: mockInitResult }));
364
- }).not.toThrow();
381
+ it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', async (version) => {
382
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: version, initializationResult: mockInitResult }));
383
+ await act(async () => {
384
+ await new Promise((resolve) => setTimeout(resolve, 0));
385
+ });
386
+ unmount();
365
387
  });
366
388
  });
367
389
  describe('Error Handling', () => {
368
- it('handles config methods that might throw', () => {
390
+ it('handles config methods that might throw', async () => {
369
391
  const errorConfig = makeFakeConfig();
370
392
  vi.spyOn(errorConfig, 'getModel').mockImplementation(() => {
371
393
  throw new Error('Config error');
372
394
  });
373
395
  // Should still render without crashing - errors should be handled internally
374
- expect(() => {
375
- render(_jsx(AppContainer, { config: errorConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
376
- }).not.toThrow();
396
+ const { unmount } = render(_jsx(AppContainer, { config: errorConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
397
+ await act(async () => {
398
+ await new Promise((resolve) => setTimeout(resolve, 0));
399
+ });
400
+ unmount();
377
401
  });
378
- it('handles undefined settings gracefully', () => {
402
+ it('handles undefined settings gracefully', async () => {
379
403
  const undefinedSettings = {
380
404
  merged: {},
381
405
  };
382
- expect(() => {
383
- render(_jsx(AppContainer, { config: mockConfig, settings: undefinedSettings, version: "1.0.0", initializationResult: mockInitResult }));
384
- }).not.toThrow();
406
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: undefinedSettings, version: "1.0.0", initializationResult: mockInitResult }));
407
+ await act(async () => {
408
+ await new Promise((resolve) => setTimeout(resolve, 0));
409
+ });
410
+ unmount();
385
411
  });
386
412
  });
387
413
  describe('Provider Hierarchy', () => {
@@ -393,13 +419,17 @@ describe('AppContainer State Management', () => {
393
419
  });
394
420
  });
395
421
  describe('Quota and Fallback Integration', () => {
396
- it('passes a null proQuotaRequest to UIStateContext by default', () => {
422
+ it('passes a null proQuotaRequest to UIStateContext by default', async () => {
397
423
  // The default mock from beforeEach already sets proQuotaRequest to null
398
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
424
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
425
+ await act(async () => {
426
+ await new Promise((resolve) => setTimeout(resolve, 0));
427
+ });
399
428
  // Assert that the context value is as expected
400
429
  expect(capturedUIState.proQuotaRequest).toBeNull();
430
+ unmount();
401
431
  });
402
- it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', () => {
432
+ it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', async () => {
403
433
  // Arrange: Create a mock request object that a UI dialog would receive
404
434
  const mockRequest = {
405
435
  failedModel: 'gemini-pro',
@@ -411,11 +441,15 @@ describe('AppContainer State Management', () => {
411
441
  handleProQuotaChoice: vi.fn(),
412
442
  });
413
443
  // Act: Render the container
414
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
444
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
445
+ await act(async () => {
446
+ await new Promise((resolve) => setTimeout(resolve, 0));
447
+ });
415
448
  // Assert: The mock request is correctly passed through the context
416
449
  expect(capturedUIState.proQuotaRequest).toEqual(mockRequest);
450
+ unmount();
417
451
  });
418
- it('passes the handleProQuotaChoice function to UIActionsContext', () => {
452
+ it('passes the handleProQuotaChoice function to UIActionsContext', async () => {
419
453
  // Arrange: Create a mock handler function
420
454
  const mockHandler = vi.fn();
421
455
  mockedUseQuotaAndFallback.mockReturnValue({
@@ -423,12 +457,18 @@ describe('AppContainer State Management', () => {
423
457
  handleProQuotaChoice: mockHandler,
424
458
  });
425
459
  // Act: Render the container
426
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
460
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
461
+ await act(async () => {
462
+ await new Promise((resolve) => setTimeout(resolve, 0));
463
+ });
427
464
  // Assert: The action in the context is the mock handler we provided
428
465
  expect(capturedUIActions.handleProQuotaChoice).toBe(mockHandler);
429
466
  // You can even verify that the plumbed function is callable
430
- capturedUIActions.handleProQuotaChoice('auth');
467
+ act(() => {
468
+ capturedUIActions.handleProQuotaChoice('auth');
469
+ });
431
470
  expect(mockHandler).toHaveBeenCalledWith('auth');
471
+ unmount();
432
472
  });
433
473
  });
434
474
  describe('Terminal Title Update Feature', () => {
@@ -677,37 +717,59 @@ describe('AppContainer State Management', () => {
677
717
  vi.useRealTimers();
678
718
  });
679
719
  it('should set and clear the queue error message after a timeout', async () => {
680
- const { rerender } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
720
+ const { rerender, unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
721
+ await act(async () => {
722
+ vi.advanceTimersByTime(0);
723
+ });
681
724
  expect(capturedUIState.queueErrorMessage).toBeNull();
682
- capturedUIActions.setQueueErrorMessage('Test error');
725
+ act(() => {
726
+ capturedUIActions.setQueueErrorMessage('Test error');
727
+ });
683
728
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
684
729
  expect(capturedUIState.queueErrorMessage).toBe('Test error');
685
- vi.advanceTimersByTime(3000);
730
+ act(() => {
731
+ vi.advanceTimersByTime(3000);
732
+ });
686
733
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
687
734
  expect(capturedUIState.queueErrorMessage).toBeNull();
735
+ unmount();
688
736
  });
689
737
  it('should reset the timer if a new error message is set', async () => {
690
- const { rerender } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
691
- capturedUIActions.setQueueErrorMessage('First error');
738
+ const { rerender, unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
739
+ await act(async () => {
740
+ vi.advanceTimersByTime(0);
741
+ });
742
+ act(() => {
743
+ capturedUIActions.setQueueErrorMessage('First error');
744
+ });
692
745
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
693
746
  expect(capturedUIState.queueErrorMessage).toBe('First error');
694
- vi.advanceTimersByTime(1500);
695
- capturedUIActions.setQueueErrorMessage('Second error');
747
+ act(() => {
748
+ vi.advanceTimersByTime(1500);
749
+ });
750
+ act(() => {
751
+ capturedUIActions.setQueueErrorMessage('Second error');
752
+ });
696
753
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
697
754
  expect(capturedUIState.queueErrorMessage).toBe('Second error');
698
- vi.advanceTimersByTime(2000);
755
+ act(() => {
756
+ vi.advanceTimersByTime(2000);
757
+ });
699
758
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
700
759
  expect(capturedUIState.queueErrorMessage).toBe('Second error');
701
760
  // 5. Advance time past the 3 second timeout from the second message
702
- vi.advanceTimersByTime(1000);
761
+ act(() => {
762
+ vi.advanceTimersByTime(1000);
763
+ });
703
764
  rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
704
765
  expect(capturedUIState.queueErrorMessage).toBeNull();
766
+ unmount();
705
767
  });
706
768
  });
707
769
  describe('Terminal Height Calculation', () => {
708
770
  const mockedMeasureElement = measureElement;
709
771
  const mockedUseTerminalSize = useTerminalSize;
710
- it('should prevent terminal height from being less than 1', () => {
772
+ it('should prevent terminal height from being less than 1', async () => {
711
773
  const resizePtySpy = vi.spyOn(ShellExecutionService, 'resizePty');
712
774
  // Arrange: Simulate a small terminal and a large footer
713
775
  mockedUseTerminalSize.mockReturnValue({ columns: 80, rows: 5 });
@@ -721,13 +783,17 @@ describe('AppContainer State Management', () => {
721
783
  cancelOngoingRequest: vi.fn(),
722
784
  activePtyId: 'some-id',
723
785
  });
724
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
786
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
787
+ await act(async () => {
788
+ await new Promise((resolve) => setTimeout(resolve, 0));
789
+ });
725
790
  // Assert: The shell should be resized to a minimum height of 1, not a negative number.
726
791
  // The old code would have tried to set a negative height.
727
792
  expect(resizePtySpy).toHaveBeenCalled();
728
793
  const lastCall = resizePtySpy.mock.calls[resizePtySpy.mock.calls.length - 1];
729
794
  // Check the height argument specifically
730
795
  expect(lastCall[2]).toBe(1);
796
+ unmount();
731
797
  });
732
798
  });
733
799
  describe('Keyboard Input Handling (CTRL+C / CTRL+D)', () => {
@@ -735,19 +801,26 @@ describe('AppContainer State Management', () => {
735
801
  let mockHandleSlashCommand;
736
802
  let mockCancelOngoingRequest;
737
803
  let rerender;
804
+ let unmount;
738
805
  // Helper function to reduce boilerplate in tests
739
- const setupKeypressTest = () => {
740
- const { rerender: inkRerender } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
741
- rerender = () => inkRerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
806
+ const setupKeypressTest = async () => {
807
+ const renderResult = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
808
+ await act(async () => {
809
+ vi.advanceTimersByTime(0);
810
+ });
811
+ rerender = () => renderResult.rerender(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
812
+ unmount = renderResult.unmount;
742
813
  };
743
814
  const pressKey = (key, times = 1) => {
744
815
  for (let i = 0; i < times; i++) {
745
- handleGlobalKeypress({
746
- name: 'c',
747
- ctrl: false,
748
- meta: false,
749
- shift: false,
750
- ...key,
816
+ act(() => {
817
+ handleGlobalKeypress({
818
+ name: 'c',
819
+ ctrl: false,
820
+ meta: false,
821
+ shift: false,
822
+ ...key,
823
+ });
751
824
  });
752
825
  rerender();
753
826
  }
@@ -788,7 +861,7 @@ describe('AppContainer State Management', () => {
788
861
  vi.useRealTimers();
789
862
  });
790
863
  describe('CTRL+C', () => {
791
- it('should cancel ongoing request on first press', () => {
864
+ it('should cancel ongoing request on first press', async () => {
792
865
  mockedUseGeminiStream.mockReturnValue({
793
866
  streamingState: 'responding',
794
867
  submitQuery: vi.fn(),
@@ -797,89 +870,119 @@ describe('AppContainer State Management', () => {
797
870
  thought: null,
798
871
  cancelOngoingRequest: mockCancelOngoingRequest,
799
872
  });
800
- setupKeypressTest();
873
+ await setupKeypressTest();
801
874
  pressKey({ name: 'c', ctrl: true });
802
875
  expect(mockCancelOngoingRequest).toHaveBeenCalledTimes(1);
803
876
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
877
+ unmount();
804
878
  });
805
- it('should quit on second press', () => {
806
- setupKeypressTest();
879
+ it('should quit on second press', async () => {
880
+ await setupKeypressTest();
807
881
  pressKey({ name: 'c', ctrl: true }, 2);
808
882
  expect(mockCancelOngoingRequest).toHaveBeenCalledTimes(2);
809
883
  expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
884
+ unmount();
810
885
  });
811
- it('should reset press count after a timeout', () => {
812
- setupKeypressTest();
886
+ it('should reset press count after a timeout', async () => {
887
+ await setupKeypressTest();
813
888
  pressKey({ name: 'c', ctrl: true });
814
889
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
815
890
  // Advance timer past the reset threshold
816
- vi.advanceTimersByTime(1001);
891
+ act(() => {
892
+ vi.advanceTimersByTime(1001);
893
+ });
817
894
  pressKey({ name: 'c', ctrl: true });
818
895
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
896
+ unmount();
819
897
  });
820
898
  });
821
899
  describe('CTRL+D', () => {
822
- it('should do nothing if text buffer is not empty', () => {
900
+ it('should do nothing if text buffer is not empty', async () => {
823
901
  mockedUseTextBuffer.mockReturnValue({
824
902
  text: 'some text',
825
903
  setText: vi.fn(),
826
904
  });
827
- setupKeypressTest();
905
+ await setupKeypressTest();
828
906
  pressKey({ name: 'd', ctrl: true }, 2);
829
907
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
908
+ unmount();
830
909
  });
831
- it('should quit on second press if buffer is empty', () => {
832
- setupKeypressTest();
910
+ it('should quit on second press if buffer is empty', async () => {
911
+ await setupKeypressTest();
833
912
  pressKey({ name: 'd', ctrl: true }, 2);
834
913
  expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
914
+ unmount();
835
915
  });
836
- it('should reset press count after a timeout', () => {
837
- setupKeypressTest();
916
+ it('should reset press count after a timeout', async () => {
917
+ await setupKeypressTest();
838
918
  pressKey({ name: 'd', ctrl: true });
839
919
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
840
920
  // Advance timer past the reset threshold
841
- vi.advanceTimersByTime(1001);
921
+ act(() => {
922
+ vi.advanceTimersByTime(1001);
923
+ });
842
924
  pressKey({ name: 'd', ctrl: true });
843
925
  expect(mockHandleSlashCommand).not.toHaveBeenCalled();
926
+ unmount();
844
927
  });
845
928
  });
846
929
  });
847
930
  describe('Model Dialog Integration', () => {
848
- it('should provide isModelDialogOpen in the UIStateContext', () => {
931
+ it('should provide isModelDialogOpen in the UIStateContext', async () => {
849
932
  mockedUseModelCommand.mockReturnValue({
850
933
  isModelDialogOpen: true,
851
934
  openModelDialog: vi.fn(),
852
935
  closeModelDialog: vi.fn(),
853
936
  });
854
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
937
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
938
+ await act(async () => {
939
+ await new Promise((resolve) => setTimeout(resolve, 0));
940
+ });
855
941
  expect(capturedUIState.isModelDialogOpen).toBe(true);
942
+ unmount();
856
943
  });
857
- it('should provide model dialog actions in the UIActionsContext', () => {
944
+ it('should provide model dialog actions in the UIActionsContext', async () => {
858
945
  const mockCloseModelDialog = vi.fn();
859
946
  mockedUseModelCommand.mockReturnValue({
860
947
  isModelDialogOpen: false,
861
948
  openModelDialog: vi.fn(),
862
949
  closeModelDialog: mockCloseModelDialog,
863
950
  });
864
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
951
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
952
+ await act(async () => {
953
+ await new Promise((resolve) => setTimeout(resolve, 0));
954
+ });
865
955
  // Verify that the actions are correctly passed through context
866
- capturedUIActions.closeModelDialog();
956
+ act(() => {
957
+ capturedUIActions.closeModelDialog();
958
+ });
867
959
  expect(mockCloseModelDialog).toHaveBeenCalled();
960
+ unmount();
868
961
  });
869
962
  });
870
963
  describe('CoreEvents Integration', () => {
871
- it('subscribes to UserFeedback and drains backlog on mount', () => {
872
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
964
+ it('subscribes to UserFeedback and drains backlog on mount', async () => {
965
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
966
+ await act(async () => {
967
+ await new Promise((resolve) => setTimeout(resolve, 0));
968
+ });
873
969
  expect(mockCoreEvents.on).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
874
970
  expect(mockCoreEvents.drainFeedbackBacklog).toHaveBeenCalledTimes(1);
971
+ unmount();
875
972
  });
876
- it('unsubscribes from UserFeedback on unmount', () => {
973
+ it('unsubscribes from UserFeedback on unmount', async () => {
877
974
  const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
975
+ await act(async () => {
976
+ await new Promise((resolve) => setTimeout(resolve, 0));
977
+ });
878
978
  unmount();
879
979
  expect(mockCoreEvents.off).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
880
980
  });
881
- it('adds history item when UserFeedback event is received', () => {
882
- render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
981
+ it('adds history item when UserFeedback event is received', async () => {
982
+ const { unmount } = render(_jsx(AppContainer, { config: mockConfig, settings: mockSettings, version: "1.0.0", initializationResult: mockInitResult }));
983
+ await act(async () => {
984
+ await new Promise((resolve) => setTimeout(resolve, 0));
985
+ });
883
986
  // Get the registered handler
884
987
  const handler = mockCoreEvents.on.mock.calls.find((call) => call[0] === CoreEvent.UserFeedback)?.[1];
885
988
  expect(handler).toBeDefined();
@@ -888,11 +991,14 @@ describe('AppContainer State Management', () => {
888
991
  severity: 'error',
889
992
  message: 'Test error message',
890
993
  };
891
- handler(payload);
994
+ act(() => {
995
+ handler(payload);
996
+ });
892
997
  expect(mockedUseHistory().addItem).toHaveBeenCalledWith(expect.objectContaining({
893
998
  type: 'error',
894
999
  text: 'Test error message',
895
1000
  }), expect.any(Number));
1001
+ unmount();
896
1002
  });
897
1003
  });
898
1004
  });