Files
gemini-cli/packages/core/src/tools/visualize.test.ts
T
Bryan Morgan 545a23f120 feat(cli): introduce visualize tool for rich data display
- Implement `visualize` tool in core to support tables, charts, and diffs.
- Add `RichDataDisplay` UI component using Ink for rendering visualizations.
- Integrate visualization support into `ToolResultDisplay`.
- Update system prompts to encourage the use of the `visualize` tool for structured data.
- Add `info` semantic color to themes.
- Fix shell parser initialization in tests.
2026-02-10 19:53:38 -05:00

108 lines
3.0 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { VisualizeTool } from './visualize.js';
import type { MessageBus } from '../confirmation-bus/message-bus.js';
import * as fs from 'node:fs/promises';
vi.mock('node:fs/promises');
vi.mock('../confirmation-bus/message-bus.js');
describe('VisualizeTool', () => {
let tool: VisualizeTool;
let messageBus: MessageBus;
beforeEach(() => {
messageBus = {} as unknown as MessageBus;
tool = new VisualizeTool(messageBus);
});
it('should return table visualization', async () => {
const data = [{ name: 'A', value: 1 }];
const result = await tool.validateBuildAndExecute(
{ data, type: 'table' },
new AbortController().signal,
);
expect(result.returnDisplay).toEqual({
type: 'table',
title: undefined,
data,
columns: [
{ key: 'name', label: 'name' },
{ key: 'value', label: 'value' },
],
savedFilePath: undefined,
});
});
it('should return bar_chart visualization', async () => {
const data = [{ label: 'A', value: 10 }];
const result = await tool.validateBuildAndExecute(
{ data, type: 'bar_chart' },
new AbortController().signal,
);
expect(result.returnDisplay).toMatchObject({
type: 'bar_chart',
data,
});
});
it('should save to file if save_as provided', async () => {
const data = [{ name: 'A', value: 1 }];
const savePath = '/tmp/test.json';
(fs.writeFile as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(
undefined,
);
const result = await tool.validateBuildAndExecute(
{ data, save_as: savePath },
new AbortController().signal,
);
expect(fs.writeFile).toHaveBeenCalledWith(
expect.stringContaining('test.json'),
expect.stringContaining('"name": "A"'),
);
expect(
(result.returnDisplay as { savedFilePath: string }).savedFilePath,
).toBeTruthy();
});
it('should return error if data is not an array', async () => {
const result = await tool.validateBuildAndExecute(
{ data: 'invalid' as unknown as Array<Record<string, unknown>> },
new AbortController().signal,
);
expect(result.error).toBeDefined();
expect(result.error?.message).toContain('Data must be an array');
});
it('should return diff visualization', async () => {
const data = { fileDiff: 'diff...', fileName: 'test.ts' };
const result = await tool.validateBuildAndExecute(
{ data, type: 'diff' },
new AbortController().signal,
);
expect(result.returnDisplay).toMatchObject({
type: 'diff',
data,
});
});
it('should return line_chart visualization', async () => {
const data = [{ label: 'Jan', value: 100 }];
const result = await tool.validateBuildAndExecute(
{ data, type: 'line_chart' },
new AbortController().signal,
);
expect(result.returnDisplay).toMatchObject({
type: 'line_chart',
data,
});
});
});