mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-06 00:52:45 -07:00
fix(cli): resolve btw command truncation in alternate buffer mode
The btw command's response was previously being rendered outside the `ScrollableList` component in `MainContent.tsx`. This caused its output to be severely truncated when the response was lengthy and the user had alternate buffer mode enabled, as the root container restricts height strictly to the terminal lines. This commit incorporates the btw output as a dynamic item inside the `virtualizedData` fed to `ScrollableList` when the alternate buffer is active. This ensures the output is scrollable and not arbitrarily cut off. It also patches `useBtw` to fix a React testing warning regarding `act(...)` updates and a bug where a dismissed btw query could overwrite state if a delayed API callback arrived after dismissal.
This commit is contained in:
committed by
Mahima Shanware
parent
19698ca4ac
commit
ed4c17e03e
@@ -393,6 +393,33 @@ describe('MainContent', () => {
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('renders BtwDisplay within ScrollableList in alternate buffer mode when btw is active', async () => {
|
||||
vi.mocked(useAlternateBuffer).mockReturnValue(true);
|
||||
const uiStateWithBtw = {
|
||||
...defaultMockUiState,
|
||||
btwState: {
|
||||
isActive: true,
|
||||
query: 'test query',
|
||||
response: 'test response',
|
||||
isStreaming: false,
|
||||
error: null,
|
||||
},
|
||||
};
|
||||
const { lastFrame, unmount } = await renderWithProviders(<MainContent />, {
|
||||
uiState: uiStateWithBtw as Partial<UIState>,
|
||||
});
|
||||
const output = lastFrame();
|
||||
// Verify ScrollableList is rendered (from our mock)
|
||||
expect(output).toContain('ScrollableList');
|
||||
// Verify btw response is rendered
|
||||
expect(output).toContain('test query');
|
||||
expect(output).toContain('test response');
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
// Verify it rendered inside ScrollableList's items in the mock
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('renders minimal header in minimal mode (alternate buffer)', async () => {
|
||||
vi.mocked(useAlternateBuffer).mockReturnValue(true);
|
||||
|
||||
|
||||
@@ -92,6 +92,23 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Unc
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`MainContent > renders BtwDisplay within ScrollableList in alternate buffer mode when btw is active 1`] = `
|
||||
"ScrollableList
|
||||
AppHeader(full)
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
> Hello
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||||
✦ Hi there
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ BY THE WAY Press Esc, Enter or Space to dismiss │
|
||||
│ │
|
||||
│ Q: test query │
|
||||
│ │
|
||||
│ test response │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`MainContent > renders a ToolConfirmationQueue without an extra line when preceded by hidden tools 1`] = `
|
||||
"AppHeader(full)
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||
|
||||
@@ -83,8 +83,10 @@ describe('useBtw', () => {
|
||||
useBtw(mockGeminiClient as unknown as GeminiClient),
|
||||
);
|
||||
|
||||
let submitPromise!: Promise<void>;
|
||||
await act(async () => {
|
||||
await result.current.submitBtw('test query');
|
||||
submitPromise = result.current.submitBtw('test query');
|
||||
await submitPromise;
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('API Error');
|
||||
@@ -104,8 +106,10 @@ describe('useBtw', () => {
|
||||
useBtw(mockGeminiClient as unknown as GeminiClient),
|
||||
);
|
||||
|
||||
let submitPromise!: Promise<void>;
|
||||
await act(async () => {
|
||||
await result.current.submitBtw('test query');
|
||||
submitPromise = result.current.submitBtw('test query');
|
||||
await submitPromise;
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Direct string error');
|
||||
@@ -124,8 +128,10 @@ describe('useBtw', () => {
|
||||
useBtw(mockGeminiClient as unknown as GeminiClient),
|
||||
);
|
||||
|
||||
let submitPromise!: Promise<void>;
|
||||
await act(async () => {
|
||||
await result.current.submitBtw('test query');
|
||||
submitPromise = result.current.submitBtw('test query');
|
||||
await submitPromise;
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Unknown error');
|
||||
@@ -144,18 +150,25 @@ describe('useBtw', () => {
|
||||
useBtw(mockGeminiClient as unknown as GeminiClient),
|
||||
);
|
||||
|
||||
let submitPromise!: Promise<void>;
|
||||
await act(async () => {
|
||||
await result.current.submitBtw('test query');
|
||||
submitPromise = result.current.submitBtw('test query');
|
||||
await submitPromise;
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Just some raw string value');
|
||||
});
|
||||
|
||||
it('should reset state on dismiss', async () => {
|
||||
let resolveStream: (value: void) => void;
|
||||
const streamGate = new Promise<void>((resolve) => {
|
||||
resolveStream = resolve;
|
||||
});
|
||||
|
||||
const mockStream = (async function* () {
|
||||
yield { type: GeminiEventType.Content, value: 'partial' };
|
||||
// Hang
|
||||
await new Promise(() => {});
|
||||
await streamGate;
|
||||
})();
|
||||
mockGeminiClient.sendBtwStream.mockReturnValue(mockStream);
|
||||
|
||||
@@ -163,14 +176,23 @@ describe('useBtw', () => {
|
||||
useBtw(mockGeminiClient as unknown as GeminiClient),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
void result.current.submitBtw('test query');
|
||||
let submitPromise!: Promise<void>;
|
||||
await act(async () => {
|
||||
submitPromise = result.current.submitBtw('test query');
|
||||
});
|
||||
|
||||
expect(result.current.isActive).toBe(true);
|
||||
expect(result.current.query).toBe('test query');
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
result.current.dismissBtw();
|
||||
resolveStream();
|
||||
// wait for the catch/finally blocks inside submitBtw to finish
|
||||
try {
|
||||
await submitPromise;
|
||||
} catch (_e) {
|
||||
// ignore AbortError
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.current.isActive).toBe(false);
|
||||
|
||||
@@ -87,6 +87,7 @@ export const useBtw = (
|
||||
abortControllerRef.current.abort();
|
||||
abortControllerRef.current = null;
|
||||
}
|
||||
requestIdRef.current++;
|
||||
dispatch({ type: 'DISMISS' });
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user