mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-27 13:34:15 -07:00
Improve code coverage for cli package (#13724)
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { render } from 'ink-testing-library';
|
||||
import { act } from 'react';
|
||||
import { IdeIntegrationNudge } from './IdeIntegrationNudge.js';
|
||||
import { KeypressProvider } from './contexts/KeypressContext.js';
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
describe('IdeIntegrationNudge', () => {
|
||||
const defaultProps = {
|
||||
ide: {
|
||||
name: 'vscode',
|
||||
displayName: 'VS Code',
|
||||
},
|
||||
onComplete: vi.fn(),
|
||||
};
|
||||
|
||||
const originalError = console.error;
|
||||
|
||||
afterEach(() => {
|
||||
console.error = originalError;
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
console.error = (...args) => {
|
||||
if (
|
||||
typeof args[0] === 'string' &&
|
||||
/was not wrapped in act/.test(args[0])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
originalError.call(console, ...args);
|
||||
};
|
||||
vi.stubEnv('GEMINI_CLI_IDE_SERVER_PORT', '');
|
||||
vi.stubEnv('GEMINI_CLI_IDE_WORKSPACE_PATH', '');
|
||||
});
|
||||
|
||||
it('renders correctly with default options', async () => {
|
||||
const { lastFrame } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
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");
|
||||
});
|
||||
|
||||
it('handles "Yes" selection', async () => {
|
||||
const onComplete = vi.fn();
|
||||
const { stdin } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
// "Yes" is the first option and selected by default usually.
|
||||
await act(async () => {
|
||||
stdin.write('\r');
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith({
|
||||
userSelection: 'yes',
|
||||
isExtensionPreInstalled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('handles "No" selection', async () => {
|
||||
const onComplete = vi.fn();
|
||||
const { stdin } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
// Navigate down to "No (esc)"
|
||||
await act(async () => {
|
||||
stdin.write('\u001B[B'); // Down arrow
|
||||
await delay(100);
|
||||
});
|
||||
await act(async () => {
|
||||
stdin.write('\r'); // Enter
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith({
|
||||
userSelection: 'no',
|
||||
isExtensionPreInstalled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('handles "Dismiss" selection', async () => {
|
||||
const onComplete = vi.fn();
|
||||
const { stdin } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
// Navigate down to "No, don't ask again"
|
||||
await act(async () => {
|
||||
stdin.write('\u001B[B'); // Down arrow
|
||||
await delay(100);
|
||||
});
|
||||
await act(async () => {
|
||||
stdin.write('\u001B[B'); // Down arrow
|
||||
await delay(100);
|
||||
});
|
||||
await act(async () => {
|
||||
stdin.write('\r'); // Enter
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith({
|
||||
userSelection: 'dismiss',
|
||||
isExtensionPreInstalled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('handles Escape key press', async () => {
|
||||
const onComplete = vi.fn();
|
||||
const { stdin } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
// Press Escape
|
||||
await act(async () => {
|
||||
stdin.write('\u001B');
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith({
|
||||
userSelection: 'no',
|
||||
isExtensionPreInstalled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('displays correct text and handles selection when extension is pre-installed', async () => {
|
||||
vi.stubEnv('GEMINI_CLI_IDE_SERVER_PORT', '1234');
|
||||
vi.stubEnv('GEMINI_CLI_IDE_WORKSPACE_PATH', '/tmp');
|
||||
|
||||
const onComplete = vi.fn();
|
||||
const { lastFrame, stdin } = render(
|
||||
<KeypressProvider>
|
||||
<IdeIntegrationNudge {...defaultProps} onComplete={onComplete} />
|
||||
</KeypressProvider>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
const frame = lastFrame();
|
||||
|
||||
expect(frame).toContain(
|
||||
'If you select Yes, the CLI will have access to your open files',
|
||||
);
|
||||
expect(frame).not.toContain("we'll install an extension");
|
||||
|
||||
// Select "Yes"
|
||||
await act(async () => {
|
||||
stdin.write('\r');
|
||||
await delay(100);
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalledWith({
|
||||
userSelection: 'yes',
|
||||
isExtensionPreInstalled: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user