feat(ui): align AskUser color scheme with UX spec (#18943)

This commit is contained in:
Jerop Kipruto
2026-02-12 16:10:25 -05:00
committed by GitHub
parent 991b2c6002
commit e8e681c670
3 changed files with 147 additions and 4 deletions

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Box } from 'ink';
import { ToolConfirmationQueue } from './ToolConfirmationQueue.js';
import { ToolCallStatus, StreamingState } from '../types.js';
@@ -12,6 +12,31 @@ import { renderWithProviders } from '../../test-utils/render.js';
import { waitFor } from '../../test-utils/async.js';
import type { Config } from '@google/gemini-cli-core';
import type { ConfirmingToolState } from '../hooks/useConfirmingTool.js';
import { theme } from '../semantic-colors.js';
vi.mock('./StickyHeader.js', async (importOriginal) => {
const actual = await importOriginal<typeof import('./StickyHeader.js')>();
return {
...actual,
StickyHeader: vi.fn((props) => actual.StickyHeader(props)),
};
});
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const actual =
await importOriginal<typeof import('@google/gemini-cli-core')>();
return {
...actual,
validatePlanPath: vi.fn().mockResolvedValue(undefined),
validatePlanContent: vi.fn().mockResolvedValue(undefined),
processSingleFileContent: vi.fn().mockResolvedValue({
llmContent: 'Plan content goes here',
error: undefined,
}),
};
});
const { StickyHeader } = await import('./StickyHeader.js');
describe('ToolConfirmationQueue', () => {
const mockConfig = {
@@ -19,8 +44,19 @@ describe('ToolConfirmationQueue', () => {
getIdeMode: () => false,
getModel: () => 'gemini-pro',
getDebugMode: () => false,
getTargetDir: () => '/mock/target/dir',
getFileSystemService: () => ({
readFile: vi.fn().mockResolvedValue('Plan content'),
}),
storage: {
getProjectTempPlansDir: () => '/mock/temp/plans',
},
} as unknown as Config;
beforeEach(() => {
vi.clearAllMocks();
});
it('renders the confirming tool with progress indicator', () => {
const confirmingTool = {
tool: {
@@ -60,6 +96,9 @@ describe('ToolConfirmationQueue', () => {
expect(output).toContain('list files'); // Tool description
expect(output).toContain("Allow execution of: 'ls'?");
expect(output).toMatchSnapshot();
const stickyHeaderProps = vi.mocked(StickyHeader).mock.calls[0][0];
expect(stickyHeaderProps.borderColor).toBe(theme.status.warning);
});
it('returns null if tool has no confirmation details', () => {
@@ -229,4 +268,80 @@ describe('ToolConfirmationQueue', () => {
expect(output).not.toContain('Press ctrl-o to show more lines');
expect(output).toMatchSnapshot();
});
it('renders AskUser tool confirmation with Success color', () => {
const confirmingTool = {
tool: {
callId: 'call-1',
name: 'ask_user',
description: 'ask user',
status: ToolCallStatus.Confirming,
confirmationDetails: {
type: 'ask_user' as const,
questions: [],
onConfirm: vi.fn(),
},
},
index: 1,
total: 1,
};
const { lastFrame } = renderWithProviders(
<ToolConfirmationQueue
confirmingTool={confirmingTool as unknown as ConfirmingToolState}
/>,
{
config: mockConfig,
uiState: {
terminalWidth: 80,
},
},
);
const output = lastFrame();
expect(output).toMatchSnapshot();
const stickyHeaderProps = vi.mocked(StickyHeader).mock.calls[0][0];
expect(stickyHeaderProps.borderColor).toBe(theme.status.success);
});
it('renders ExitPlanMode tool confirmation with Success color', async () => {
const confirmingTool = {
tool: {
callId: 'call-1',
name: 'exit_plan_mode',
description: 'exit plan mode',
status: ToolCallStatus.Confirming,
confirmationDetails: {
type: 'exit_plan_mode' as const,
planPath: '/path/to/plan',
onConfirm: vi.fn(),
},
},
index: 1,
total: 1,
};
const { lastFrame } = renderWithProviders(
<ToolConfirmationQueue
confirmingTool={confirmingTool as unknown as ConfirmingToolState}
/>,
{
config: mockConfig,
uiState: {
terminalWidth: 80,
},
},
);
await waitFor(() => {
expect(lastFrame()).toContain('Plan content goes here');
});
const output = lastFrame();
expect(output).toMatchSnapshot();
const stickyHeaderProps = vi.mocked(StickyHeader).mock.calls[0][0];
expect(stickyHeaderProps.borderColor).toBe(theme.status.success);
});
});