mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 21:03:05 -07:00
Improve code coverage for cli/src/ui/privacy package (#13493)
This commit is contained in:
@@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render } from '../../test-utils/render.js';
|
||||||
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||||
|
import { CloudFreePrivacyNotice } from './CloudFreePrivacyNotice.js';
|
||||||
|
import { usePrivacySettings } from '../hooks/usePrivacySettings.js';
|
||||||
|
import { useKeypress } from '../hooks/useKeypress.js';
|
||||||
|
import type { Config } from '@google/gemini-cli-core';
|
||||||
|
import { RadioButtonSelect } from '../components/shared/RadioButtonSelect.js';
|
||||||
|
|
||||||
|
// Mocks
|
||||||
|
vi.mock('../hooks/usePrivacySettings.js', () => ({
|
||||||
|
usePrivacySettings: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('../components/shared/RadioButtonSelect.js', () => ({
|
||||||
|
RadioButtonSelect: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('../hooks/useKeypress.js', () => ({
|
||||||
|
useKeypress: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockedUsePrivacySettings = usePrivacySettings as Mock;
|
||||||
|
const mockedUseKeypress = useKeypress as Mock;
|
||||||
|
const mockedRadioButtonSelect = RadioButtonSelect as Mock;
|
||||||
|
|
||||||
|
describe('CloudFreePrivacyNotice', () => {
|
||||||
|
const mockConfig = {} as Config;
|
||||||
|
const onExit = vi.fn();
|
||||||
|
const updateDataCollectionOptIn = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetAllMocks();
|
||||||
|
mockedUsePrivacySettings.mockReturnValue({
|
||||||
|
privacyState: {
|
||||||
|
isLoading: false,
|
||||||
|
error: undefined,
|
||||||
|
isFreeTier: true,
|
||||||
|
dataCollectionOptIn: undefined,
|
||||||
|
},
|
||||||
|
updateDataCollectionOptIn,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
isLoading: false,
|
||||||
|
error: undefined,
|
||||||
|
isFreeTier: true,
|
||||||
|
dataCollectionOptIn: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
{
|
||||||
|
stateName: 'loading state',
|
||||||
|
mockState: { isLoading: true },
|
||||||
|
expectedText: 'Loading...',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stateName: 'error state',
|
||||||
|
mockState: { error: 'Something went wrong' },
|
||||||
|
expectedText: 'Error loading Opt-in settings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stateName: 'non-free tier state',
|
||||||
|
mockState: { isFreeTier: false },
|
||||||
|
expectedText: 'Gemini Code Assist Privacy Notice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stateName: 'free tier state',
|
||||||
|
mockState: { isFreeTier: true },
|
||||||
|
expectedText: 'Gemini Code Assist for Individuals Privacy Notice',
|
||||||
|
},
|
||||||
|
])('renders correctly in $stateName', ({ mockState, expectedText }) => {
|
||||||
|
mockedUsePrivacySettings.mockReturnValue({
|
||||||
|
privacyState: { ...defaultState, ...mockState },
|
||||||
|
updateDataCollectionOptIn,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { lastFrame } = render(
|
||||||
|
<CloudFreePrivacyNotice config={mockConfig} onExit={onExit} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(lastFrame()).toContain(expectedText);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
{
|
||||||
|
stateName: 'error state',
|
||||||
|
mockState: { error: 'Something went wrong' },
|
||||||
|
shouldExit: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stateName: 'non-free tier state',
|
||||||
|
mockState: { isFreeTier: false },
|
||||||
|
shouldExit: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stateName: 'free tier state (no selection)',
|
||||||
|
mockState: { isFreeTier: true },
|
||||||
|
shouldExit: false,
|
||||||
|
},
|
||||||
|
])(
|
||||||
|
'exits on Escape in $stateName: $shouldExit',
|
||||||
|
({ mockState, shouldExit }) => {
|
||||||
|
mockedUsePrivacySettings.mockReturnValue({
|
||||||
|
privacyState: { ...defaultState, ...mockState },
|
||||||
|
updateDataCollectionOptIn,
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<CloudFreePrivacyNotice config={mockConfig} onExit={onExit} />);
|
||||||
|
|
||||||
|
const keypressHandler = mockedUseKeypress.mock.calls[0][0];
|
||||||
|
keypressHandler({ name: 'escape' });
|
||||||
|
|
||||||
|
if (shouldExit) {
|
||||||
|
expect(onExit).toHaveBeenCalled();
|
||||||
|
} else {
|
||||||
|
expect(onExit).not.toHaveBeenCalled();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('RadioButtonSelect interaction', () => {
|
||||||
|
it.each([
|
||||||
|
{ selection: true, label: 'Yes' },
|
||||||
|
{ selection: false, label: 'No' },
|
||||||
|
])('calls correct functions on selecting "$label"', ({ selection }) => {
|
||||||
|
render(<CloudFreePrivacyNotice config={mockConfig} onExit={onExit} />);
|
||||||
|
|
||||||
|
const onSelectHandler = mockedRadioButtonSelect.mock.calls[0][0].onSelect;
|
||||||
|
onSelectHandler(selection);
|
||||||
|
|
||||||
|
expect(updateDataCollectionOptIn).toHaveBeenCalledWith(selection);
|
||||||
|
expect(onExit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render } from '../../test-utils/render.js';
|
||||||
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||||
|
import { CloudPaidPrivacyNotice } from './CloudPaidPrivacyNotice.js';
|
||||||
|
import { useKeypress } from '../hooks/useKeypress.js';
|
||||||
|
|
||||||
|
// Mocks
|
||||||
|
vi.mock('../hooks/useKeypress.js', () => ({
|
||||||
|
useKeypress: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockedUseKeypress = useKeypress as Mock;
|
||||||
|
|
||||||
|
describe('CloudPaidPrivacyNotice', () => {
|
||||||
|
const onExit = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const { lastFrame } = render(<CloudPaidPrivacyNotice onExit={onExit} />);
|
||||||
|
|
||||||
|
expect(lastFrame()).toContain('Vertex AI Notice');
|
||||||
|
expect(lastFrame()).toContain('Service Specific Terms');
|
||||||
|
expect(lastFrame()).toContain('Press Esc to exit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exits on Escape', () => {
|
||||||
|
render(<CloudPaidPrivacyNotice onExit={onExit} />);
|
||||||
|
|
||||||
|
const keypressHandler = mockedUseKeypress.mock.calls[0][0];
|
||||||
|
keypressHandler({ name: 'escape' });
|
||||||
|
|
||||||
|
expect(onExit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render } from '../../test-utils/render.js';
|
||||||
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||||
|
import { GeminiPrivacyNotice } from './GeminiPrivacyNotice.js';
|
||||||
|
import { useKeypress } from '../hooks/useKeypress.js';
|
||||||
|
|
||||||
|
// Mocks
|
||||||
|
vi.mock('../hooks/useKeypress.js', () => ({
|
||||||
|
useKeypress: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockedUseKeypress = useKeypress as Mock;
|
||||||
|
|
||||||
|
describe('GeminiPrivacyNotice', () => {
|
||||||
|
const onExit = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const { lastFrame } = render(<GeminiPrivacyNotice onExit={onExit} />);
|
||||||
|
|
||||||
|
expect(lastFrame()).toContain('Gemini API Key Notice');
|
||||||
|
expect(lastFrame()).toContain('By using the Gemini API');
|
||||||
|
expect(lastFrame()).toContain('Press Esc to exit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exits on Escape', () => {
|
||||||
|
render(<GeminiPrivacyNotice onExit={onExit} />);
|
||||||
|
|
||||||
|
const keypressHandler = mockedUseKeypress.mock.calls[0][0];
|
||||||
|
keypressHandler({ name: 'escape' });
|
||||||
|
|
||||||
|
expect(onExit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { render } from '../../test-utils/render.js';
|
||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { PrivacyNotice } from './PrivacyNotice.js';
|
||||||
|
import type {
|
||||||
|
AuthType,
|
||||||
|
Config,
|
||||||
|
ContentGeneratorConfig,
|
||||||
|
} from '@google/gemini-cli-core';
|
||||||
|
|
||||||
|
// Mock child components
|
||||||
|
vi.mock('./GeminiPrivacyNotice.js', async () => {
|
||||||
|
const { Text } = await import('ink');
|
||||||
|
return {
|
||||||
|
GeminiPrivacyNotice: () => <Text>GeminiPrivacyNotice</Text>,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock('./CloudPaidPrivacyNotice.js', async () => {
|
||||||
|
const { Text } = await import('ink');
|
||||||
|
return {
|
||||||
|
CloudPaidPrivacyNotice: () => <Text>CloudPaidPrivacyNotice</Text>,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock('./CloudFreePrivacyNotice.js', async () => {
|
||||||
|
const { Text } = await import('ink');
|
||||||
|
return {
|
||||||
|
CloudFreePrivacyNotice: () => <Text>CloudFreePrivacyNotice</Text>,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PrivacyNotice', () => {
|
||||||
|
const onExit = vi.fn();
|
||||||
|
const mockConfig = {
|
||||||
|
getContentGeneratorConfig: vi.fn(),
|
||||||
|
} as unknown as Config;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
{
|
||||||
|
authType: 'gemini-api-key' as AuthType,
|
||||||
|
expectedComponent: 'GeminiPrivacyNotice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
authType: 'vertex-ai' as AuthType,
|
||||||
|
expectedComponent: 'CloudPaidPrivacyNotice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
authType: 'oauth-personal' as AuthType,
|
||||||
|
expectedComponent: 'CloudFreePrivacyNotice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
authType: 'UNKNOWN' as AuthType,
|
||||||
|
expectedComponent: 'CloudFreePrivacyNotice',
|
||||||
|
},
|
||||||
|
])(
|
||||||
|
'renders $expectedComponent when authType is $authType',
|
||||||
|
({ authType, expectedComponent }) => {
|
||||||
|
vi.mocked(mockConfig.getContentGeneratorConfig).mockReturnValue({
|
||||||
|
authType,
|
||||||
|
} as unknown as ContentGeneratorConfig);
|
||||||
|
|
||||||
|
const { lastFrame } = render(
|
||||||
|
<PrivacyNotice config={mockConfig} onExit={onExit} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(lastFrame()).toContain(expectedComponent);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user