diff --git a/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.test.tsx b/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.test.tsx
new file mode 100644
index 0000000000..e077f64e8e
--- /dev/null
+++ b/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.test.tsx
@@ -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(
+ ,
+ );
+
+ 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();
+
+ 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();
+
+ const onSelectHandler = mockedRadioButtonSelect.mock.calls[0][0].onSelect;
+ onSelectHandler(selection);
+
+ expect(updateDataCollectionOptIn).toHaveBeenCalledWith(selection);
+ expect(onExit).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.test.tsx b/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.test.tsx
new file mode 100644
index 0000000000..0aab0e18c4
--- /dev/null
+++ b/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.test.tsx
@@ -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();
+
+ expect(lastFrame()).toContain('Vertex AI Notice');
+ expect(lastFrame()).toContain('Service Specific Terms');
+ expect(lastFrame()).toContain('Press Esc to exit');
+ });
+
+ it('exits on Escape', () => {
+ render();
+
+ const keypressHandler = mockedUseKeypress.mock.calls[0][0];
+ keypressHandler({ name: 'escape' });
+
+ expect(onExit).toHaveBeenCalled();
+ });
+});
diff --git a/packages/cli/src/ui/privacy/GeminiPrivacyNotice.test.tsx b/packages/cli/src/ui/privacy/GeminiPrivacyNotice.test.tsx
new file mode 100644
index 0000000000..3548aaa615
--- /dev/null
+++ b/packages/cli/src/ui/privacy/GeminiPrivacyNotice.test.tsx
@@ -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();
+
+ 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();
+
+ const keypressHandler = mockedUseKeypress.mock.calls[0][0];
+ keypressHandler({ name: 'escape' });
+
+ expect(onExit).toHaveBeenCalled();
+ });
+});
diff --git a/packages/cli/src/ui/privacy/PrivacyNotice.test.tsx b/packages/cli/src/ui/privacy/PrivacyNotice.test.tsx
new file mode 100644
index 0000000000..c12e5fd622
--- /dev/null
+++ b/packages/cli/src/ui/privacy/PrivacyNotice.test.tsx
@@ -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: () => GeminiPrivacyNotice,
+ };
+});
+
+vi.mock('./CloudPaidPrivacyNotice.js', async () => {
+ const { Text } = await import('ink');
+ return {
+ CloudPaidPrivacyNotice: () => CloudPaidPrivacyNotice,
+ };
+});
+
+vi.mock('./CloudFreePrivacyNotice.js', async () => {
+ const { Text } = await import('ink');
+ return {
+ CloudFreePrivacyNotice: () => CloudFreePrivacyNotice,
+ };
+});
+
+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(
+ ,
+ );
+
+ expect(lastFrame()).toContain(expectedComponent);
+ },
+ );
+});