@google/gemini-cli 0.12.0-nightly.20251023.c4c0c0d1 → 0.12.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/README.md +7 -5
- package/dist/package.json +3 -3
- package/dist/src/commands/extensions/disable.d.ts +1 -1
- package/dist/src/commands/extensions/disable.js +5 -4
- package/dist/src/commands/extensions/disable.js.map +1 -1
- package/dist/src/commands/extensions/enable.d.ts +1 -1
- package/dist/src/commands/extensions/enable.js +3 -2
- package/dist/src/commands/extensions/enable.js.map +1 -1
- package/dist/src/commands/extensions/install.js +2 -1
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +1 -0
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/commands/extensions/link.js +2 -1
- package/dist/src/commands/extensions/link.js.map +1 -1
- package/dist/src/commands/extensions/list.js +2 -2
- package/dist/src/commands/extensions/list.js.map +1 -1
- package/dist/src/commands/extensions/uninstall.js +2 -1
- package/dist/src/commands/extensions/uninstall.js.map +1 -1
- package/dist/src/commands/extensions/update.js +2 -2
- package/dist/src/commands/extensions/update.js.map +1 -1
- package/dist/src/commands/mcp/list.js +2 -2
- package/dist/src/commands/mcp/list.js.map +1 -1
- package/dist/src/config/config.d.ts +6 -3
- package/dist/src/config/config.js +56 -11
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +208 -175
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.d.ts +23 -10
- package/dist/src/config/extension-manager.js +90 -64
- package/dist/src/config/extension-manager.js.map +1 -1
- package/dist/src/config/extension.test.js +183 -76
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
- package/dist/src/config/extensions/extensionEnablement.js +3 -2
- package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
- package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.d.ts +3 -3
- package/dist/src/config/extensions/extensionSettings.js +74 -24
- package/dist/src/config/extensions/extensionSettings.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.test.js +145 -24
- package/dist/src/config/extensions/extensionSettings.test.js.map +1 -1
- package/dist/src/config/extensions/github.js +3 -3
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/github.test.js +1 -1
- package/dist/src/config/extensions/github.test.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.d.ts +1 -1
- package/dist/src/config/extensions/github_fetch.js +13 -1
- package/dist/src/config/extensions/github_fetch.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
- package/dist/src/config/extensions/github_fetch.test.js +169 -0
- package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
- package/dist/src/config/extensions/update.js +7 -6
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/extensions/update.test.js +54 -30
- package/dist/src/config/extensions/update.test.js.map +1 -1
- package/dist/src/config/keyBindings.js +1 -1
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/policies/read-only.toml +56 -0
- package/dist/src/config/policies/write.toml +63 -0
- package/dist/src/config/policies/yolo.toml +31 -0
- package/dist/src/config/policy-engine.integration.test.js +41 -38
- package/dist/src/config/policy-engine.integration.test.js.map +1 -1
- package/dist/src/config/policy-toml-loader.d.ts +46 -0
- package/dist/src/config/policy-toml-loader.js +314 -0
- package/dist/src/config/policy-toml-loader.js.map +1 -0
- package/dist/src/config/policy-toml-loader.test.d.ts +6 -0
- package/dist/src/config/policy-toml-loader.test.js +626 -0
- package/dist/src/config/policy-toml-loader.test.js.map +1 -0
- package/dist/src/config/policy.d.ts +9 -2
- package/dist/src/config/policy.js +139 -110
- package/dist/src/config/policy.js.map +1 -1
- package/dist/src/config/policy.test.js +780 -82
- package/dist/src/config/policy.test.js.map +1 -1
- package/dist/src/config/settings.test.js +6 -6
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/core/initializer.js +2 -1
- package/dist/src/core/initializer.js.map +1 -1
- package/dist/src/gemini.js +6 -17
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +27 -2
- 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.js +16 -4
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +67 -12
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/test-utils/render.d.ts +12 -0
- package/dist/src/test-utils/render.js +28 -1
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/test-utils/render.test.d.ts +6 -0
- package/dist/src/test-utils/render.test.js +54 -0
- package/dist/src/test-utils/render.test.js.map +1 -0
- package/dist/src/ui/AppContainer.js +29 -23
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +8 -0
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.js +1 -1
- package/dist/src/ui/commands/directoryCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +45 -1
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +64 -1
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.js +1 -1
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.test.js +3 -1
- package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js +4 -4
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/Footer.js +1 -1
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Footer.test.js +24 -0
- package/dist/src/ui/components/Footer.test.js.map +1 -1
- package/dist/src/ui/components/Help.test.js +0 -1
- package/dist/src/ui/components/Help.test.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +442 -342
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.test.js +5 -5
- package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -12
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +13 -14
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.test.js +1 -2
- package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +11 -12
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.test.js +2 -1
- package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.d.ts +1 -1
- package/dist/src/ui/components/views/ExtensionsList.js +4 -1
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
- package/dist/src/ui/contexts/KeypressContext.js +114 -64
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +166 -482
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/SessionContext.test.js +27 -13
- package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +2 -2
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +18 -2
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +74 -80
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAtCompletion.test.js +32 -23
- package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +2 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.js +79 -78
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
- package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
- package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -2
- package/dist/src/ui/hooks/useExtensionUpdates.js +4 -2
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +37 -26
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
- package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.test.js +25 -9
- package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.test.js +45 -22
- package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +56 -19
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js +155 -74
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.test.js +29 -16
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +24 -7
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.test.js +94 -113
- package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
- package/dist/src/ui/hooks/useMessageQueue.test.js +61 -45
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
- package/dist/src/ui/hooks/useModelCommand.test.js +18 -11
- package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.test.js +83 -110
- package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
- package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -10
- package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
- package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +33 -40
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +37 -26
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.test.js +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.test.js +193 -132
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
- package/dist/src/ui/hooks/useShellHistory.test.js +40 -16
- package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +54 -49
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useTimer.test.js +43 -14
- package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +163 -74
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/vim.test.js +251 -356
- package/dist/src/ui/hooks/vim.test.js.map +1 -1
- package/dist/src/ui/keyMatchers.test.js +3 -3
- package/dist/src/ui/keyMatchers.test.js.map +1 -1
- package/dist/src/ui/utils/textOutput.d.ts +25 -0
- package/dist/src/ui/utils/textOutput.js +49 -0
- package/dist/src/ui/utils/textOutput.js.map +1 -0
- package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
- package/dist/src/ui/utils/textOutput.test.js +79 -0
- package/dist/src/ui/utils/textOutput.test.js.map +1 -0
- package/dist/src/ui/utils/updateCheck.d.ts +7 -1
- package/dist/src/ui/utils/updateCheck.js +27 -26
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.test.js +19 -49
- package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
- package/dist/src/utils/handleAutoUpdate.js +9 -3
- package/dist/src/utils/handleAutoUpdate.js.map +1 -1
- package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
- package/dist/src/zed-integration/zedIntegration.js +9 -16
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/google-gemini-cli-0.12.0-nightly.20251022.0542de95.tgz +0 -0
|
@@ -5,7 +5,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
5
5
|
* SPDX-License-Identifier: Apache-2.0
|
|
6
6
|
*/
|
|
7
7
|
import { renderWithProviders } from '../../test-utils/render.js';
|
|
8
|
-
import {
|
|
8
|
+
import { act } from 'react';
|
|
9
9
|
import { InputPrompt } from './InputPrompt.js';
|
|
10
10
|
import { ApprovalMode } from '@google/gemini-cli-core';
|
|
11
11
|
import * as path from 'node:path';
|
|
@@ -207,63 +207,68 @@ describe('InputPrompt', () => {
|
|
|
207
207
|
streamingState: StreamingState.Idle,
|
|
208
208
|
};
|
|
209
209
|
});
|
|
210
|
-
const wait = (ms = 50) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
211
210
|
it('should call shellHistory.getPreviousCommand on up arrow in shell mode', async () => {
|
|
212
211
|
props.shellModeActive = true;
|
|
213
212
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
214
|
-
await
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled();
|
|
213
|
+
await act(async () => {
|
|
214
|
+
stdin.write('\u001B[A');
|
|
215
|
+
});
|
|
216
|
+
await vi.waitFor(() => expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled());
|
|
218
217
|
unmount();
|
|
219
218
|
});
|
|
220
219
|
it('should call shellHistory.getNextCommand on down arrow in shell mode', async () => {
|
|
221
220
|
props.shellModeActive = true;
|
|
222
221
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
223
|
-
await
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
expect(mockShellHistory.getNextCommand).toHaveBeenCalled();
|
|
222
|
+
await act(async () => {
|
|
223
|
+
stdin.write('\u001B[B');
|
|
224
|
+
});
|
|
225
|
+
await vi.waitFor(() => expect(mockShellHistory.getNextCommand).toHaveBeenCalled());
|
|
227
226
|
unmount();
|
|
228
227
|
});
|
|
229
228
|
it('should set the buffer text when a shell history command is retrieved', async () => {
|
|
230
229
|
props.shellModeActive = true;
|
|
231
230
|
vi.mocked(mockShellHistory.getPreviousCommand).mockReturnValue('previous command');
|
|
232
231
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
233
|
-
await
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
await act(async () => {
|
|
233
|
+
stdin.write('\u001B[A');
|
|
234
|
+
});
|
|
235
|
+
await vi.waitFor(() => {
|
|
236
|
+
expect(mockShellHistory.getPreviousCommand).toHaveBeenCalled();
|
|
237
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('previous command');
|
|
238
|
+
});
|
|
238
239
|
unmount();
|
|
239
240
|
});
|
|
240
241
|
it('should call shellHistory.addCommandToHistory on submit in shell mode', async () => {
|
|
241
242
|
props.shellModeActive = true;
|
|
242
243
|
props.buffer.setText('ls -l');
|
|
243
244
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
244
|
-
await
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
await act(async () => {
|
|
246
|
+
stdin.write('\r');
|
|
247
|
+
});
|
|
248
|
+
await vi.waitFor(() => {
|
|
249
|
+
expect(mockShellHistory.addCommandToHistory).toHaveBeenCalledWith('ls -l');
|
|
250
|
+
expect(props.onSubmit).toHaveBeenCalledWith('ls -l');
|
|
251
|
+
});
|
|
249
252
|
unmount();
|
|
250
253
|
});
|
|
251
254
|
it('should NOT call shell history methods when not in shell mode', async () => {
|
|
252
255
|
props.buffer.setText('some text');
|
|
253
256
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
254
|
-
await
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
await
|
|
259
|
-
|
|
260
|
-
|
|
257
|
+
await act(async () => {
|
|
258
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
259
|
+
});
|
|
260
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
261
|
+
await act(async () => {
|
|
262
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
263
|
+
});
|
|
264
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateDown).toHaveBeenCalled());
|
|
265
|
+
await act(async () => {
|
|
266
|
+
stdin.write('\r'); // Enter
|
|
267
|
+
});
|
|
268
|
+
await vi.waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('some text'));
|
|
261
269
|
expect(mockShellHistory.getPreviousCommand).not.toHaveBeenCalled();
|
|
262
270
|
expect(mockShellHistory.getNextCommand).not.toHaveBeenCalled();
|
|
263
271
|
expect(mockShellHistory.addCommandToHistory).not.toHaveBeenCalled();
|
|
264
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
265
|
-
expect(mockInputHistory.navigateDown).toHaveBeenCalled();
|
|
266
|
-
expect(props.onSubmit).toHaveBeenCalledWith('some text');
|
|
267
272
|
unmount();
|
|
268
273
|
});
|
|
269
274
|
it('should call completion.navigateUp for both up arrow and Ctrl+P when suggestions are showing', async () => {
|
|
@@ -277,13 +282,15 @@ describe('InputPrompt', () => {
|
|
|
277
282
|
});
|
|
278
283
|
props.buffer.setText('/mem');
|
|
279
284
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
280
|
-
await wait();
|
|
281
285
|
// Test up arrow
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
await
|
|
286
|
-
|
|
286
|
+
await act(async () => {
|
|
287
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
288
|
+
});
|
|
289
|
+
await vi.waitFor(() => expect(mockCommandCompletion.navigateUp).toHaveBeenCalledTimes(1));
|
|
290
|
+
await act(async () => {
|
|
291
|
+
stdin.write('\u0010'); // Ctrl+P
|
|
292
|
+
});
|
|
293
|
+
await vi.waitFor(() => expect(mockCommandCompletion.navigateUp).toHaveBeenCalledTimes(2));
|
|
287
294
|
expect(mockCommandCompletion.navigateDown).not.toHaveBeenCalled();
|
|
288
295
|
unmount();
|
|
289
296
|
});
|
|
@@ -298,13 +305,15 @@ describe('InputPrompt', () => {
|
|
|
298
305
|
});
|
|
299
306
|
props.buffer.setText('/mem');
|
|
300
307
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
301
|
-
await wait();
|
|
302
308
|
// Test down arrow
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
await
|
|
307
|
-
|
|
309
|
+
await act(async () => {
|
|
310
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
311
|
+
});
|
|
312
|
+
await vi.waitFor(() => expect(mockCommandCompletion.navigateDown).toHaveBeenCalledTimes(1));
|
|
313
|
+
await act(async () => {
|
|
314
|
+
stdin.write('\u000E'); // Ctrl+N
|
|
315
|
+
});
|
|
316
|
+
await vi.waitFor(() => expect(mockCommandCompletion.navigateDown).toHaveBeenCalledTimes(2));
|
|
308
317
|
expect(mockCommandCompletion.navigateUp).not.toHaveBeenCalled();
|
|
309
318
|
unmount();
|
|
310
319
|
});
|
|
@@ -315,15 +324,22 @@ describe('InputPrompt', () => {
|
|
|
315
324
|
});
|
|
316
325
|
props.buffer.setText('some text');
|
|
317
326
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
318
|
-
await
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
await
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
await
|
|
327
|
+
await act(async () => {
|
|
328
|
+
stdin.write('\u001B[A'); // Up arrow
|
|
329
|
+
});
|
|
330
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
331
|
+
await act(async () => {
|
|
332
|
+
stdin.write('\u001B[B'); // Down arrow
|
|
333
|
+
});
|
|
334
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateDown).toHaveBeenCalled());
|
|
335
|
+
await act(async () => {
|
|
336
|
+
stdin.write('\u0010'); // Ctrl+P
|
|
337
|
+
});
|
|
338
|
+
await vi.waitFor(() => { });
|
|
339
|
+
await act(async () => {
|
|
340
|
+
stdin.write('\u000E'); // Ctrl+N
|
|
341
|
+
});
|
|
342
|
+
await vi.waitFor(() => { });
|
|
327
343
|
expect(mockCommandCompletion.navigateUp).not.toHaveBeenCalled();
|
|
328
344
|
expect(mockCommandCompletion.navigateDown).not.toHaveBeenCalled();
|
|
329
345
|
unmount();
|
|
@@ -338,23 +354,27 @@ describe('InputPrompt', () => {
|
|
|
338
354
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
|
339
355
|
vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue('/test/.gemini-clipboard/clipboard-123.png');
|
|
340
356
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
341
|
-
await wait();
|
|
342
357
|
// Send Ctrl+V
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
358
|
+
await act(async () => {
|
|
359
|
+
stdin.write('\x16'); // Ctrl+V
|
|
360
|
+
});
|
|
361
|
+
await vi.waitFor(() => {
|
|
362
|
+
expect(clipboardUtils.clipboardHasImage).toHaveBeenCalled();
|
|
363
|
+
expect(clipboardUtils.saveClipboardImage).toHaveBeenCalledWith(props.config.getTargetDir());
|
|
364
|
+
expect(clipboardUtils.cleanupOldClipboardImages).toHaveBeenCalledWith(props.config.getTargetDir());
|
|
365
|
+
expect(mockBuffer.replaceRangeByOffset).toHaveBeenCalled();
|
|
366
|
+
});
|
|
349
367
|
unmount();
|
|
350
368
|
});
|
|
351
369
|
it('should not insert anything when clipboard has no image', async () => {
|
|
352
370
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
|
|
353
371
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
354
|
-
await
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
372
|
+
await act(async () => {
|
|
373
|
+
stdin.write('\x16'); // Ctrl+V
|
|
374
|
+
});
|
|
375
|
+
await vi.waitFor(() => {
|
|
376
|
+
expect(clipboardUtils.clipboardHasImage).toHaveBeenCalled();
|
|
377
|
+
});
|
|
358
378
|
expect(clipboardUtils.saveClipboardImage).not.toHaveBeenCalled();
|
|
359
379
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
360
380
|
unmount();
|
|
@@ -363,10 +383,12 @@ describe('InputPrompt', () => {
|
|
|
363
383
|
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(true);
|
|
364
384
|
vi.mocked(clipboardUtils.saveClipboardImage).mockResolvedValue(null);
|
|
365
385
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
366
|
-
await
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
386
|
+
await act(async () => {
|
|
387
|
+
stdin.write('\x16'); // Ctrl+V
|
|
388
|
+
});
|
|
389
|
+
await vi.waitFor(() => {
|
|
390
|
+
expect(clipboardUtils.saveClipboardImage).toHaveBeenCalled();
|
|
391
|
+
});
|
|
370
392
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
371
393
|
unmount();
|
|
372
394
|
});
|
|
@@ -380,11 +402,13 @@ describe('InputPrompt', () => {
|
|
|
380
402
|
mockBuffer.lines = ['Hello world'];
|
|
381
403
|
mockBuffer.replaceRangeByOffset = vi.fn();
|
|
382
404
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
383
|
-
await
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
405
|
+
await act(async () => {
|
|
406
|
+
stdin.write('\x16'); // Ctrl+V
|
|
407
|
+
});
|
|
408
|
+
await vi.waitFor(() => {
|
|
409
|
+
// Should insert at cursor position with spaces
|
|
410
|
+
expect(mockBuffer.replaceRangeByOffset).toHaveBeenCalled();
|
|
411
|
+
});
|
|
388
412
|
// Get the actual call to see what path was used
|
|
389
413
|
const actualCall = vi.mocked(mockBuffer.replaceRangeByOffset).mock
|
|
390
414
|
.calls[0];
|
|
@@ -399,10 +423,12 @@ describe('InputPrompt', () => {
|
|
|
399
423
|
.mockImplementation(() => { });
|
|
400
424
|
vi.mocked(clipboardUtils.clipboardHasImage).mockRejectedValue(new Error('Clipboard error'));
|
|
401
425
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
402
|
-
await
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
426
|
+
await act(async () => {
|
|
427
|
+
stdin.write('\x16'); // Ctrl+V
|
|
428
|
+
});
|
|
429
|
+
await vi.waitFor(() => {
|
|
430
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Error handling clipboard image:', expect.any(Error));
|
|
431
|
+
});
|
|
406
432
|
expect(mockBuffer.setText).not.toHaveBeenCalled();
|
|
407
433
|
consoleErrorSpy.mockRestore();
|
|
408
434
|
unmount();
|
|
@@ -418,10 +444,10 @@ describe('InputPrompt', () => {
|
|
|
418
444
|
});
|
|
419
445
|
props.buffer.setText('/mem');
|
|
420
446
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
421
|
-
await
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
447
|
+
await act(async () => {
|
|
448
|
+
stdin.write('\t'); // Press Tab
|
|
449
|
+
});
|
|
450
|
+
await vi.waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
425
451
|
unmount();
|
|
426
452
|
});
|
|
427
453
|
it('should append a sub-command when the parent command is already complete', async () => {
|
|
@@ -437,10 +463,10 @@ describe('InputPrompt', () => {
|
|
|
437
463
|
});
|
|
438
464
|
props.buffer.setText('/memory ');
|
|
439
465
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
440
|
-
await
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(1);
|
|
466
|
+
await act(async () => {
|
|
467
|
+
stdin.write('\t'); // Press Tab
|
|
468
|
+
});
|
|
469
|
+
await vi.waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(1));
|
|
444
470
|
unmount();
|
|
445
471
|
});
|
|
446
472
|
it('should handle the "backspace" edge case correctly', async () => {
|
|
@@ -457,11 +483,12 @@ describe('InputPrompt', () => {
|
|
|
457
483
|
// The user has backspaced, so the query is now just '/memory'
|
|
458
484
|
props.buffer.setText('/memory');
|
|
459
485
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
460
|
-
await
|
|
461
|
-
|
|
462
|
-
|
|
486
|
+
await act(async () => {
|
|
487
|
+
stdin.write('\t'); // Press Tab
|
|
488
|
+
});
|
|
489
|
+
await vi.waitFor(() =>
|
|
463
490
|
// It should NOT become '/show'. It should correctly become '/memory show'.
|
|
464
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
491
|
+
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
465
492
|
unmount();
|
|
466
493
|
});
|
|
467
494
|
it('should complete a partial argument for a command', async () => {
|
|
@@ -474,10 +501,10 @@ describe('InputPrompt', () => {
|
|
|
474
501
|
});
|
|
475
502
|
props.buffer.setText('/chat resume fi-');
|
|
476
503
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
477
|
-
await
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
504
|
+
await act(async () => {
|
|
505
|
+
stdin.write('\t'); // Press Tab
|
|
506
|
+
});
|
|
507
|
+
await vi.waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
481
508
|
unmount();
|
|
482
509
|
});
|
|
483
510
|
it('should autocomplete on Enter when suggestions are active, without submitting', async () => {
|
|
@@ -489,11 +516,13 @@ describe('InputPrompt', () => {
|
|
|
489
516
|
});
|
|
490
517
|
props.buffer.setText('/mem');
|
|
491
518
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
492
|
-
await
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
519
|
+
await act(async () => {
|
|
520
|
+
stdin.write('\r');
|
|
521
|
+
});
|
|
522
|
+
await vi.waitFor(() => {
|
|
523
|
+
// The app should autocomplete the text, NOT submit.
|
|
524
|
+
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
525
|
+
});
|
|
497
526
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
498
527
|
unmount();
|
|
499
528
|
});
|
|
@@ -514,18 +543,19 @@ describe('InputPrompt', () => {
|
|
|
514
543
|
});
|
|
515
544
|
props.buffer.setText('/?');
|
|
516
545
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
517
|
-
await
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
546
|
+
await act(async () => {
|
|
547
|
+
stdin.write('\t'); // Press Tab for autocomplete
|
|
548
|
+
});
|
|
549
|
+
await vi.waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
521
550
|
unmount();
|
|
522
551
|
});
|
|
523
552
|
it('should not submit on Enter when the buffer is empty or only contains whitespace', async () => {
|
|
524
553
|
props.buffer.setText(' '); // Set buffer to whitespace
|
|
525
554
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
526
|
-
await
|
|
527
|
-
|
|
528
|
-
|
|
555
|
+
await act(async () => {
|
|
556
|
+
stdin.write('\r'); // Press Enter
|
|
557
|
+
});
|
|
558
|
+
await vi.waitFor(() => { });
|
|
529
559
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
530
560
|
unmount();
|
|
531
561
|
});
|
|
@@ -537,10 +567,10 @@ describe('InputPrompt', () => {
|
|
|
537
567
|
});
|
|
538
568
|
props.buffer.setText('/clear');
|
|
539
569
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
540
|
-
await
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
expect(props.onSubmit).toHaveBeenCalledWith('/clear');
|
|
570
|
+
await act(async () => {
|
|
571
|
+
stdin.write('\r');
|
|
572
|
+
});
|
|
573
|
+
await vi.waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('/clear'));
|
|
544
574
|
unmount();
|
|
545
575
|
});
|
|
546
576
|
it('should submit directly on Enter when a complete leaf command is typed', async () => {
|
|
@@ -551,10 +581,10 @@ describe('InputPrompt', () => {
|
|
|
551
581
|
});
|
|
552
582
|
props.buffer.setText('/clear');
|
|
553
583
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
554
|
-
await
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
expect(props.onSubmit).toHaveBeenCalledWith('/clear');
|
|
584
|
+
await act(async () => {
|
|
585
|
+
stdin.write('\r');
|
|
586
|
+
});
|
|
587
|
+
await vi.waitFor(() => expect(props.onSubmit).toHaveBeenCalledWith('/clear'));
|
|
558
588
|
unmount();
|
|
559
589
|
});
|
|
560
590
|
it('should autocomplete an @-path on Enter without submitting', async () => {
|
|
@@ -566,10 +596,10 @@ describe('InputPrompt', () => {
|
|
|
566
596
|
});
|
|
567
597
|
props.buffer.setText('@src/components/');
|
|
568
598
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
569
|
-
await
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0);
|
|
599
|
+
await act(async () => {
|
|
600
|
+
stdin.write('\r');
|
|
601
|
+
});
|
|
602
|
+
await vi.waitFor(() => expect(mockCommandCompletion.handleAutocomplete).toHaveBeenCalledWith(0));
|
|
573
603
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
574
604
|
unmount();
|
|
575
605
|
});
|
|
@@ -579,31 +609,36 @@ describe('InputPrompt', () => {
|
|
|
579
609
|
mockBuffer.cursor = [0, 11];
|
|
580
610
|
mockBuffer.lines = ['first line\\'];
|
|
581
611
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
582
|
-
await
|
|
583
|
-
|
|
584
|
-
|
|
612
|
+
await act(async () => {
|
|
613
|
+
stdin.write('\r');
|
|
614
|
+
});
|
|
615
|
+
await vi.waitFor(() => {
|
|
616
|
+
expect(props.buffer.backspace).toHaveBeenCalled();
|
|
617
|
+
expect(props.buffer.newline).toHaveBeenCalled();
|
|
618
|
+
});
|
|
585
619
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
586
|
-
expect(props.buffer.backspace).toHaveBeenCalled();
|
|
587
|
-
expect(props.buffer.newline).toHaveBeenCalled();
|
|
588
620
|
unmount();
|
|
589
621
|
});
|
|
590
622
|
it('should clear the buffer on Ctrl+C if it has text', async () => {
|
|
591
623
|
props.buffer.setText('some text to clear');
|
|
592
624
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
593
|
-
await
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
625
|
+
await act(async () => {
|
|
626
|
+
stdin.write('\x03'); // Ctrl+C character
|
|
627
|
+
});
|
|
628
|
+
await vi.waitFor(() => {
|
|
629
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('');
|
|
630
|
+
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
631
|
+
});
|
|
598
632
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
599
633
|
unmount();
|
|
600
634
|
});
|
|
601
635
|
it('should NOT clear the buffer on Ctrl+C if it is empty', async () => {
|
|
602
636
|
props.buffer.text = '';
|
|
603
637
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
604
|
-
await
|
|
605
|
-
|
|
606
|
-
|
|
638
|
+
await act(async () => {
|
|
639
|
+
stdin.write('\x03'); // Ctrl+C character
|
|
640
|
+
});
|
|
641
|
+
await vi.waitFor(() => { });
|
|
607
642
|
expect(props.buffer.setText).not.toHaveBeenCalled();
|
|
608
643
|
unmount();
|
|
609
644
|
});
|
|
@@ -699,8 +734,9 @@ describe('InputPrompt', () => {
|
|
|
699
734
|
: [],
|
|
700
735
|
});
|
|
701
736
|
const { unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
702
|
-
await
|
|
703
|
-
|
|
737
|
+
await vi.waitFor(() => {
|
|
738
|
+
expect(mockedUseCommandCompletion).toHaveBeenCalledWith(mockBuffer, ['/test/project/src'], path.join('test', 'project', 'src'), mockSlashCommands, mockCommandContext, false, false, expect.any(Object));
|
|
739
|
+
});
|
|
704
740
|
unmount();
|
|
705
741
|
});
|
|
706
742
|
});
|
|
@@ -708,32 +744,38 @@ describe('InputPrompt', () => {
|
|
|
708
744
|
it('should not call buffer.handleInput when vim mode is enabled and vim handles the input', async () => {
|
|
709
745
|
props.vimHandleInput = vi.fn().mockReturnValue(true); // Mock that vim handled it.
|
|
710
746
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
711
|
-
await
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
747
|
+
await act(async () => {
|
|
748
|
+
stdin.write('i');
|
|
749
|
+
});
|
|
750
|
+
await vi.waitFor(() => {
|
|
751
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
752
|
+
});
|
|
715
753
|
expect(mockBuffer.handleInput).not.toHaveBeenCalled();
|
|
716
754
|
unmount();
|
|
717
755
|
});
|
|
718
756
|
it('should call buffer.handleInput when vim mode is enabled but vim does not handle the input', async () => {
|
|
719
757
|
props.vimHandleInput = vi.fn().mockReturnValue(false); // Mock that vim did NOT handle it.
|
|
720
758
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
721
|
-
await
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
759
|
+
await act(async () => {
|
|
760
|
+
stdin.write('i');
|
|
761
|
+
});
|
|
762
|
+
await vi.waitFor(() => {
|
|
763
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
764
|
+
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
765
|
+
});
|
|
726
766
|
unmount();
|
|
727
767
|
});
|
|
728
768
|
it('should call handleInput when vim mode is disabled', async () => {
|
|
729
769
|
// Mock vimHandleInput to return false (vim didn't handle the input)
|
|
730
770
|
props.vimHandleInput = vi.fn().mockReturnValue(false);
|
|
731
771
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
732
|
-
await
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
772
|
+
await act(async () => {
|
|
773
|
+
stdin.write('i');
|
|
774
|
+
});
|
|
775
|
+
await vi.waitFor(() => {
|
|
776
|
+
expect(props.vimHandleInput).toHaveBeenCalled();
|
|
777
|
+
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
778
|
+
});
|
|
737
779
|
unmount();
|
|
738
780
|
});
|
|
739
781
|
});
|
|
@@ -741,21 +783,24 @@ describe('InputPrompt', () => {
|
|
|
741
783
|
it('should handle bracketed paste when not focused', async () => {
|
|
742
784
|
props.focus = false;
|
|
743
785
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
744
|
-
await
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
786
|
+
await act(async () => {
|
|
787
|
+
stdin.write('\x1B[200~pasted text\x1B[201~');
|
|
788
|
+
});
|
|
789
|
+
await vi.waitFor(() => {
|
|
790
|
+
expect(mockBuffer.handleInput).toHaveBeenCalledWith(expect.objectContaining({
|
|
791
|
+
paste: true,
|
|
792
|
+
sequence: 'pasted text',
|
|
793
|
+
}));
|
|
794
|
+
});
|
|
751
795
|
unmount();
|
|
752
796
|
});
|
|
753
797
|
it('should ignore regular keypresses when not focused', async () => {
|
|
754
798
|
props.focus = false;
|
|
755
799
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
756
|
-
await
|
|
757
|
-
|
|
758
|
-
|
|
800
|
+
await act(async () => {
|
|
801
|
+
stdin.write('a');
|
|
802
|
+
});
|
|
803
|
+
await vi.waitFor(() => { });
|
|
759
804
|
expect(mockBuffer.handleInput).not.toHaveBeenCalled();
|
|
760
805
|
unmount();
|
|
761
806
|
});
|
|
@@ -817,9 +862,10 @@ describe('InputPrompt', () => {
|
|
|
817
862
|
mockBuffer.viewportVisualLines = [text];
|
|
818
863
|
mockBuffer.visualCursor = visualCursor;
|
|
819
864
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
820
|
-
await
|
|
821
|
-
|
|
822
|
-
|
|
865
|
+
await vi.waitFor(() => {
|
|
866
|
+
const frame = stdout.lastFrame();
|
|
867
|
+
expect(frame).toContain(expected);
|
|
868
|
+
});
|
|
823
869
|
unmount();
|
|
824
870
|
});
|
|
825
871
|
});
|
|
@@ -863,9 +909,10 @@ describe('InputPrompt', () => {
|
|
|
863
909
|
mockBuffer.visualCursor = visualCursor;
|
|
864
910
|
mockBuffer.visualToLogicalMap = visualToLogicalMap;
|
|
865
911
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
866
|
-
await
|
|
867
|
-
|
|
868
|
-
|
|
912
|
+
await vi.waitFor(() => {
|
|
913
|
+
const frame = stdout.lastFrame();
|
|
914
|
+
expect(frame).toContain(expected);
|
|
915
|
+
});
|
|
869
916
|
unmount();
|
|
870
917
|
});
|
|
871
918
|
it('should display cursor on a blank line in a multiline block', async () => {
|
|
@@ -880,11 +927,12 @@ describe('InputPrompt', () => {
|
|
|
880
927
|
[2, 0],
|
|
881
928
|
];
|
|
882
929
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
883
|
-
await
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
930
|
+
await vi.waitFor(() => {
|
|
931
|
+
const frame = stdout.lastFrame();
|
|
932
|
+
const lines = frame.split('\n');
|
|
933
|
+
// The line with the cursor should just be an inverted space inside the box border
|
|
934
|
+
expect(lines.find((l) => l.includes(chalk.inverse(' ')))).not.toBeUndefined();
|
|
935
|
+
});
|
|
888
936
|
unmount();
|
|
889
937
|
});
|
|
890
938
|
});
|
|
@@ -904,15 +952,16 @@ describe('InputPrompt', () => {
|
|
|
904
952
|
[2, 0], // 'world' is logical line 2, col 0
|
|
905
953
|
];
|
|
906
954
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
907
|
-
await
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
955
|
+
await vi.waitFor(() => {
|
|
956
|
+
const frame = stdout.lastFrame();
|
|
957
|
+
// Check that all lines, including the empty one, are rendered.
|
|
958
|
+
// This implicitly tests that the Box wrapper provides height for the empty line.
|
|
959
|
+
expect(frame).toContain('hello');
|
|
960
|
+
expect(frame).toContain(`world${chalk.inverse(' ')}`);
|
|
961
|
+
const outputLines = frame.split('\n');
|
|
962
|
+
// The number of lines should be 2 for the border plus 3 for the content.
|
|
963
|
+
expect(outputLines.length).toBe(5);
|
|
964
|
+
});
|
|
916
965
|
unmount();
|
|
917
966
|
});
|
|
918
967
|
});
|
|
@@ -932,16 +981,18 @@ describe('InputPrompt', () => {
|
|
|
932
981
|
},
|
|
933
982
|
])('should handle multiline paste $description', async ({ pastedText }) => {
|
|
934
983
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
935
|
-
await wait();
|
|
936
984
|
// Simulate a bracketed paste event from the terminal
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
985
|
+
await act(async () => {
|
|
986
|
+
stdin.write(`\x1b[200~${pastedText}\x1b[201~`);
|
|
987
|
+
});
|
|
988
|
+
await vi.waitFor(() => {
|
|
989
|
+
// Verify that the buffer's handleInput was called once with the full text
|
|
990
|
+
expect(props.buffer.handleInput).toHaveBeenCalledTimes(1);
|
|
991
|
+
expect(props.buffer.handleInput).toHaveBeenCalledWith(expect.objectContaining({
|
|
992
|
+
paste: true,
|
|
993
|
+
sequence: pastedText,
|
|
994
|
+
}));
|
|
995
|
+
});
|
|
945
996
|
unmount();
|
|
946
997
|
});
|
|
947
998
|
});
|
|
@@ -963,11 +1014,13 @@ describe('InputPrompt', () => {
|
|
|
963
1014
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
964
1015
|
await vi.runAllTimersAsync();
|
|
965
1016
|
// Simulate a paste operation (this should set the paste protection)
|
|
966
|
-
act(() => {
|
|
1017
|
+
await act(async () => {
|
|
967
1018
|
stdin.write(`\x1b[200~pasted content\x1b[201~`);
|
|
968
1019
|
});
|
|
969
1020
|
// Simulate an Enter key press immediately after paste
|
|
970
|
-
|
|
1021
|
+
await act(async () => {
|
|
1022
|
+
stdin.write('\r');
|
|
1023
|
+
});
|
|
971
1024
|
await vi.runAllTimersAsync();
|
|
972
1025
|
// Verify that onSubmit was NOT called due to recent paste protection
|
|
973
1026
|
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
@@ -981,7 +1034,7 @@ describe('InputPrompt', () => {
|
|
|
981
1034
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
982
1035
|
await vi.runAllTimersAsync();
|
|
983
1036
|
// Simulate a paste operation (this sets the protection)
|
|
984
|
-
act(() => {
|
|
1037
|
+
await act(async () => {
|
|
985
1038
|
stdin.write('\x1b[200~pasted text\x1b[201~');
|
|
986
1039
|
});
|
|
987
1040
|
await vi.runAllTimersAsync();
|
|
@@ -990,7 +1043,9 @@ describe('InputPrompt', () => {
|
|
|
990
1043
|
await vi.advanceTimersByTimeAsync(50);
|
|
991
1044
|
});
|
|
992
1045
|
// Now Enter should work normally
|
|
993
|
-
|
|
1046
|
+
await act(async () => {
|
|
1047
|
+
stdin.write('\r');
|
|
1048
|
+
});
|
|
994
1049
|
await vi.runAllTimersAsync();
|
|
995
1050
|
expect(props.onSubmit).toHaveBeenCalledWith('pasted text');
|
|
996
1051
|
expect(props.buffer.newline).not.toHaveBeenCalled();
|
|
@@ -1011,10 +1066,14 @@ describe('InputPrompt', () => {
|
|
|
1011
1066
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: true });
|
|
1012
1067
|
await vi.runAllTimersAsync();
|
|
1013
1068
|
// Simulate a paste operation
|
|
1014
|
-
|
|
1069
|
+
await act(async () => {
|
|
1070
|
+
stdin.write('\x1b[200~some pasted stuff\x1b[201~');
|
|
1071
|
+
});
|
|
1015
1072
|
await vi.runAllTimersAsync();
|
|
1016
1073
|
// Simulate an Enter key press immediately after paste
|
|
1017
|
-
|
|
1074
|
+
await act(async () => {
|
|
1075
|
+
stdin.write('\r');
|
|
1076
|
+
});
|
|
1018
1077
|
await vi.runAllTimersAsync();
|
|
1019
1078
|
// Verify that onSubmit was called
|
|
1020
1079
|
expect(props.onSubmit).toHaveBeenCalledWith('pasted command');
|
|
@@ -1026,7 +1085,9 @@ describe('InputPrompt', () => {
|
|
|
1026
1085
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1027
1086
|
await vi.runAllTimersAsync();
|
|
1028
1087
|
// Press Enter without any recent paste
|
|
1029
|
-
|
|
1088
|
+
await act(async () => {
|
|
1089
|
+
stdin.write('\r');
|
|
1090
|
+
});
|
|
1030
1091
|
await vi.runAllTimersAsync();
|
|
1031
1092
|
// Verify that onSubmit was called normally
|
|
1032
1093
|
expect(props.onSubmit).toHaveBeenCalledWith('normal command');
|
|
@@ -1039,13 +1100,19 @@ describe('InputPrompt', () => {
|
|
|
1039
1100
|
props.onEscapePromptChange = onEscapePromptChange;
|
|
1040
1101
|
props.buffer.setText('text to clear');
|
|
1041
1102
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1042
|
-
await
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1103
|
+
await act(async () => {
|
|
1104
|
+
stdin.write('\x1B');
|
|
1105
|
+
});
|
|
1106
|
+
await vi.waitFor(() => {
|
|
1107
|
+
expect(onEscapePromptChange).toHaveBeenCalledWith(true);
|
|
1108
|
+
});
|
|
1109
|
+
await act(async () => {
|
|
1110
|
+
stdin.write('\x1B');
|
|
1111
|
+
});
|
|
1112
|
+
await vi.waitFor(() => {
|
|
1113
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('');
|
|
1114
|
+
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
1115
|
+
});
|
|
1049
1116
|
unmount();
|
|
1050
1117
|
});
|
|
1051
1118
|
it('should reset escape state on any non-ESC key', async () => {
|
|
@@ -1053,12 +1120,16 @@ describe('InputPrompt', () => {
|
|
|
1053
1120
|
props.onEscapePromptChange = onEscapePromptChange;
|
|
1054
1121
|
props.buffer.setText('some text');
|
|
1055
1122
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1056
|
-
|
|
1057
|
-
|
|
1123
|
+
await act(async () => {
|
|
1124
|
+
stdin.write('\x1B');
|
|
1125
|
+
});
|
|
1126
|
+
await vi.waitFor(() => {
|
|
1058
1127
|
expect(onEscapePromptChange).toHaveBeenCalledWith(true);
|
|
1059
1128
|
});
|
|
1060
|
-
|
|
1061
|
-
|
|
1129
|
+
await act(async () => {
|
|
1130
|
+
stdin.write('a');
|
|
1131
|
+
});
|
|
1132
|
+
await vi.waitFor(() => {
|
|
1062
1133
|
expect(onEscapePromptChange).toHaveBeenCalledWith(false);
|
|
1063
1134
|
});
|
|
1064
1135
|
unmount();
|
|
@@ -1066,10 +1137,10 @@ describe('InputPrompt', () => {
|
|
|
1066
1137
|
it('should handle ESC in shell mode by disabling shell mode', async () => {
|
|
1067
1138
|
props.shellModeActive = true;
|
|
1068
1139
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1069
|
-
await
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
expect(props.setShellModeActive).toHaveBeenCalledWith(false);
|
|
1140
|
+
await act(async () => {
|
|
1141
|
+
stdin.write('\x1B');
|
|
1142
|
+
});
|
|
1143
|
+
await vi.waitFor(() => expect(props.setShellModeActive).toHaveBeenCalledWith(false));
|
|
1073
1144
|
unmount();
|
|
1074
1145
|
});
|
|
1075
1146
|
it('should handle ESC when completion suggestions are showing', async () => {
|
|
@@ -1079,10 +1150,10 @@ describe('InputPrompt', () => {
|
|
|
1079
1150
|
suggestions: [{ label: 'suggestion', value: 'suggestion' }],
|
|
1080
1151
|
});
|
|
1081
1152
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1082
|
-
await
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled();
|
|
1153
|
+
await act(async () => {
|
|
1154
|
+
stdin.write('\x1B');
|
|
1155
|
+
});
|
|
1156
|
+
await vi.waitFor(() => expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled());
|
|
1086
1157
|
unmount();
|
|
1087
1158
|
});
|
|
1088
1159
|
it('should not call onEscapePromptChange when not provided', async () => {
|
|
@@ -1091,20 +1162,23 @@ describe('InputPrompt', () => {
|
|
|
1091
1162
|
props.buffer.setText('some text');
|
|
1092
1163
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1093
1164
|
await vi.runAllTimersAsync();
|
|
1094
|
-
|
|
1165
|
+
await act(async () => {
|
|
1166
|
+
stdin.write('\x1B');
|
|
1167
|
+
});
|
|
1095
1168
|
await vi.runAllTimersAsync();
|
|
1096
1169
|
vi.useRealTimers();
|
|
1097
1170
|
unmount();
|
|
1098
1171
|
});
|
|
1099
1172
|
it('should not interfere with existing keyboard shortcuts', async () => {
|
|
1100
1173
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), { kittyProtocolEnabled: false });
|
|
1101
|
-
await
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
expect(props.onClearScreen).toHaveBeenCalled();
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1174
|
+
await act(async () => {
|
|
1175
|
+
stdin.write('\x0C');
|
|
1176
|
+
});
|
|
1177
|
+
await vi.waitFor(() => expect(props.onClearScreen).toHaveBeenCalled());
|
|
1178
|
+
await act(async () => {
|
|
1179
|
+
stdin.write('\x01');
|
|
1180
|
+
});
|
|
1181
|
+
await vi.waitFor(() => expect(props.buffer.move).toHaveBeenCalledWith('home'));
|
|
1108
1182
|
unmount();
|
|
1109
1183
|
});
|
|
1110
1184
|
});
|
|
@@ -1132,12 +1206,11 @@ describe('InputPrompt', () => {
|
|
|
1132
1206
|
activeSuggestionIndex: 0,
|
|
1133
1207
|
});
|
|
1134
1208
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1135
|
-
await wait();
|
|
1136
1209
|
// Trigger reverse search with Ctrl+R
|
|
1137
|
-
act(() => {
|
|
1210
|
+
await act(async () => {
|
|
1138
1211
|
stdin.write('\x12');
|
|
1139
1212
|
});
|
|
1140
|
-
await waitFor(() => {
|
|
1213
|
+
await vi.waitFor(() => {
|
|
1141
1214
|
const frame = stdout.lastFrame();
|
|
1142
1215
|
expect(frame).toContain('(r:)');
|
|
1143
1216
|
expect(frame).toContain('echo hello');
|
|
@@ -1148,12 +1221,17 @@ describe('InputPrompt', () => {
|
|
|
1148
1221
|
});
|
|
1149
1222
|
it('resets reverse search state on Escape', async () => {
|
|
1150
1223
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1151
|
-
await
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1224
|
+
await act(async () => {
|
|
1225
|
+
stdin.write('\x12');
|
|
1226
|
+
});
|
|
1227
|
+
await vi.waitFor(() => { });
|
|
1228
|
+
await act(async () => {
|
|
1229
|
+
stdin.write('\x1B');
|
|
1230
|
+
});
|
|
1231
|
+
await act(async () => {
|
|
1232
|
+
stdin.write('\u001b[27u'); // Press kitty escape key
|
|
1233
|
+
});
|
|
1234
|
+
await vi.waitFor(() => {
|
|
1157
1235
|
expect(stdout.lastFrame()).not.toContain('(r:)');
|
|
1158
1236
|
});
|
|
1159
1237
|
expect(stdout.lastFrame()).not.toContain('echo hello');
|
|
@@ -1179,20 +1257,21 @@ describe('InputPrompt', () => {
|
|
|
1179
1257
|
}));
|
|
1180
1258
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1181
1259
|
// Enter reverse search mode with Ctrl+R
|
|
1182
|
-
act(() => {
|
|
1260
|
+
await act(async () => {
|
|
1183
1261
|
stdin.write('\x12');
|
|
1184
1262
|
});
|
|
1185
1263
|
// Verify reverse search is active
|
|
1186
|
-
await waitFor(() => {
|
|
1264
|
+
await vi.waitFor(() => {
|
|
1187
1265
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1188
1266
|
});
|
|
1189
1267
|
// Press Tab to complete the highlighted entry
|
|
1190
|
-
act(() => {
|
|
1268
|
+
await act(async () => {
|
|
1191
1269
|
stdin.write('\t');
|
|
1192
1270
|
});
|
|
1193
|
-
await
|
|
1194
|
-
|
|
1195
|
-
|
|
1271
|
+
await vi.waitFor(() => {
|
|
1272
|
+
expect(mockHandleAutocomplete).toHaveBeenCalledWith(0);
|
|
1273
|
+
expect(props.buffer.setText).toHaveBeenCalledWith('echo hello');
|
|
1274
|
+
});
|
|
1196
1275
|
unmount();
|
|
1197
1276
|
}, 15000);
|
|
1198
1277
|
it('submits the highlighted entry on Enter and exits reverse-search', async () => {
|
|
@@ -1208,16 +1287,16 @@ describe('InputPrompt', () => {
|
|
|
1208
1287
|
activeSuggestionIndex: 0,
|
|
1209
1288
|
});
|
|
1210
1289
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1211
|
-
act(() => {
|
|
1290
|
+
await act(async () => {
|
|
1212
1291
|
stdin.write('\x12');
|
|
1213
1292
|
});
|
|
1214
|
-
await waitFor(() => {
|
|
1293
|
+
await vi.waitFor(() => {
|
|
1215
1294
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1216
1295
|
});
|
|
1217
|
-
act(() => {
|
|
1296
|
+
await act(async () => {
|
|
1218
1297
|
stdin.write('\r');
|
|
1219
1298
|
});
|
|
1220
|
-
await waitFor(() => {
|
|
1299
|
+
await vi.waitFor(() => {
|
|
1221
1300
|
expect(stdout.lastFrame()).not.toContain('(r:)');
|
|
1222
1301
|
});
|
|
1223
1302
|
expect(props.onSubmit).toHaveBeenCalledWith('echo hello');
|
|
@@ -1237,19 +1316,18 @@ describe('InputPrompt', () => {
|
|
|
1237
1316
|
showSuggestions: reverseSearchActiveFromInputPrompt,
|
|
1238
1317
|
}));
|
|
1239
1318
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1240
|
-
await wait();
|
|
1241
1319
|
// reverse search with Ctrl+R
|
|
1242
|
-
act(() => {
|
|
1320
|
+
await act(async () => {
|
|
1243
1321
|
stdin.write('\x12');
|
|
1244
1322
|
});
|
|
1245
|
-
await waitFor(() => {
|
|
1323
|
+
await vi.waitFor(() => {
|
|
1246
1324
|
expect(stdout.lastFrame()).toContain('(r:)');
|
|
1247
1325
|
});
|
|
1248
1326
|
// Press kitty escape key
|
|
1249
|
-
act(() => {
|
|
1327
|
+
await act(async () => {
|
|
1250
1328
|
stdin.write('\u001b[27u');
|
|
1251
1329
|
});
|
|
1252
|
-
await waitFor(() => {
|
|
1330
|
+
await vi.waitFor(() => {
|
|
1253
1331
|
expect(stdout.lastFrame()).not.toContain('(r:)');
|
|
1254
1332
|
expect(props.buffer.text).toBe(initialText);
|
|
1255
1333
|
expect(props.buffer.cursor).toEqual(initialCursor);
|
|
@@ -1263,10 +1341,12 @@ describe('InputPrompt', () => {
|
|
|
1263
1341
|
props.buffer.cursor = [1, 2];
|
|
1264
1342
|
props.buffer.lines = ['line 1', 'line 2', 'line 3'];
|
|
1265
1343
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1266
|
-
await
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1344
|
+
await act(async () => {
|
|
1345
|
+
stdin.write('\x05'); // Ctrl+E
|
|
1346
|
+
});
|
|
1347
|
+
await vi.waitFor(() => {
|
|
1348
|
+
expect(props.buffer.move).toHaveBeenCalledWith('end');
|
|
1349
|
+
});
|
|
1270
1350
|
expect(props.buffer.moveToOffset).not.toHaveBeenCalled();
|
|
1271
1351
|
unmount();
|
|
1272
1352
|
});
|
|
@@ -1275,10 +1355,12 @@ describe('InputPrompt', () => {
|
|
|
1275
1355
|
props.buffer.cursor = [0, 5];
|
|
1276
1356
|
props.buffer.lines = ['single line text'];
|
|
1277
1357
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1278
|
-
await
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1358
|
+
await act(async () => {
|
|
1359
|
+
stdin.write('\x05'); // Ctrl+E
|
|
1360
|
+
});
|
|
1361
|
+
await vi.waitFor(() => {
|
|
1362
|
+
expect(props.buffer.move).toHaveBeenCalledWith('end');
|
|
1363
|
+
});
|
|
1282
1364
|
expect(props.buffer.moveToOffset).not.toHaveBeenCalled();
|
|
1283
1365
|
unmount();
|
|
1284
1366
|
});
|
|
@@ -1298,15 +1380,15 @@ describe('InputPrompt', () => {
|
|
|
1298
1380
|
activeSuggestionIndex: isActive ? 0 : -1,
|
|
1299
1381
|
}));
|
|
1300
1382
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1301
|
-
await
|
|
1302
|
-
act(() => {
|
|
1383
|
+
await act(async () => {
|
|
1303
1384
|
stdin.write('\x12'); // Ctrl+R
|
|
1304
1385
|
});
|
|
1305
|
-
await
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1386
|
+
await vi.waitFor(() => {
|
|
1387
|
+
const frame = stdout.lastFrame() ?? '';
|
|
1388
|
+
expect(frame).toContain('(r:)');
|
|
1389
|
+
expect(frame).toContain('git commit');
|
|
1390
|
+
expect(frame).toContain('git push');
|
|
1391
|
+
});
|
|
1310
1392
|
unmount();
|
|
1311
1393
|
});
|
|
1312
1394
|
it('expands and collapses long suggestion via Right/Left arrows', async () => {
|
|
@@ -1321,18 +1403,26 @@ describe('InputPrompt', () => {
|
|
|
1321
1403
|
isLoadingSuggestions: false,
|
|
1322
1404
|
});
|
|
1323
1405
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1324
|
-
await
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
await
|
|
1334
|
-
|
|
1335
|
-
|
|
1406
|
+
await act(async () => {
|
|
1407
|
+
stdin.write('\x12');
|
|
1408
|
+
});
|
|
1409
|
+
await vi.waitFor(() => {
|
|
1410
|
+
expect(clean(stdout.lastFrame())).toContain('→');
|
|
1411
|
+
});
|
|
1412
|
+
await act(async () => {
|
|
1413
|
+
stdin.write('\u001B[C');
|
|
1414
|
+
});
|
|
1415
|
+
await vi.waitFor(() => {
|
|
1416
|
+
expect(clean(stdout.lastFrame())).toContain('←');
|
|
1417
|
+
});
|
|
1418
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-expanded-match');
|
|
1419
|
+
await act(async () => {
|
|
1420
|
+
stdin.write('\u001B[D');
|
|
1421
|
+
});
|
|
1422
|
+
await vi.waitFor(() => {
|
|
1423
|
+
expect(clean(stdout.lastFrame())).toContain('→');
|
|
1424
|
+
});
|
|
1425
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-collapsed-match');
|
|
1336
1426
|
unmount();
|
|
1337
1427
|
});
|
|
1338
1428
|
it('renders match window and expanded view (snapshots)', async () => {
|
|
@@ -1349,13 +1439,18 @@ describe('InputPrompt', () => {
|
|
|
1349
1439
|
isLoadingSuggestions: false,
|
|
1350
1440
|
});
|
|
1351
1441
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1352
|
-
await
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1442
|
+
await act(async () => {
|
|
1443
|
+
stdin.write('\x12');
|
|
1444
|
+
});
|
|
1445
|
+
await vi.waitFor(() => {
|
|
1446
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-collapsed-match');
|
|
1447
|
+
});
|
|
1448
|
+
await act(async () => {
|
|
1449
|
+
stdin.write('\u001B[C');
|
|
1450
|
+
});
|
|
1451
|
+
await vi.waitFor(() => {
|
|
1452
|
+
expect(stdout.lastFrame()).toMatchSnapshot('command-search-render-expanded-match');
|
|
1453
|
+
});
|
|
1359
1454
|
unmount();
|
|
1360
1455
|
});
|
|
1361
1456
|
it('does not show expand/collapse indicator for short suggestions', async () => {
|
|
@@ -1370,12 +1465,16 @@ describe('InputPrompt', () => {
|
|
|
1370
1465
|
isLoadingSuggestions: false,
|
|
1371
1466
|
});
|
|
1372
1467
|
const { stdin, stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1373
|
-
await
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1468
|
+
await act(async () => {
|
|
1469
|
+
stdin.write('\x12');
|
|
1470
|
+
});
|
|
1471
|
+
await vi.waitFor(() => {
|
|
1472
|
+
const frame = clean(stdout.lastFrame());
|
|
1473
|
+
// Ensure it rendered the search mode
|
|
1474
|
+
expect(frame).toContain('(r:)');
|
|
1475
|
+
expect(frame).not.toContain('→');
|
|
1476
|
+
expect(frame).not.toContain('←');
|
|
1477
|
+
});
|
|
1379
1478
|
unmount();
|
|
1380
1479
|
});
|
|
1381
1480
|
});
|
|
@@ -1385,12 +1484,12 @@ describe('InputPrompt', () => {
|
|
|
1385
1484
|
props.popAllMessages = mockPopAllMessages;
|
|
1386
1485
|
props.buffer.text = '';
|
|
1387
1486
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1388
|
-
await
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1487
|
+
await act(async () => {
|
|
1488
|
+
stdin.write('\u001B[A');
|
|
1489
|
+
});
|
|
1490
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1392
1491
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1393
|
-
act(() => {
|
|
1492
|
+
await act(async () => {
|
|
1394
1493
|
callback('Message 1\n\nMessage 2\n\nMessage 3');
|
|
1395
1494
|
});
|
|
1396
1495
|
expect(props.buffer.setText).toHaveBeenCalledWith('Message 1\n\nMessage 2\n\nMessage 3');
|
|
@@ -1401,11 +1500,11 @@ describe('InputPrompt', () => {
|
|
|
1401
1500
|
props.popAllMessages = mockPopAllMessages;
|
|
1402
1501
|
props.buffer.text = 'some text';
|
|
1403
1502
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1404
|
-
await
|
|
1405
|
-
|
|
1406
|
-
|
|
1503
|
+
await act(async () => {
|
|
1504
|
+
stdin.write('\u001B[A');
|
|
1505
|
+
});
|
|
1506
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
1407
1507
|
expect(mockPopAllMessages).not.toHaveBeenCalled();
|
|
1408
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
1409
1508
|
unmount();
|
|
1410
1509
|
});
|
|
1411
1510
|
it('should handle undefined messages from popAllMessages', async () => {
|
|
@@ -1413,12 +1512,12 @@ describe('InputPrompt', () => {
|
|
|
1413
1512
|
props.popAllMessages = mockPopAllMessages;
|
|
1414
1513
|
props.buffer.text = '';
|
|
1415
1514
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1416
|
-
await
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1515
|
+
await act(async () => {
|
|
1516
|
+
stdin.write('\u001B[A');
|
|
1517
|
+
});
|
|
1518
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1420
1519
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1421
|
-
act(() => {
|
|
1520
|
+
await act(async () => {
|
|
1422
1521
|
callback(undefined);
|
|
1423
1522
|
});
|
|
1424
1523
|
expect(props.buffer.setText).not.toHaveBeenCalled();
|
|
@@ -1433,10 +1532,10 @@ describe('InputPrompt', () => {
|
|
|
1433
1532
|
props.buffer.visualCursor = [0, 0];
|
|
1434
1533
|
props.buffer.visualScrollRow = 0;
|
|
1435
1534
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1436
|
-
await
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1535
|
+
await act(async () => {
|
|
1536
|
+
stdin.write('\u001B[A');
|
|
1537
|
+
});
|
|
1538
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1440
1539
|
unmount();
|
|
1441
1540
|
});
|
|
1442
1541
|
it('should handle single queued message', async () => {
|
|
@@ -1444,11 +1543,12 @@ describe('InputPrompt', () => {
|
|
|
1444
1543
|
props.popAllMessages = mockPopAllMessages;
|
|
1445
1544
|
props.buffer.text = '';
|
|
1446
1545
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1447
|
-
await
|
|
1448
|
-
|
|
1449
|
-
|
|
1546
|
+
await act(async () => {
|
|
1547
|
+
stdin.write('\u001B[A');
|
|
1548
|
+
});
|
|
1549
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1450
1550
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1451
|
-
act(() => {
|
|
1551
|
+
await act(async () => {
|
|
1452
1552
|
callback('Single message');
|
|
1453
1553
|
});
|
|
1454
1554
|
expect(props.buffer.setText).toHaveBeenCalledWith('Single message');
|
|
@@ -1459,20 +1559,20 @@ describe('InputPrompt', () => {
|
|
|
1459
1559
|
props.popAllMessages = mockPopAllMessages;
|
|
1460
1560
|
props.buffer.text = ' '; // Whitespace only
|
|
1461
1561
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1462
|
-
await
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1562
|
+
await act(async () => {
|
|
1563
|
+
stdin.write('\u001B[A');
|
|
1564
|
+
});
|
|
1565
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1466
1566
|
unmount();
|
|
1467
1567
|
});
|
|
1468
1568
|
it('should not call popAllMessages if it is not provided', async () => {
|
|
1469
1569
|
props.popAllMessages = undefined;
|
|
1470
1570
|
props.buffer.text = '';
|
|
1471
1571
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1472
|
-
await
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
1572
|
+
await act(async () => {
|
|
1573
|
+
stdin.write('\u001B[A');
|
|
1574
|
+
});
|
|
1575
|
+
await vi.waitFor(() => expect(mockInputHistory.navigateUp).toHaveBeenCalled());
|
|
1476
1576
|
unmount();
|
|
1477
1577
|
});
|
|
1478
1578
|
it('should navigate input history on fresh start when no queued messages exist', async () => {
|
|
@@ -1480,12 +1580,12 @@ describe('InputPrompt', () => {
|
|
|
1480
1580
|
props.popAllMessages = mockPopAllMessages;
|
|
1481
1581
|
props.buffer.text = '';
|
|
1482
1582
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1483
|
-
await
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
expect(mockPopAllMessages).toHaveBeenCalled();
|
|
1583
|
+
await act(async () => {
|
|
1584
|
+
stdin.write('\u001B[A');
|
|
1585
|
+
});
|
|
1586
|
+
await vi.waitFor(() => expect(mockPopAllMessages).toHaveBeenCalled());
|
|
1487
1587
|
const callback = mockPopAllMessages.mock.calls[0][0];
|
|
1488
|
-
act(() => {
|
|
1588
|
+
await act(async () => {
|
|
1489
1589
|
callback(undefined);
|
|
1490
1590
|
});
|
|
1491
1591
|
expect(mockInputHistory.navigateUp).toHaveBeenCalled();
|
|
@@ -1497,33 +1597,31 @@ describe('InputPrompt', () => {
|
|
|
1497
1597
|
it('should render correctly in shell mode', async () => {
|
|
1498
1598
|
props.shellModeActive = true;
|
|
1499
1599
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1500
|
-
await
|
|
1501
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1600
|
+
await vi.waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1502
1601
|
unmount();
|
|
1503
1602
|
});
|
|
1504
1603
|
it('should render correctly when accepting edits', async () => {
|
|
1505
1604
|
props.approvalMode = ApprovalMode.AUTO_EDIT;
|
|
1506
1605
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1507
|
-
await
|
|
1508
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1606
|
+
await vi.waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1509
1607
|
unmount();
|
|
1510
1608
|
});
|
|
1511
1609
|
it('should render correctly in yolo mode', async () => {
|
|
1512
1610
|
props.approvalMode = ApprovalMode.YOLO;
|
|
1513
1611
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1514
|
-
await
|
|
1515
|
-
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1612
|
+
await vi.waitFor(() => expect(stdout.lastFrame()).toMatchSnapshot());
|
|
1516
1613
|
unmount();
|
|
1517
1614
|
});
|
|
1518
1615
|
it('should not show inverted cursor when shell is focused', async () => {
|
|
1519
1616
|
props.isEmbeddedShellFocused = true;
|
|
1520
1617
|
props.focus = false;
|
|
1521
1618
|
const { stdout, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1522
|
-
await
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1619
|
+
await vi.waitFor(() => {
|
|
1620
|
+
expect(stdout.lastFrame()).not.toContain(`{chalk.inverse(' ')}`);
|
|
1621
|
+
// This snapshot is good to make sure there was an input prompt but does
|
|
1622
|
+
// not show the inverted cursor because snapshots do not show colors.
|
|
1623
|
+
expect(stdout.lastFrame()).toMatchSnapshot();
|
|
1624
|
+
});
|
|
1527
1625
|
unmount();
|
|
1528
1626
|
});
|
|
1529
1627
|
});
|
|
@@ -1531,10 +1629,10 @@ describe('InputPrompt', () => {
|
|
|
1531
1629
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }), {
|
|
1532
1630
|
shellFocus: false,
|
|
1533
1631
|
});
|
|
1534
|
-
await
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
expect(mockBuffer.handleInput).toHaveBeenCalled();
|
|
1632
|
+
await act(async () => {
|
|
1633
|
+
stdin.write('a');
|
|
1634
|
+
});
|
|
1635
|
+
await vi.waitFor(() => expect(mockBuffer.handleInput).toHaveBeenCalled());
|
|
1538
1636
|
unmount();
|
|
1539
1637
|
});
|
|
1540
1638
|
describe('command queuing while streaming', () => {
|
|
@@ -1569,17 +1667,19 @@ describe('InputPrompt', () => {
|
|
|
1569
1667
|
props.buffer.text = bufferText;
|
|
1570
1668
|
props.shellModeActive = shellMode;
|
|
1571
1669
|
const { stdin, unmount } = renderWithProviders(_jsx(InputPrompt, { ...props }));
|
|
1572
|
-
await
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1670
|
+
await act(async () => {
|
|
1671
|
+
stdin.write('\r');
|
|
1672
|
+
});
|
|
1673
|
+
await vi.waitFor(() => {
|
|
1674
|
+
if (shouldSubmit) {
|
|
1675
|
+
expect(props.onSubmit).toHaveBeenCalledWith(bufferText);
|
|
1676
|
+
expect(props.setQueueErrorMessage).not.toHaveBeenCalled();
|
|
1677
|
+
}
|
|
1678
|
+
else {
|
|
1679
|
+
expect(props.onSubmit).not.toHaveBeenCalled();
|
|
1680
|
+
expect(props.setQueueErrorMessage).toHaveBeenCalledWith(errorMessage);
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1583
1683
|
unmount();
|
|
1584
1684
|
});
|
|
1585
1685
|
});
|