mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-19 17:50:37 -07:00
Migrate core render util to use xterm.js as part of the rendering loop. (#19044)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { ShellInputPrompt } from './ShellInputPrompt.js';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { ShellExecutionService } from '@google/gemini-cli-core';
|
||||
import { useUIActions, type UIActions } from '../contexts/UIActionsContext.js';
|
||||
|
||||
@@ -46,63 +47,86 @@ describe('ShellInputPrompt', () => {
|
||||
} as Partial<UIActions> as UIActions);
|
||||
});
|
||||
|
||||
it('renders nothing', () => {
|
||||
const { lastFrame } = render(
|
||||
it('renders nothing', async () => {
|
||||
const { lastFrame, waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
expect(lastFrame()).toBe('');
|
||||
await waitUntilReady();
|
||||
expect(lastFrame({ allowEmpty: true })).toBe('');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('sends tab to pty', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
it('sends tab to pty', async () => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({
|
||||
name: 'tab',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: '\t',
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: 'tab',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: '\t',
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockWriteToPty).toHaveBeenCalledWith(1, '\t');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['a', 'a'],
|
||||
['b', 'b'],
|
||||
])('handles keypress input: %s', (name, sequence) => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
])('handles keypress input: %s', async (name, sequence) => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
// Get the registered handler
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
// Simulate keypress
|
||||
handler({
|
||||
name,
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence,
|
||||
await act(async () => {
|
||||
handler({
|
||||
name,
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence,
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockWriteToPty).toHaveBeenCalledWith(1, sequence);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['up', -1],
|
||||
['down', 1],
|
||||
])('handles scroll %s (Command.SCROLL_%s)', (key, direction) => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
])('handles scroll %s (Command.SCROLL_%s)', async (key, direction) => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({ name: key, shift: true, alt: false, ctrl: false, cmd: false });
|
||||
await act(async () => {
|
||||
handler({ name: key, shift: true, alt: false, ctrl: false, cmd: false });
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockScrollPty).toHaveBeenCalledWith(1, direction);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -110,97 +134,140 @@ describe('ShellInputPrompt', () => {
|
||||
['pagedown', 15],
|
||||
])(
|
||||
'handles page scroll %s (Command.PAGE_%s) with default size',
|
||||
(key, expectedScroll) => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
async (key, expectedScroll) => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({ name: key, shift: false, alt: false, ctrl: false, cmd: false });
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: key,
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockScrollPty).toHaveBeenCalledWith(1, expectedScroll);
|
||||
unmount();
|
||||
},
|
||||
);
|
||||
|
||||
it('respects scrollPageSize prop', () => {
|
||||
render(
|
||||
it('respects scrollPageSize prop', async () => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt
|
||||
activeShellPtyId={1}
|
||||
focus={true}
|
||||
scrollPageSize={10}
|
||||
/>,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
// PageDown
|
||||
handler({
|
||||
name: 'pagedown',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: 'pagedown',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
expect(mockScrollPty).toHaveBeenCalledWith(1, 10);
|
||||
|
||||
// PageUp
|
||||
handler({
|
||||
name: 'pageup',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: 'pageup',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
expect(mockScrollPty).toHaveBeenCalledWith(1, -10);
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('does not handle input when not focused', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={false} />);
|
||||
it('does not handle input when not focused', async () => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={false} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({
|
||||
name: 'a',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: 'a',
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: 'a',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: 'a',
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockWriteToPty).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('does not handle input when no active shell', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={null} focus={true} />);
|
||||
it('does not handle input when no active shell', async () => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={null} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
handler({
|
||||
name: 'a',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: 'a',
|
||||
await act(async () => {
|
||||
handler({
|
||||
name: 'a',
|
||||
shift: false,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
sequence: 'a',
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(mockWriteToPty).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('ignores Command.UNFOCUS_SHELL (Shift+Tab) to allow focus navigation', () => {
|
||||
render(<ShellInputPrompt activeShellPtyId={1} focus={true} />);
|
||||
it('ignores Command.UNFOCUS_SHELL (Shift+Tab) to allow focus navigation', async () => {
|
||||
const { waitUntilReady, unmount } = render(
|
||||
<ShellInputPrompt activeShellPtyId={1} focus={true} />,
|
||||
);
|
||||
await waitUntilReady();
|
||||
|
||||
const handler = mockUseKeypress.mock.calls[0][0];
|
||||
|
||||
const result = handler({
|
||||
name: 'tab',
|
||||
shift: true,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
let result: boolean | undefined;
|
||||
await act(async () => {
|
||||
result = handler({
|
||||
name: 'tab',
|
||||
shift: true,
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
cmd: false,
|
||||
});
|
||||
});
|
||||
await waitUntilReady();
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(mockWriteToPty).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user