From aea0d2d0be2ccea827ffad6941ca934763d1adaa Mon Sep 17 00:00:00 2001 From: Keith Guerin Date: Mon, 30 Mar 2026 16:47:03 -0700 Subject: [PATCH] test(cli): update tests to reflect new tips default and fix technical debt --- packages/cli/src/ui/App.test.tsx | 84 +++++++++---------- .../src/ui/__snapshots__/App.test.tsx.snap | 28 +++---- .../cli/src/ui/components/AppHeader.test.tsx | 75 +++++++++++++---- .../__snapshots__/AppHeader.test.tsx.snap | 28 ------- 4 files changed, 113 insertions(+), 102 deletions(-) diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx index f31d656b77..f94ccc07fe 100644 --- a/packages/cli/src/ui/App.test.tsx +++ b/packages/cli/src/ui/App.test.tsx @@ -91,20 +91,40 @@ describe('App', () => { backgroundTasks: new Map(), }; - it('should render main content and composer when not quitting', async () => { - const { lastFrame, unmount } = await renderWithProviders(, { - uiState: mockUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: false, hideTips: false }, - }), - }); + it('should render main content and composer without tips by default', async () => { + const { lastFrame, unmount, waitUntilReady } = await renderWithProviders( + , + { + uiState: mockUIState, + settings: createMockSettings({ + ui: { useAlternateBuffer: false }, + }), + }, + ); + await waitUntilReady(); - expect(lastFrame()).toContain('Tips for getting started'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toContain('Notifications'); expect(lastFrame()).toContain('Composer'); unmount(); }); + it('should render tips when hideTips is explicitly set to false', async () => { + const { lastFrame, unmount, waitUntilReady } = await renderWithProviders( + , + { + uiState: mockUIState, + settings: createMockSettings({ + ui: { useAlternateBuffer: false, hideTips: false }, + }), + }, + ); + await waitUntilReady(); + + expect(lastFrame()).toContain('Tips for getting started'); + unmount(); + }); + it('should render quitting display when quittingMessages is set', async () => { const quittingUIState = { ...mockUIState, @@ -113,9 +133,7 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: quittingUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: false, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: false } }), }); expect(lastFrame()).toContain('Quitting...'); @@ -132,9 +150,7 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: quittingUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toContain('HistoryItemDisplay'); @@ -150,12 +166,10 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: dialogUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); - expect(lastFrame()).toContain('Tips for getting started'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toContain('Notifications'); expect(lastFrame()).toContain('DialogManager'); unmount(); @@ -175,9 +189,7 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toContain(`Press Ctrl+${key} again to exit.`); @@ -190,14 +202,12 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: mockUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toContain('Notifications'); expect(lastFrame()).toContain('Footer'); - expect(lastFrame()).toContain('Tips for getting started'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toContain('Composer'); unmount(); }); @@ -207,12 +217,10 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: mockUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); - expect(lastFrame()).toContain('Tips for getting started'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toContain('Notifications'); expect(lastFrame()).toContain('Composer'); unmount(); @@ -261,12 +269,10 @@ describe('App', () => { const { lastFrame, unmount } = await renderWithProviders(, { uiState: stateWithConfirmingTool, config: configWithExperiment, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); - expect(lastFrame()).toContain('Tips for getting started'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toContain('Notifications'); expect(lastFrame()).toContain('Action Required'); // From ToolConfirmationQueue expect(lastFrame()).toContain('Composer'); @@ -279,9 +285,7 @@ describe('App', () => { (useIsScreenReaderEnabled as Mock).mockReturnValue(false); const { lastFrame, unmount } = await renderWithProviders(, { uiState: mockUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toMatchSnapshot(); unmount(); @@ -291,9 +295,7 @@ describe('App', () => { (useIsScreenReaderEnabled as Mock).mockReturnValue(true); const { lastFrame, unmount } = await renderWithProviders(, { uiState: mockUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toMatchSnapshot(); unmount(); @@ -306,9 +308,7 @@ describe('App', () => { } as UIState; const { lastFrame, unmount } = await renderWithProviders(, { uiState: dialogUIState, - settings: createMockSettings({ - ui: { useAlternateBuffer: true, hideTips: false }, - }), + settings: createMockSettings({ ui: { useAlternateBuffer: true } }), }); expect(lastFrame()).toMatchSnapshot(); unmount(); diff --git a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap index f145eadfff..f84af954f6 100644 --- a/packages/cli/src/ui/__snapshots__/App.test.tsx.snap +++ b/packages/cli/src/ui/__snapshots__/App.test.tsx.snap @@ -11,11 +11,11 @@ exports[`App > Snapshots > renders default layout correctly 1`] = ` -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results + + + + + @@ -55,12 +55,6 @@ Footer Gemini CLI v1.2.3 - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results Composer " `; @@ -118,12 +112,6 @@ exports[`App > should render ToolConfirmationQueue along with Composer when tool Gemini CLI v1.2.3 - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results HistoryItemDisplay ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Action Required │ @@ -145,6 +133,12 @@ HistoryItemDisplay + + + + + + Notifications Composer diff --git a/packages/cli/src/ui/components/AppHeader.test.tsx b/packages/cli/src/ui/components/AppHeader.test.tsx index 03697b1b6d..843dd1527b 100644 --- a/packages/cli/src/ui/components/AppHeader.test.tsx +++ b/packages/cli/src/ui/components/AppHeader.test.tsx @@ -11,7 +11,7 @@ import { import { createMockSettings } from '../../test-utils/settings.js'; import type { LoadedSettings } from '../../config/settings.js'; import { AppHeader } from './AppHeader.js'; -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { makeFakeConfig } from '@google/gemini-cli-core'; import crypto from 'node:crypto'; @@ -20,6 +20,11 @@ vi.mock('../utils/terminalSetup.js', () => ({ })); describe('', () => { + beforeEach(() => { + vi.clearAllMocks(); + persistentStateMock.setData({ tipsShown: undefined }); + }); + it('should render the banner with default text', async () => { const uiState = { history: [], @@ -34,15 +39,36 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); expect(lastFrame()).toContain('This is the default banner'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toMatchSnapshot(); unmount(); }); + it('should render tips when hideTips is explicitly set to false', async () => { + const uiState = { + history: [], + bannerData: { + defaultText: 'This is the default banner', + warningText: '', + }, + bannerVisible: true, + }; + + const { lastFrame, unmount } = await renderWithProviders( + , + { + uiState, + }, + ); + + expect(lastFrame()).not.toContain('Tips for getting started'); + unmount(); + }); + it('should render the banner with warning text', async () => { const uiState = { history: [], @@ -57,11 +83,11 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); expect(lastFrame()).toContain('There are capacity issues'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toMatchSnapshot(); unmount(); }); @@ -79,11 +105,11 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); expect(lastFrame()).not.toContain('Banner'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toMatchSnapshot(); unmount(); }); @@ -110,11 +136,11 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); expect(lastFrame()).not.toContain('This is the default banner'); + expect(lastFrame()).not.toContain('Tips for getting started'); expect(lastFrame()).toMatchSnapshot(); unmount(); }); @@ -128,10 +154,6 @@ describe('', () => { }, }; - // Set tipsShown to 10 or more to prevent Tips from incrementing its count - // and interfering with the expected persistentState.set call. - persistentStateMock.setData({ tipsShown: 10 }); - const { unmount } = await renderWithProviders( , { @@ -165,7 +187,6 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); @@ -173,7 +194,7 @@ describe('', () => { unmount(); }); - it('should render Tips when tipsShown is less than 10', async () => { + it('should render Tips when tipsShown is less than 10 and hideTips is false', async () => { const uiState = { history: [], bannerData: { @@ -198,6 +219,30 @@ describe('', () => { unmount(); }); + it('should NOT render Tips when tipsShown is less than 10 but hideTips is true (default)', async () => { + const uiState = { + history: [], + bannerData: { + defaultText: 'First line\\nSecond line', + warningText: '', + }, + bannerVisible: true, + }; + + persistentStateMock.setData({ tipsShown: 5 }); + + const { lastFrame, unmount } = await renderWithProviders( + , + { + uiState, + }, + ); + + expect(lastFrame()).not.toContain('Tips'); + expect(persistentStateMock.set).not.toHaveBeenCalledWith('tipsShown', 6); + unmount(); + }); + it('should NOT render Tips when tipsShown is 10 or more', async () => { const uiState = { bannerData: { @@ -212,7 +257,6 @@ describe('', () => { , { uiState, - settings: createMockSettings({ ui: { hideTips: false } }), }, ); @@ -221,7 +265,7 @@ describe('', () => { }); it('should show tips until they have been shown 10 times (persistence flow)', async () => { - persistentStateMock.setData({ tipsShown: 9 }); + persistentStateMock.set('tipsShown', 0); const uiState = { history: [], @@ -239,7 +283,7 @@ describe('', () => { }); expect(session1.lastFrame()).toContain('Tips'); - expect(persistentStateMock.get('tipsShown')).toBe(10); + expect(persistentStateMock.get('tipsShown')).toBe(1); session1.unmount(); // Second session - state is persisted in the fake @@ -247,7 +291,8 @@ describe('', () => { settings: createMockSettings({ ui: { hideTips: false } }), }); - expect(session2.lastFrame()).not.toContain('Tips'); + expect(session2.lastFrame()).toContain('Tips'); + expect(persistentStateMock.get('tipsShown')).toBe(2); session2.unmount(); }); diff --git a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap index ee9ea5f708..6de752a92a 100644 --- a/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/AppHeader.test.tsx.snap @@ -8,14 +8,6 @@ exports[` > should not render the banner when no flags are set 1`] ▝▀ ▀▀▀▀▘▝▀▀▀▀▘▀▀▘ ▀▀▘▀▀▘▀▀▘ ▝▀▀▝▀▀ Gemini CLI v1.0.0 - - - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results " `; @@ -27,14 +19,6 @@ exports[` > should not render the default banner if shown count is ▝▀ ▀▀▀▀▘▝▀▀▀▀▘▀▀▘ ▀▀▘▀▀▘▀▀▘ ▝▀▀▝▀▀ Gemini CLI v1.0.0 - - - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results " `; @@ -51,12 +35,6 @@ exports[` > should render the banner with default text 1`] = ` ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ This is the default banner │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results " `; @@ -73,12 +51,6 @@ exports[` > should render the banner with warning text 1`] = ` ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ There are capacity issues │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ - -Tips for getting started: -1. Create GEMINI.md files to customize your interactions -2. /help for more information -3. Ask coding questions, edit code or run commands -4. Be specific for the best results " `;