mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-30 23:14:32 -07:00
feat(cli): overhaul thinking UI (#18725)
This commit is contained in:
@@ -7,84 +7,156 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { renderWithProviders } from '../../../test-utils/render.js';
|
||||
import { ThinkingMessage } from './ThinkingMessage.js';
|
||||
import React from 'react';
|
||||
|
||||
describe('ThinkingMessage', () => {
|
||||
it('renders subject line', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
it('renders subject line with vertical rule and "Thinking..." header', async () => {
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{ subject: 'Planning', description: 'test' }}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain(' Thinking...');
|
||||
expect(output).toContain('│');
|
||||
expect(output).toContain('Planning');
|
||||
expect(output).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('uses description when subject is empty', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{ subject: '', description: 'Processing details' }}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('Processing details');
|
||||
expect(output).toContain('│');
|
||||
expect(output).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders full mode with left border and full text', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Planning',
|
||||
description: 'I am planning the solution.',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain('│');
|
||||
expect(output).toContain('Planning');
|
||||
expect(output).toContain('I am planning the solution.');
|
||||
expect(output).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('indents summary line correctly', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
it('renders "Thinking..." header when isFirstThinking is true', async () => {
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Summary line',
|
||||
description: 'First body line',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
const output = renderResult.lastFrame();
|
||||
expect(output).toContain(' Thinking...');
|
||||
expect(output).toContain('Summary line');
|
||||
expect(output).toContain('│');
|
||||
expect(output).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('normalizes escaped newline tokens', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Matching the Blocks',
|
||||
description: '\\n\\nSome more text',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
expect(renderResult.lastFrame()).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders empty state gracefully', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
|
||||
<ThinkingMessage thought={{ subject: '', description: '' }} />,
|
||||
const renderResult = renderWithProviders(
|
||||
<ThinkingMessage
|
||||
thought={{ subject: '', description: '' }}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(lastFrame({ allowEmpty: true })).toBe('');
|
||||
unmount();
|
||||
expect(renderResult.lastFrame({ allowEmpty: true })).toBe('');
|
||||
renderResult.unmount();
|
||||
});
|
||||
|
||||
it('renders multiple thinking messages sequentially correctly', async () => {
|
||||
const renderResult = renderWithProviders(
|
||||
<React.Fragment>
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Initial analysis',
|
||||
description:
|
||||
'This is a multiple line paragraph for the first thinking message of how the model analyzes the problem.',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
isFirstThinking={true}
|
||||
/>
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Planning execution',
|
||||
description:
|
||||
'This a second multiple line paragraph for the second thinking message explaining the plan in detail so that it wraps around the terminal display.',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
/>
|
||||
<ThinkingMessage
|
||||
thought={{
|
||||
subject: 'Refining approach',
|
||||
description:
|
||||
'And finally a third multiple line paragraph for the third thinking message to refine the solution.',
|
||||
}}
|
||||
terminalWidth={80}
|
||||
/>
|
||||
</React.Fragment>,
|
||||
);
|
||||
await renderResult.waitUntilReady();
|
||||
|
||||
expect(renderResult.lastFrame()).toMatchSnapshot();
|
||||
await expect(renderResult).toMatchSvgSnapshot();
|
||||
renderResult.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user