test(cli): add unit tests for /btw command functionality and components

This commit is contained in:
Mahima Shanware
2026-03-27 18:58:36 +00:00
committed by Mahima Shanware
parent dcde43b031
commit 86487af7ff
4 changed files with 237 additions and 0 deletions
@@ -0,0 +1,38 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { btwCommand } from './btwCommand.js';
import { CommandKind } from './types.js';
import type { CommandContext } from './types.js';
describe('btwCommand', () => {
it('has the correct metadata', () => {
expect(btwCommand.name).toBe('btw');
expect(btwCommand.kind).toBe(CommandKind.BUILT_IN);
expect(btwCommand.autoExecute).toBe(true);
expect(btwCommand.isSafeConcurrent).toBe(true);
});
it('returns an error message when args are empty', () => {
const context = {} as CommandContext;
const result = btwCommand.action!(context, ' ');
expect(result).toEqual({
type: 'message',
messageType: 'error',
content: 'Please provide a question, e.g. /btw what is this regex doing?',
});
});
it('returns a btw action when query is provided', () => {
const context = {} as CommandContext;
const result = btwCommand.action!(context, ' what is this regex doing? ');
expect(result).toEqual({
type: 'btw',
query: 'what is this regex doing?',
});
});
});
@@ -0,0 +1,88 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { renderWithProviders } from '../../test-utils/render.js';
import { BtwDisplay } from './BtwDisplay.js';
import { StreamingState } from '../types.js';
import type { UIState } from '../contexts/UIStateContext.js';
describe('BtwDisplay', () => {
const defaultMockUiState = {
renderMarkdown: true,
} as unknown as Partial<UIState>;
it('renders nothing when query is empty', async () => {
const { lastFrame, unmount } = await renderWithProviders(
<BtwDisplay
query=""
response=""
isStreaming={false}
error={null}
terminalWidth={100}
/>,
{ uiState: defaultMockUiState },
);
expect(lastFrame({ allowEmpty: true })).toBe('');
unmount();
});
it('renders query and response', async () => {
const { lastFrame, unmount } = await renderWithProviders(
<BtwDisplay
query="What is life?"
response="Life is 42."
isStreaming={false}
error={null}
terminalWidth={100}
/>,
{ uiState: defaultMockUiState },
);
const frame = lastFrame();
expect(frame).toContain('What is life?');
expect(frame).toContain('Life is 42.');
expect(frame).toContain('BY THE WAY');
unmount();
});
it('renders error message when error is provided', async () => {
const { lastFrame, unmount } = await renderWithProviders(
<BtwDisplay
query="What is life?"
response="Life is 42."
isStreaming={false}
error="An API error occurred."
terminalWidth={100}
/>,
{ uiState: defaultMockUiState },
);
const frame = lastFrame();
expect(frame).toContain('An API error occurred.');
expect(frame).not.toContain('Life is 42.');
unmount();
});
it('renders a spinner when streaming', async () => {
const { lastFrame, unmount } = await renderWithProviders(
<BtwDisplay
query="What is life?"
response="Life is 42."
isStreaming={true}
error={null}
terminalWidth={100}
/>,
{
uiState: {
...defaultMockUiState,
streamingState: StreamingState.Responding,
},
},
);
const frame = lastFrame();
expect(frame).toContain('⠋'); // Assuming standard spinner frame
unmount();
});
});
@@ -5097,6 +5097,92 @@ describe('InputPrompt', () => {
},
);
});
describe('Btw dismiss behavior', () => {
it('dismisses Btw on ESC key press', async () => {
const dismissBtw = vi.fn();
const { stdin, unmount } = await renderWithProviders(
<InputPrompt {...props} />,
{
uiState: {
btwState: {
isActive: true,
query: '',
response: '',
isStreaming: false,
error: null,
},
},
uiActions: { dismissBtw },
},
);
await act(async () => {
stdin.write('\x1B'); // ESC
});
await waitFor(() => {
expect(dismissBtw).toHaveBeenCalled();
});
unmount();
});
it('dismisses Btw on Enter key press', async () => {
const dismissBtw = vi.fn();
const { stdin, unmount } = await renderWithProviders(
<InputPrompt {...props} />,
{
uiState: {
btwState: {
isActive: true,
query: '',
response: '',
isStreaming: false,
error: null,
},
},
uiActions: { dismissBtw },
},
);
await act(async () => {
stdin.write('\r'); // Enter
});
await waitFor(() => {
expect(dismissBtw).toHaveBeenCalled();
});
unmount();
});
it('dismisses Btw on Space key press when buffer is empty', async () => {
const dismissBtw = vi.fn();
const { stdin, unmount } = await renderWithProviders(
<InputPrompt {...props} />,
{
uiState: {
btwState: {
isActive: true,
query: '',
response: '',
isStreaming: false,
error: null,
},
},
uiActions: { dismissBtw },
},
);
await act(async () => {
stdin.write(' '); // Space
});
await waitFor(() => {
expect(dismissBtw).toHaveBeenCalled();
});
unmount();
});
});
});
function clean(str: string | undefined): string {
@@ -644,6 +644,31 @@ describe('useSlashCommandProcessor', () => {
expect(mockSetQuittingMessages).toHaveBeenCalledWith(['bye']);
});
it('should handle a "btw" action', async () => {
const btwAction = vi
.fn()
.mockResolvedValue({ type: 'btw', query: 'some query' });
const command = createTestCommand({
name: 'side_question',
action: btwAction,
});
const result = await setupProcessorHook({
builtinCommands: [command],
});
await waitFor(() => expect(result.current.slashCommands).toHaveLength(1));
let processedResult;
await act(async () => {
processedResult = await result.current.handleSlashCommand(
'/side_question some args',
);
});
expect(processedResult).toEqual({ type: 'btw', query: 'some query' });
});
it('should handle "submit_prompt" action returned from a file-based command', async () => {
const fileCommand = createTestCommand(
{