@google/gemini-cli 0.18.0-nightly.20251118.7cc5234b9 → 0.18.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.
Files changed (240) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -0
  3. package/dist/package.json +4 -4
  4. package/dist/src/commands/extensions/disable.test.js +19 -13
  5. package/dist/src/commands/extensions/disable.test.js.map +1 -1
  6. package/dist/src/commands/extensions/enable.test.js +16 -9
  7. package/dist/src/commands/extensions/enable.test.js.map +1 -1
  8. package/dist/src/commands/extensions/link.test.js +18 -11
  9. package/dist/src/commands/extensions/link.test.js.map +1 -1
  10. package/dist/src/commands/extensions/list.test.js +20 -13
  11. package/dist/src/commands/extensions/list.test.js.map +1 -1
  12. package/dist/src/commands/extensions/uninstall.test.js +26 -18
  13. package/dist/src/commands/extensions/uninstall.test.js.map +1 -1
  14. package/dist/src/commands/extensions/update.test.js +20 -13
  15. package/dist/src/commands/extensions/update.test.js.map +1 -1
  16. package/dist/src/commands/mcp/add.test.js +8 -3
  17. package/dist/src/commands/mcp/add.test.js.map +1 -1
  18. package/dist/src/commands/mcp/list.test.js +1 -6
  19. package/dist/src/commands/mcp/list.test.js.map +1 -1
  20. package/dist/src/commands/mcp/remove.test.js +23 -12
  21. package/dist/src/commands/mcp/remove.test.js.map +1 -1
  22. package/dist/src/config/config.d.ts +2 -1
  23. package/dist/src/config/config.js +38 -14
  24. package/dist/src/config/config.js.map +1 -1
  25. package/dist/src/config/config.test.js +64 -10
  26. package/dist/src/config/config.test.js.map +1 -1
  27. package/dist/src/config/extension.test.js +131 -125
  28. package/dist/src/config/extension.test.js.map +1 -1
  29. package/dist/src/config/settingsSchema.d.ts +2 -2
  30. package/dist/src/config/settingsSchema.js +3 -3
  31. package/dist/src/config/settingsSchema.js.map +1 -1
  32. package/dist/src/config/settingsSchema.test.js +1 -1
  33. package/dist/src/config/settingsSchema.test.js.map +1 -1
  34. package/dist/src/gemini.js +65 -7
  35. package/dist/src/gemini.js.map +1 -1
  36. package/dist/src/gemini.test.js +55 -15
  37. package/dist/src/gemini.test.js.map +1 -1
  38. package/dist/src/generated/git-commit.d.ts +2 -2
  39. package/dist/src/generated/git-commit.js +2 -2
  40. package/dist/src/generated/git-commit.js.map +1 -1
  41. package/dist/src/nonInteractiveCli.js +4 -1
  42. package/dist/src/nonInteractiveCli.js.map +1 -1
  43. package/dist/src/nonInteractiveCli.test.js +2 -2
  44. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  45. package/dist/src/services/CommandService.test.js +3 -2
  46. package/dist/src/services/CommandService.test.js.map +1 -1
  47. package/dist/src/services/McpPromptLoader.js +5 -3
  48. package/dist/src/services/McpPromptLoader.js.map +1 -1
  49. package/dist/src/services/McpPromptLoader.test.js +29 -1
  50. package/dist/src/services/McpPromptLoader.test.js.map +1 -1
  51. package/dist/src/test-utils/render.d.ts +26 -2
  52. package/dist/src/test-utils/render.js +76 -3
  53. package/dist/src/test-utils/render.js.map +1 -1
  54. package/dist/src/ui/AppContainer.js +57 -32
  55. package/dist/src/ui/AppContainer.js.map +1 -1
  56. package/dist/src/ui/AppContainer.test.js +169 -102
  57. package/dist/src/ui/AppContainer.test.js.map +1 -1
  58. package/dist/src/ui/auth/AuthDialog.test.js +2 -2
  59. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  60. package/dist/src/ui/commands/aboutCommand.js +8 -1
  61. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  62. package/dist/src/ui/commands/aboutCommand.test.js +4 -0
  63. package/dist/src/ui/commands/aboutCommand.test.js.map +1 -1
  64. package/dist/src/ui/commands/clearCommand.js +12 -0
  65. package/dist/src/ui/commands/clearCommand.js.map +1 -1
  66. package/dist/src/ui/commands/clearCommand.test.js +5 -0
  67. package/dist/src/ui/commands/clearCommand.test.js.map +1 -1
  68. package/dist/src/ui/commands/memoryCommand.js +1 -0
  69. package/dist/src/ui/commands/memoryCommand.js.map +1 -1
  70. package/dist/src/ui/commands/memoryCommand.test.js +3 -0
  71. package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
  72. package/dist/src/ui/commands/setupGithubCommand.d.ts +1 -0
  73. package/dist/src/ui/commands/setupGithubCommand.js +82 -45
  74. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  75. package/dist/src/ui/commands/setupGithubCommand.test.js +35 -5
  76. package/dist/src/ui/commands/setupGithubCommand.test.js.map +1 -1
  77. package/dist/src/ui/components/AboutBox.d.ts +1 -0
  78. package/dist/src/ui/components/AboutBox.js +1 -1
  79. package/dist/src/ui/components/AboutBox.js.map +1 -1
  80. package/dist/src/ui/components/AppHeader.js +3 -8
  81. package/dist/src/ui/components/AppHeader.js.map +1 -1
  82. package/dist/src/ui/components/Banner.d.ts +4 -2
  83. package/dist/src/ui/components/Banner.js +18 -4
  84. package/dist/src/ui/components/Banner.js.map +1 -1
  85. package/dist/src/ui/components/DebugProfiler.d.ts +1 -0
  86. package/dist/src/ui/components/DebugProfiler.js +23 -34
  87. package/dist/src/ui/components/DebugProfiler.js.map +1 -1
  88. package/dist/src/ui/components/DebugProfiler.test.js +1 -0
  89. package/dist/src/ui/components/DebugProfiler.test.js.map +1 -1
  90. package/dist/src/ui/components/DialogManager.js +1 -1
  91. package/dist/src/ui/components/DialogManager.js.map +1 -1
  92. package/dist/src/ui/components/GradientRegression.test.js +22 -1
  93. package/dist/src/ui/components/GradientRegression.test.js.map +1 -1
  94. package/dist/src/ui/components/Header.test.js +27 -2
  95. package/dist/src/ui/components/Header.test.js.map +1 -1
  96. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  97. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  98. package/dist/src/ui/components/InputPrompt.js +16 -24
  99. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  100. package/dist/src/ui/components/InputPrompt.test.js +84 -24
  101. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  102. package/dist/src/ui/components/ModelDialog.js +2 -2
  103. package/dist/src/ui/components/ModelDialog.js.map +1 -1
  104. package/dist/src/ui/components/SettingsDialog.d.ts +3 -1
  105. package/dist/src/ui/components/SettingsDialog.js +4 -1
  106. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  107. package/dist/src/ui/components/ThemedGradient.js +2 -1
  108. package/dist/src/ui/components/ThemedGradient.js.map +1 -1
  109. package/dist/src/ui/components/messages/ShellToolMessage.d.ts +14 -0
  110. package/dist/src/ui/components/messages/ShellToolMessage.js +76 -0
  111. package/dist/src/ui/components/messages/ShellToolMessage.js.map +1 -0
  112. package/dist/src/ui/components/messages/ShellToolMessage.test.d.ts +6 -0
  113. package/dist/src/ui/components/messages/ShellToolMessage.test.js +123 -0
  114. package/dist/src/ui/components/messages/ShellToolMessage.test.js.map +1 -0
  115. package/dist/src/ui/components/messages/ToolGroupMessage.js +19 -1
  116. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  117. package/dist/src/ui/components/messages/ToolMessage.d.ts +3 -6
  118. package/dist/src/ui/components/messages/ToolMessage.js +5 -121
  119. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
  120. package/dist/src/ui/components/messages/ToolMessage.test.js +13 -5
  121. package/dist/src/ui/components/messages/ToolMessage.test.js.map +1 -1
  122. package/dist/src/ui/components/messages/ToolResultDisplay.d.ts +13 -0
  123. package/dist/src/ui/components/messages/ToolResultDisplay.js +54 -0
  124. package/dist/src/ui/components/messages/ToolResultDisplay.js.map +1 -0
  125. package/dist/src/ui/components/messages/ToolShared.d.ts +23 -0
  126. package/dist/src/ui/components/messages/ToolShared.js +40 -0
  127. package/dist/src/ui/components/messages/ToolShared.js.map +1 -0
  128. package/dist/src/ui/components/shared/text-buffer.js +4 -1
  129. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  130. package/dist/src/ui/contexts/KeypressContext.js +21 -11
  131. package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
  132. package/dist/src/ui/contexts/KeypressContext.test.js +29 -10
  133. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  134. package/dist/src/ui/contexts/UIActionsContext.d.ts +1 -0
  135. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  136. package/dist/src/ui/hooks/shellCommandProcessor.js +8 -4
  137. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  138. package/dist/src/ui/hooks/shellCommandProcessor.test.js +4 -3
  139. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  140. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -1
  141. package/dist/src/ui/hooks/slashCommandProcessor.js +5 -3
  142. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  143. package/dist/src/ui/hooks/useBracketedPaste.js +3 -2
  144. package/dist/src/ui/hooks/useBracketedPaste.js.map +1 -1
  145. package/dist/src/ui/hooks/useCommandCompletion.test.js +5 -5
  146. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  147. package/dist/src/ui/hooks/useConsoleMessages.d.ts +0 -1
  148. package/dist/src/ui/hooks/useConsoleMessages.js +26 -1
  149. package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
  150. package/dist/src/ui/hooks/useConsoleMessages.test.js +37 -5
  151. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  152. package/dist/src/ui/hooks/useEditorSettings.d.ts +2 -2
  153. package/dist/src/ui/hooks/useEditorSettings.js.map +1 -1
  154. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  155. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
  156. package/dist/src/ui/hooks/useGeminiStream.js +48 -10
  157. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  158. package/dist/src/ui/hooks/useGeminiStream.test.js +20 -21
  159. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  160. package/dist/src/ui/hooks/useHistoryManager.d.ts +5 -2
  161. package/dist/src/ui/hooks/useHistoryManager.js +39 -3
  162. package/dist/src/ui/hooks/useHistoryManager.js.map +1 -1
  163. package/dist/src/ui/hooks/useIncludeDirsTrust.js +0 -1
  164. package/dist/src/ui/hooks/useIncludeDirsTrust.js.map +1 -1
  165. package/dist/src/ui/hooks/useInputHistoryStore.test.js +4 -1
  166. package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
  167. package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +0 -1
  168. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +1 -2
  169. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +1 -1
  170. package/dist/src/ui/hooks/useMouseClick.d.ts +12 -0
  171. package/dist/src/ui/hooks/useMouseClick.js +28 -0
  172. package/dist/src/ui/hooks/useMouseClick.js.map +1 -0
  173. package/dist/src/ui/hooks/useMouseClick.test.d.ts +6 -0
  174. package/dist/src/ui/hooks/useMouseClick.test.js +59 -0
  175. package/dist/src/ui/hooks/useMouseClick.test.js.map +1 -0
  176. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +1 -1
  177. package/dist/src/ui/hooks/useReactToolScheduler.js +1 -8
  178. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  179. package/dist/src/ui/hooks/useReactToolScheduler.test.js +1 -8
  180. package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -1
  181. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +18 -12
  182. package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
  183. package/dist/src/ui/hooks/useSessionBrowser.js +13 -4
  184. package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -1
  185. package/dist/src/ui/hooks/useSessionBrowser.test.js +37 -0
  186. package/dist/src/ui/hooks/useSessionBrowser.test.js.map +1 -1
  187. package/dist/src/ui/hooks/useSessionResume.js +1 -1
  188. package/dist/src/ui/hooks/useSessionResume.js.map +1 -1
  189. package/dist/src/ui/hooks/useSessionResume.test.js +4 -4
  190. package/dist/src/ui/hooks/useSessionResume.test.js.map +1 -1
  191. package/dist/src/ui/hooks/useThemeCommand.d.ts +2 -2
  192. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -1
  193. package/dist/src/ui/hooks/useToolScheduler.test.js +2 -2
  194. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  195. package/dist/src/ui/themes/theme-manager.test.js +2 -1
  196. package/dist/src/ui/themes/theme-manager.test.js.map +1 -1
  197. package/dist/src/ui/types.d.ts +2 -0
  198. package/dist/src/ui/types.js.map +1 -1
  199. package/dist/src/ui/utils/ConsolePatcher.js +6 -9
  200. package/dist/src/ui/utils/ConsolePatcher.js.map +1 -1
  201. package/dist/src/ui/utils/kittyProtocolDetector.d.ts +6 -2
  202. package/dist/src/ui/utils/kittyProtocolDetector.js +48 -43
  203. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
  204. package/dist/src/ui/utils/mouse.js +3 -3
  205. package/dist/src/ui/utils/mouse.js.map +1 -1
  206. package/dist/src/utils/cleanup.d.ts +2 -0
  207. package/dist/src/utils/cleanup.js +16 -0
  208. package/dist/src/utils/cleanup.js.map +1 -1
  209. package/dist/src/utils/errors.js +10 -0
  210. package/dist/src/utils/errors.js.map +1 -1
  211. package/dist/src/utils/events.d.ts +0 -2
  212. package/dist/src/utils/events.js +0 -1
  213. package/dist/src/utils/events.js.map +1 -1
  214. package/dist/src/utils/installationInfo.test.js +8 -9
  215. package/dist/src/utils/installationInfo.test.js.map +1 -1
  216. package/dist/src/utils/sessionCleanup.test.js +4 -2
  217. package/dist/src/utils/sessionCleanup.test.js.map +1 -1
  218. package/dist/src/utils/sessionUtils.d.ts +5 -0
  219. package/dist/src/utils/sessionUtils.js +6 -1
  220. package/dist/src/utils/sessionUtils.js.map +1 -1
  221. package/dist/src/utils/sessions.test.d.ts +6 -0
  222. package/dist/src/utils/sessions.test.js +516 -0
  223. package/dist/src/utils/sessions.test.js.map +1 -0
  224. package/dist/src/utils/stdio.d.ts +32 -0
  225. package/dist/src/utils/stdio.js +85 -0
  226. package/dist/src/utils/stdio.js.map +1 -0
  227. package/dist/src/utils/stdio.test.d.ts +6 -0
  228. package/dist/src/utils/stdio.test.js +47 -0
  229. package/dist/src/utils/stdio.test.js.map +1 -0
  230. package/dist/src/validateNonInterActiveAuth.js +2 -0
  231. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  232. package/dist/src/validateNonInterActiveAuth.test.js +10 -6
  233. package/dist/src/validateNonInterActiveAuth.test.js.map +1 -1
  234. package/dist/src/zed-integration/schema.d.ts +30 -30
  235. package/dist/src/zed-integration/zedIntegration.d.ts +0 -7
  236. package/dist/src/zed-integration/zedIntegration.js +9 -21
  237. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  238. package/dist/tsconfig.tsbuildinfo +1 -1
  239. package/package.json +5 -5
  240. package/dist/google-gemini-cli-0.18.0-nightly.20251118.86828bb56.tgz +0 -0
@@ -6,6 +6,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
6
6
  */
7
7
  import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
8
8
  import { render } from '../test-utils/render.js';
9
+ import { waitFor } from '../test-utils/async.js';
9
10
  import { cleanup } from 'ink-testing-library';
10
11
  import { act, useContext } from 'react';
11
12
  import { AppContainer } from './AppContainer.js';
@@ -15,26 +16,34 @@ import { makeFakeConfig, CoreEvent, AuthType, } from '@google/gemini-cli-core';
15
16
  const mockCoreEvents = vi.hoisted(() => ({
16
17
  on: vi.fn(),
17
18
  off: vi.fn(),
18
- drainFeedbackBacklog: vi.fn(),
19
+ drainBacklogs: vi.fn(),
19
20
  emit: vi.fn(),
20
21
  }));
22
+ // Mock IdeClient
23
+ const mockIdeClient = vi.hoisted(() => ({
24
+ getInstance: vi.fn().mockReturnValue(new Promise(() => { })),
25
+ }));
26
+ // Mock stdout
27
+ const mocks = vi.hoisted(() => ({
28
+ mockStdout: { write: vi.fn() },
29
+ }));
21
30
  vi.mock('@google/gemini-cli-core', async (importOriginal) => {
22
31
  const actual = await importOriginal();
23
32
  return {
24
33
  ...actual,
25
34
  coreEvents: mockCoreEvents,
35
+ IdeClient: mockIdeClient,
26
36
  };
27
37
  });
28
38
  import { useQuotaAndFallback } from './hooks/useQuotaAndFallback.js';
29
39
  import { UIStateContext } from './contexts/UIStateContext.js';
30
40
  import { UIActionsContext, } from './contexts/UIActionsContext.js';
31
41
  // Mock useStdout to capture terminal title writes
32
- let mockStdout;
33
42
  vi.mock('ink', async (importOriginal) => {
34
43
  const actual = await importOriginal();
35
44
  return {
36
45
  ...actual,
37
- useStdout: () => ({ stdout: mockStdout }),
46
+ useStdout: () => ({ stdout: mocks.mockStdout }),
38
47
  measureElement: vi.fn(),
39
48
  };
40
49
  });
@@ -86,6 +95,15 @@ vi.mock('./utils/mouse.js', () => ({
86
95
  enableMouseEvents: vi.fn(),
87
96
  disableMouseEvents: vi.fn(),
88
97
  }));
98
+ vi.mock('../utils/stdio.js', () => ({
99
+ writeToStdout: vi.fn((...args) => process.stdout.write(...args)),
100
+ writeToStderr: vi.fn((...args) => process.stderr.write(...args)),
101
+ patchStdio: vi.fn(() => () => { }),
102
+ createInkStdio: vi.fn(() => ({
103
+ stdout: process.stdout,
104
+ stderr: process.stderr,
105
+ })),
106
+ }));
89
107
  import { useHistory } from './hooks/useHistoryManager.js';
90
108
  import { useThemeCommand } from './hooks/useThemeCommand.js';
91
109
  import { useAuthCommand } from './auth/useAuth.js';
@@ -112,6 +130,7 @@ import { useTerminalSize } from './hooks/useTerminalSize.js';
112
130
  import { ShellExecutionService } from '@google/gemini-cli-core';
113
131
  import {} from '../config/extension-manager.js';
114
132
  import { enableMouseEvents, disableMouseEvents } from './utils/mouse.js';
133
+ import { writeToStdout } from '../utils/stdio.js';
115
134
  describe('AppContainer State Management', () => {
116
135
  let mockConfig;
117
136
  let mockSettings;
@@ -147,7 +166,7 @@ describe('AppContainer State Management', () => {
147
166
  beforeEach(() => {
148
167
  vi.clearAllMocks();
149
168
  // Initialize mock stdout for terminal title tests
150
- mockStdout = { write: vi.fn() };
169
+ mocks.mockStdout.write.mockClear();
151
170
  // Mock computeWindowTitle function to centralize title logic testing
152
171
  vi.mock('../utils/windowTitle.js', async () => ({
153
172
  computeWindowTitle: vi.fn((folderName) =>
@@ -246,7 +265,7 @@ describe('AppContainer State Management', () => {
246
265
  // Add other properties if AppContainer uses them
247
266
  });
248
267
  mockedUseLogger.mockReturnValue({
249
- getPreviousUserMessages: vi.fn().mockResolvedValue([]),
268
+ getPreviousUserMessages: vi.fn().mockReturnValue(new Promise(() => { })),
250
269
  });
251
270
  mockedUseLoadingIndicator.mockReturnValue({
252
271
  elapsedTime: '0.0s',
@@ -292,17 +311,13 @@ describe('AppContainer State Management', () => {
292
311
  describe('Basic Rendering', () => {
293
312
  it('renders without crashing with minimal props', async () => {
294
313
  const { unmount } = renderAppContainer();
295
- await act(async () => {
296
- await new Promise((resolve) => setTimeout(resolve, 0));
297
- });
314
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
298
315
  unmount();
299
316
  });
300
317
  it('renders with startup warnings', async () => {
301
318
  const startupWarnings = ['Warning 1', 'Warning 2'];
302
319
  const { unmount } = renderAppContainer({ startupWarnings });
303
- await act(async () => {
304
- await new Promise((resolve) => setTimeout(resolve, 0));
305
- });
320
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
306
321
  unmount();
307
322
  });
308
323
  });
@@ -315,9 +330,7 @@ describe('AppContainer State Management', () => {
315
330
  const { unmount } = renderAppContainer({
316
331
  initResult: initResultWithError,
317
332
  });
318
- await act(async () => {
319
- await new Promise((resolve) => setTimeout(resolve, 0));
320
- });
333
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
321
334
  unmount();
322
335
  });
323
336
  it('handles debug mode state', () => {
@@ -331,31 +344,23 @@ describe('AppContainer State Management', () => {
331
344
  describe('Context Providers', () => {
332
345
  it('provides AppContext with correct values', async () => {
333
346
  const { unmount } = renderAppContainer({ version: '2.0.0' });
334
- await act(async () => {
335
- await new Promise((resolve) => setTimeout(resolve, 0));
336
- });
347
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
337
348
  // Should render and unmount cleanly
338
349
  expect(() => unmount()).not.toThrow();
339
350
  });
340
351
  it('provides UIStateContext with state management', async () => {
341
352
  const { unmount } = renderAppContainer();
342
- await act(async () => {
343
- await new Promise((resolve) => setTimeout(resolve, 0));
344
- });
353
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
345
354
  unmount();
346
355
  });
347
356
  it('provides UIActionsContext with action handlers', async () => {
348
357
  const { unmount } = renderAppContainer();
349
- await act(async () => {
350
- await new Promise((resolve) => setTimeout(resolve, 0));
351
- });
358
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
352
359
  unmount();
353
360
  });
354
361
  it('provides ConfigContext with config object', async () => {
355
362
  const { unmount } = renderAppContainer();
356
- await act(async () => {
357
- await new Promise((resolve) => setTimeout(resolve, 0));
358
- });
363
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
359
364
  unmount();
360
365
  });
361
366
  });
@@ -370,9 +375,7 @@ describe('AppContainer State Management', () => {
370
375
  },
371
376
  };
372
377
  const { unmount } = renderAppContainer({ settings: settingsAllHidden });
373
- await act(async () => {
374
- await new Promise((resolve) => setTimeout(resolve, 0));
375
- });
378
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
376
379
  unmount();
377
380
  });
378
381
  it('handles settings with memory usage enabled', async () => {
@@ -385,18 +388,14 @@ describe('AppContainer State Management', () => {
385
388
  },
386
389
  };
387
390
  const { unmount } = renderAppContainer({ settings: settingsWithMemory });
388
- await act(async () => {
389
- await new Promise((resolve) => setTimeout(resolve, 0));
390
- });
391
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
391
392
  unmount();
392
393
  });
393
394
  });
394
395
  describe('Version Handling', () => {
395
396
  it.each(['1.0.0', '2.1.3-beta', '3.0.0-nightly'])('handles version format: %s', async (version) => {
396
397
  const { unmount } = renderAppContainer({ version });
397
- await act(async () => {
398
- await new Promise((resolve) => setTimeout(resolve, 0));
399
- });
398
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
400
399
  unmount();
401
400
  });
402
401
  });
@@ -408,9 +407,6 @@ describe('AppContainer State Management', () => {
408
407
  });
409
408
  // Should still render without crashing - errors should be handled internally
410
409
  const { unmount } = renderAppContainer({ config: errorConfig });
411
- await act(async () => {
412
- await new Promise((resolve) => setTimeout(resolve, 0));
413
- });
414
410
  unmount();
415
411
  });
416
412
  it('handles undefined settings gracefully', async () => {
@@ -418,9 +414,7 @@ describe('AppContainer State Management', () => {
418
414
  merged: {},
419
415
  };
420
416
  const { unmount } = renderAppContainer({ settings: undefinedSettings });
421
- await act(async () => {
422
- await new Promise((resolve) => setTimeout(resolve, 0));
423
- });
417
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
424
418
  unmount();
425
419
  });
426
420
  });
@@ -716,11 +710,10 @@ describe('AppContainer State Management', () => {
716
710
  it('passes a null proQuotaRequest to UIStateContext by default', async () => {
717
711
  // The default mock from beforeEach already sets proQuotaRequest to null
718
712
  const { unmount } = renderAppContainer();
719
- await act(async () => {
720
- await new Promise((resolve) => setTimeout(resolve, 0));
713
+ await waitFor(() => {
714
+ // Assert that the context value is as expected
715
+ expect(capturedUIState.proQuotaRequest).toBeNull();
721
716
  });
722
- // Assert that the context value is as expected
723
- expect(capturedUIState.proQuotaRequest).toBeNull();
724
717
  unmount();
725
718
  });
726
719
  it('passes a valid proQuotaRequest to UIStateContext when provided by the hook', async () => {
@@ -736,11 +729,10 @@ describe('AppContainer State Management', () => {
736
729
  });
737
730
  // Act: Render the container
738
731
  const { unmount } = renderAppContainer();
739
- await act(async () => {
740
- await new Promise((resolve) => setTimeout(resolve, 0));
732
+ await waitFor(() => {
733
+ // Assert: The mock request is correctly passed through the context
734
+ expect(capturedUIState.proQuotaRequest).toEqual(mockRequest);
741
735
  });
742
- // Assert: The mock request is correctly passed through the context
743
- expect(capturedUIState.proQuotaRequest).toEqual(mockRequest);
744
736
  unmount();
745
737
  });
746
738
  it('passes the handleProQuotaChoice function to UIActionsContext', async () => {
@@ -752,11 +744,10 @@ describe('AppContainer State Management', () => {
752
744
  });
753
745
  // Act: Render the container
754
746
  const { unmount } = renderAppContainer();
755
- await act(async () => {
756
- await new Promise((resolve) => setTimeout(resolve, 0));
747
+ await waitFor(() => {
748
+ // Assert: The action in the context is the mock handler we provided
749
+ expect(capturedUIActions.handleProQuotaChoice).toBe(mockHandler);
757
750
  });
758
- // Assert: The action in the context is the mock handler we provided
759
- expect(capturedUIActions.handleProQuotaChoice).toBe(mockHandler);
760
751
  // You can even verify that the plumbed function is callable
761
752
  act(() => {
762
753
  capturedUIActions.handleProQuotaChoice('retry_later');
@@ -768,7 +759,12 @@ describe('AppContainer State Management', () => {
768
759
  describe('Terminal Title Update Feature', () => {
769
760
  beforeEach(() => {
770
761
  // Reset mock stdout for each test
771
- mockStdout = { write: vi.fn() };
762
+ mocks.mockStdout.write.mockClear();
763
+ });
764
+ it('verifies useStdout is mocked', async () => {
765
+ const { useStdout } = await import('ink');
766
+ const { stdout } = useStdout();
767
+ expect(stdout).toBe(mocks.mockStdout);
772
768
  });
773
769
  it('should not update terminal title when showStatusInTitle is false', () => {
774
770
  // Arrange: Set up mock settings with showStatusInTitle disabled
@@ -788,7 +784,7 @@ describe('AppContainer State Management', () => {
788
784
  settings: mockSettingsWithShowStatusFalse,
789
785
  });
790
786
  // Assert: Check that no title-related writes occurred
791
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
787
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
792
788
  expect(titleWrites).toHaveLength(0);
793
789
  unmount();
794
790
  });
@@ -810,7 +806,7 @@ describe('AppContainer State Management', () => {
810
806
  settings: mockSettingsWithHideTitleTrue,
811
807
  });
812
808
  // Assert: Check that no title-related writes occurred
813
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
809
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
814
810
  expect(titleWrites).toHaveLength(0);
815
811
  unmount();
816
812
  });
@@ -842,7 +838,7 @@ describe('AppContainer State Management', () => {
842
838
  settings: mockSettingsWithTitleEnabled,
843
839
  });
844
840
  // Assert: Check that title was updated with thought subject
845
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
841
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
846
842
  expect(titleWrites).toHaveLength(1);
847
843
  expect(titleWrites[0][0]).toBe(`\x1b]2;${thoughtSubject.padEnd(80, ' ')}\x07`);
848
844
  unmount();
@@ -874,7 +870,7 @@ describe('AppContainer State Management', () => {
874
870
  settings: mockSettingsWithTitleEnabled,
875
871
  });
876
872
  // Assert: Check that title was updated with default Idle text
877
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
873
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
878
874
  expect(titleWrites).toHaveLength(1);
879
875
  expect(titleWrites[0][0]).toBe(`\x1b]2;${'Gemini - workspace'.padEnd(80, ' ')}\x07`);
880
876
  unmount();
@@ -907,7 +903,7 @@ describe('AppContainer State Management', () => {
907
903
  settings: mockSettingsWithTitleEnabled,
908
904
  });
909
905
  // Assert: Check that title was updated with confirmation text
910
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
906
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
911
907
  expect(titleWrites).toHaveLength(1);
912
908
  expect(titleWrites[0][0]).toBe(`\x1b]2;${thoughtSubject.padEnd(80, ' ')}\x07`);
913
909
  unmount();
@@ -940,7 +936,7 @@ describe('AppContainer State Management', () => {
940
936
  settings: mockSettingsWithTitleEnabled,
941
937
  });
942
938
  // Assert: Check that title is padded to exactly 80 characters
943
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
939
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
944
940
  expect(titleWrites).toHaveLength(1);
945
941
  const calledWith = titleWrites[0][0];
946
942
  const expectedTitle = shortTitle.padEnd(80, ' ');
@@ -978,7 +974,7 @@ describe('AppContainer State Management', () => {
978
974
  settings: mockSettingsWithTitleEnabled,
979
975
  });
980
976
  // Assert: Check that the correct ANSI escape sequence is used
981
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
977
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
982
978
  expect(titleWrites).toHaveLength(1);
983
979
  const expectedEscapeSequence = `\x1b]2;${title.padEnd(80, ' ')}\x07`;
984
980
  expect(titleWrites[0][0]).toBe(expectedEscapeSequence);
@@ -1013,7 +1009,7 @@ describe('AppContainer State Management', () => {
1013
1009
  settings: mockSettingsWithTitleEnabled,
1014
1010
  });
1015
1011
  // Assert: Check that title was updated with CLI_TITLE value
1016
- const titleWrites = mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
1012
+ const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]2;'));
1017
1013
  expect(titleWrites).toHaveLength(1);
1018
1014
  expect(titleWrites[0][0]).toBe(`\x1b]2;${'Custom Gemini Title'.padEnd(80, ' ')}\x07`);
1019
1015
  unmount();
@@ -1094,12 +1090,7 @@ describe('AppContainer State Management', () => {
1094
1090
  activePtyId: 'some-id',
1095
1091
  });
1096
1092
  const { unmount } = renderAppContainer();
1097
- await act(async () => {
1098
- await new Promise((resolve) => setTimeout(resolve, 0));
1099
- });
1100
- // Assert: The shell should be resized to a minimum height of 1, not a negative number.
1101
- // The old code would have tried to set a negative height.
1102
- expect(resizePtySpy).toHaveBeenCalled();
1093
+ await waitFor(() => expect(resizePtySpy).toHaveBeenCalled());
1103
1094
  const lastCall = resizePtySpy.mock.calls[resizePtySpy.mock.calls.length - 1];
1104
1095
  // Check the height argument specifically
1105
1096
  expect(lastCall[2]).toBe(1);
@@ -1190,7 +1181,7 @@ describe('AppContainer State Management', () => {
1190
1181
  await setupKeypressTest();
1191
1182
  pressKey({ name: 'c', ctrl: true }, 2);
1192
1183
  expect(mockCancelOngoingRequest).toHaveBeenCalledTimes(2);
1193
- expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
1184
+ expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit', undefined, undefined, false);
1194
1185
  unmount();
1195
1186
  });
1196
1187
  it('should reset press count after a timeout', async () => {
@@ -1220,7 +1211,7 @@ describe('AppContainer State Management', () => {
1220
1211
  it('should quit on second press if buffer is empty', async () => {
1221
1212
  await setupKeypressTest();
1222
1213
  pressKey({ name: 'd', ctrl: true }, 2);
1223
- expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit');
1214
+ expect(mockHandleSlashCommand).toHaveBeenCalledWith('/quit', undefined, undefined, false);
1224
1215
  unmount();
1225
1216
  });
1226
1217
  it('should reset press count after a timeout', async () => {
@@ -1261,7 +1252,7 @@ describe('AppContainer State Management', () => {
1261
1252
  unmount = renderResult.unmount;
1262
1253
  };
1263
1254
  beforeEach(() => {
1264
- mockStdout.write.mockClear();
1255
+ mocks.mockStdout.write.mockClear();
1265
1256
  mockedUseKeypress.mockImplementation((callback) => {
1266
1257
  handleGlobalKeypress = callback;
1267
1258
  });
@@ -1284,7 +1275,7 @@ describe('AppContainer State Management', () => {
1284
1275
  ])('$modeName', ({ isAlternateMode, shouldEnable }) => {
1285
1276
  it(`should ${shouldEnable ? 'toggle' : 'NOT toggle'} mouse off when Ctrl+S is pressed`, async () => {
1286
1277
  await setupCopyModeTest(isAlternateMode);
1287
- mockStdout.write.mockClear(); // Clear initial enable call
1278
+ mocks.mockStdout.write.mockClear(); // Clear initial enable call
1288
1279
  act(() => {
1289
1280
  handleGlobalKeypress({
1290
1281
  name: 's',
@@ -1308,7 +1299,7 @@ describe('AppContainer State Management', () => {
1308
1299
  if (shouldEnable) {
1309
1300
  it('should toggle mouse back on when Ctrl+S is pressed again', async () => {
1310
1301
  await setupCopyModeTest(isAlternateMode);
1311
- mockStdout.write.mockClear();
1302
+ writeToStdout.mockClear();
1312
1303
  // Turn it on (disable mouse)
1313
1304
  act(() => {
1314
1305
  handleGlobalKeypress({
@@ -1354,7 +1345,7 @@ describe('AppContainer State Management', () => {
1354
1345
  });
1355
1346
  });
1356
1347
  rerender();
1357
- mockStdout.write.mockClear();
1348
+ writeToStdout.mockClear();
1358
1349
  // Press any other key
1359
1350
  act(() => {
1360
1351
  handleGlobalKeypress({
@@ -1383,9 +1374,7 @@ describe('AppContainer State Management', () => {
1383
1374
  closeModelDialog: vi.fn(),
1384
1375
  });
1385
1376
  const { unmount } = renderAppContainer();
1386
- await act(async () => {
1387
- await new Promise((resolve) => setTimeout(resolve, 0));
1388
- });
1377
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1389
1378
  expect(capturedUIState.isModelDialogOpen).toBe(true);
1390
1379
  unmount();
1391
1380
  });
@@ -1397,9 +1386,7 @@ describe('AppContainer State Management', () => {
1397
1386
  closeModelDialog: mockCloseModelDialog,
1398
1387
  });
1399
1388
  const { unmount } = renderAppContainer();
1400
- await act(async () => {
1401
- await new Promise((resolve) => setTimeout(resolve, 0));
1402
- });
1389
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1403
1390
  // Verify that the actions are correctly passed through context
1404
1391
  act(() => {
1405
1392
  capturedUIActions.closeModelDialog();
@@ -1411,26 +1398,20 @@ describe('AppContainer State Management', () => {
1411
1398
  describe('CoreEvents Integration', () => {
1412
1399
  it('subscribes to UserFeedback and drains backlog on mount', async () => {
1413
1400
  const { unmount } = renderAppContainer();
1414
- await act(async () => {
1415
- await new Promise((resolve) => setTimeout(resolve, 0));
1416
- });
1401
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1417
1402
  expect(mockCoreEvents.on).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
1418
- expect(mockCoreEvents.drainFeedbackBacklog).toHaveBeenCalledTimes(1);
1403
+ expect(mockCoreEvents.drainBacklogs).toHaveBeenCalledTimes(1);
1419
1404
  unmount();
1420
1405
  });
1421
1406
  it('unsubscribes from UserFeedback on unmount', async () => {
1422
1407
  const { unmount } = renderAppContainer();
1423
- await act(async () => {
1424
- await new Promise((resolve) => setTimeout(resolve, 0));
1425
- });
1408
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1426
1409
  unmount();
1427
1410
  expect(mockCoreEvents.off).toHaveBeenCalledWith(CoreEvent.UserFeedback, expect.any(Function));
1428
1411
  });
1429
1412
  it('adds history item when UserFeedback event is received', async () => {
1430
1413
  const { unmount } = renderAppContainer();
1431
- await act(async () => {
1432
- await new Promise((resolve) => setTimeout(resolve, 0));
1433
- });
1414
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1434
1415
  // Get the registered handler
1435
1416
  const handler = mockCoreEvents.on.mock.calls.find((call) => call[0] === CoreEvent.UserFeedback)?.[1];
1436
1417
  expect(handler).toBeDefined();
@@ -1452,10 +1433,8 @@ describe('AppContainer State Management', () => {
1452
1433
  // Arrange: Mock initial model
1453
1434
  vi.spyOn(mockConfig, 'getModel').mockReturnValue('initial-model');
1454
1435
  const { unmount } = renderAppContainer();
1455
- await act(async () => {
1456
- await vi.waitFor(() => {
1457
- expect(capturedUIState?.currentModel).toBe('initial-model');
1458
- });
1436
+ await waitFor(() => {
1437
+ expect(capturedUIState?.currentModel).toBe('initial-model');
1459
1438
  });
1460
1439
  // Get the registered handler for ModelChanged
1461
1440
  const handler = mockCoreEvents.on.mock.calls.find((call) => call[0] === CoreEvent.ModelChanged)?.[1];
@@ -1487,10 +1466,7 @@ describe('AppContainer State Management', () => {
1487
1466
  });
1488
1467
  // The main assertion is that the render does not throw.
1489
1468
  const { unmount } = renderAppContainer();
1490
- await act(async () => {
1491
- await new Promise((resolve) => setTimeout(resolve, 0));
1492
- });
1493
- expect(resizePtySpy).toHaveBeenCalled();
1469
+ await waitFor(() => expect(resizePtySpy).toHaveBeenCalled());
1494
1470
  unmount();
1495
1471
  });
1496
1472
  });
@@ -1502,14 +1478,105 @@ describe('AppContainer State Management', () => {
1502
1478
  apiKey: 'fake-key',
1503
1479
  });
1504
1480
  const { unmount } = renderAppContainer();
1505
- await act(async () => {
1506
- await new Promise((resolve) => setTimeout(resolve, 0));
1507
- });
1508
- await vi.waitFor(() => {
1481
+ await waitFor(() => {
1509
1482
  expect(capturedUIState.bannerData.defaultText).toBeDefined();
1510
1483
  unmount();
1511
1484
  });
1512
1485
  });
1513
1486
  });
1487
+ describe('onCancelSubmit Behavior', () => {
1488
+ let mockSetText;
1489
+ // Helper to extract arguments from the useGeminiStream hook call
1490
+ // This isolates the positional argument dependency to a single location
1491
+ const extractUseGeminiStreamArgs = (args) => ({
1492
+ onCancelSubmit: args[13],
1493
+ });
1494
+ beforeEach(() => {
1495
+ mockSetText = vi.fn();
1496
+ mockedUseTextBuffer.mockReturnValue({
1497
+ text: '',
1498
+ setText: mockSetText,
1499
+ });
1500
+ });
1501
+ it('clears the prompt when onCancelSubmit is called with shouldRestorePrompt=false', async () => {
1502
+ const { unmount } = renderAppContainer();
1503
+ await waitFor(() => expect(capturedUIState).toBeTruthy());
1504
+ const { onCancelSubmit } = extractUseGeminiStreamArgs(mockedUseGeminiStream.mock.lastCall);
1505
+ act(() => {
1506
+ onCancelSubmit(false);
1507
+ });
1508
+ expect(mockSetText).toHaveBeenCalledWith('');
1509
+ unmount();
1510
+ });
1511
+ it('restores the prompt when onCancelSubmit is called with shouldRestorePrompt=true (or undefined)', async () => {
1512
+ mockedUseLogger.mockReturnValue({
1513
+ getPreviousUserMessages: vi
1514
+ .fn()
1515
+ .mockResolvedValue(['previous message']),
1516
+ });
1517
+ const { unmount } = renderAppContainer();
1518
+ await waitFor(() => expect(capturedUIState.userMessages).toContain('previous message'));
1519
+ const { onCancelSubmit } = extractUseGeminiStreamArgs(mockedUseGeminiStream.mock.lastCall);
1520
+ await act(async () => {
1521
+ onCancelSubmit(true);
1522
+ });
1523
+ expect(mockSetText).toHaveBeenCalledWith('previous message');
1524
+ unmount();
1525
+ });
1526
+ it('correctly restores prompt even if userMessages is stale (race condition fix)', async () => {
1527
+ // Setup initial history with one message
1528
+ const initialHistory = [{ type: 'user', text: 'Previous Prompt' }];
1529
+ mockedUseHistory.mockReturnValue({
1530
+ history: initialHistory,
1531
+ addItem: vi.fn(),
1532
+ updateItem: vi.fn(),
1533
+ clearItems: vi.fn(),
1534
+ loadHistory: vi.fn(),
1535
+ });
1536
+ let resolveLoggerPromise;
1537
+ const loggerPromise = new Promise((resolve) => {
1538
+ resolveLoggerPromise = resolve;
1539
+ });
1540
+ // Mock logger to control when userMessages updates
1541
+ const getPreviousUserMessagesMock = vi
1542
+ .fn()
1543
+ .mockResolvedValueOnce([]) // Initial mount
1544
+ .mockReturnValueOnce(loggerPromise); // Second render (simulated update)
1545
+ mockedUseLogger.mockReturnValue({
1546
+ getPreviousUserMessages: getPreviousUserMessagesMock,
1547
+ });
1548
+ const { unmount, rerender } = renderAppContainer();
1549
+ // Wait for userMessages to be populated with 'Previous Prompt'
1550
+ await waitFor(() => expect(capturedUIState.userMessages).toContain('Previous Prompt'));
1551
+ // Simulate a new prompt being added (e.g., user sent it, but it overflowed)
1552
+ const newPrompt = 'Current Prompt that Overflowed';
1553
+ const newHistory = [...initialHistory, { type: 'user', text: newPrompt }];
1554
+ mockedUseHistory.mockReturnValue({
1555
+ history: newHistory,
1556
+ addItem: vi.fn(),
1557
+ updateItem: vi.fn(),
1558
+ clearItems: vi.fn(),
1559
+ loadHistory: vi.fn(),
1560
+ });
1561
+ // Rerender to reflect the history change.
1562
+ // This triggers the effect to update userMessages, but it hangs on loggerPromise.
1563
+ rerender(getAppContainer());
1564
+ const { onCancelSubmit } = extractUseGeminiStreamArgs(mockedUseGeminiStream.mock.lastCall);
1565
+ // Call onCancelSubmit immediately. userMessages is still stale (has only 'Previous Prompt')
1566
+ // because the effect is waiting on loggerPromise.
1567
+ act(() => {
1568
+ onCancelSubmit(true);
1569
+ });
1570
+ // Now resolve the promise to let the effect complete and update userMessages
1571
+ await act(async () => {
1572
+ resolveLoggerPromise([]);
1573
+ });
1574
+ // With the fix, it should have waited for userMessages to update and then set the new prompt
1575
+ await waitFor(() => {
1576
+ expect(mockSetText).toHaveBeenCalledWith(newPrompt);
1577
+ });
1578
+ unmount();
1579
+ });
1580
+ });
1514
1581
  });
1515
1582
  //# sourceMappingURL=AppContainer.test.js.map