Migrate core render util to use xterm.js as part of the rendering loop. (#19044)

This commit is contained in:
Jacob Richman
2026-02-18 16:46:50 -08:00
committed by GitHub
parent 04c52513e7
commit 04f65f3d55
213 changed files with 7065 additions and 3852 deletions
@@ -11,8 +11,6 @@ import { IdeIntegrationNudge } from './IdeIntegrationNudge.js';
import { KeypressProvider } from './contexts/KeypressContext.js';
import { debugLogger } from '@google/gemini-cli-core';
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// Mock debugLogger
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const actual =
@@ -56,128 +54,129 @@ describe('IdeIntegrationNudge', () => {
});
it('renders correctly with default options', async () => {
const { lastFrame } = render(
const { lastFrame, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
const frame = lastFrame();
expect(frame).toContain('Do you want to connect VS Code to Gemini CLI?');
expect(frame).toContain('Yes');
expect(frame).toContain('No (esc)');
expect(frame).toContain("No, don't ask again");
unmount();
});
it('handles "Yes" selection', async () => {
const onComplete = vi.fn();
const { stdin } = render(
const { stdin, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
// "Yes" is the first option and selected by default usually.
await act(async () => {
stdin.write('\r');
await delay(100);
});
await waitUntilReady();
expect(onComplete).toHaveBeenCalledWith({
userSelection: 'yes',
isExtensionPreInstalled: false,
});
unmount();
});
it('handles "No" selection', async () => {
const onComplete = vi.fn();
const { stdin } = render(
const { stdin, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
// Navigate down to "No (esc)"
await act(async () => {
stdin.write('\u001B[B'); // Down arrow
await delay(100);
});
await waitUntilReady();
await act(async () => {
stdin.write('\r'); // Enter
await delay(100);
});
await waitUntilReady();
expect(onComplete).toHaveBeenCalledWith({
userSelection: 'no',
isExtensionPreInstalled: false,
});
unmount();
});
it('handles "Dismiss" selection', async () => {
const onComplete = vi.fn();
const { stdin } = render(
const { stdin, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
// Navigate down to "No, don't ask again"
await act(async () => {
stdin.write('\u001B[B'); // Down arrow
await delay(100);
});
await waitUntilReady();
await act(async () => {
stdin.write('\u001B[B'); // Down arrow
await delay(100);
});
await waitUntilReady();
await act(async () => {
stdin.write('\r'); // Enter
await delay(100);
});
await waitUntilReady();
expect(onComplete).toHaveBeenCalledWith({
userSelection: 'dismiss',
isExtensionPreInstalled: false,
});
unmount();
});
it('handles Escape key press', async () => {
const onComplete = vi.fn();
const { stdin } = render(
const { stdin, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
// Press Escape
await act(async () => {
stdin.write('\u001B');
await delay(100);
});
// Escape key has a timeout in KeypressContext, so we need to wrap waitUntilReady in act
await act(async () => {
await waitUntilReady();
});
expect(onComplete).toHaveBeenCalledWith({
userSelection: 'no',
isExtensionPreInstalled: false,
});
unmount();
});
it('displays correct text and handles selection when extension is pre-installed', async () => {
@@ -185,15 +184,13 @@ describe('IdeIntegrationNudge', () => {
vi.stubEnv('GEMINI_CLI_IDE_WORKSPACE_PATH', '/tmp');
const onComplete = vi.fn();
const { lastFrame, stdin } = render(
const { lastFrame, stdin, waitUntilReady, unmount } = render(
<KeypressProvider>
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
</KeypressProvider>,
);
await act(async () => {
await delay(100);
});
await waitUntilReady();
const frame = lastFrame();
@@ -205,12 +202,13 @@ describe('IdeIntegrationNudge', () => {
// Select "Yes"
await act(async () => {
stdin.write('\r');
await delay(100);
});
await waitUntilReady();
expect(onComplete).toHaveBeenCalledWith({
userSelection: 'yes',
isExtensionPreInstalled: true,
});
unmount();
});
});