summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/components/StatsDisplay.test.tsx
diff options
context:
space:
mode:
authorAbhi <[email protected]>2025-06-29 20:44:33 -0400
committerGitHub <[email protected]>2025-06-30 00:44:33 +0000
commit770f862832dfef477705bee69bd2a84397d105a8 (patch)
tree8cb647cf789f05458ff491b461aa531a6932ad3d /packages/cli/src/ui/components/StatsDisplay.test.tsx
parent0fd602eb43eea7abca980dc2ae3fd7bf2ba76a2a (diff)
feat: Change /stats to include more detailed breakdowns (#2615)
Diffstat (limited to 'packages/cli/src/ui/components/StatsDisplay.test.tsx')
-rw-r--r--packages/cli/src/ui/components/StatsDisplay.test.tsx292
1 files changed, 242 insertions, 50 deletions
diff --git a/packages/cli/src/ui/components/StatsDisplay.test.tsx b/packages/cli/src/ui/components/StatsDisplay.test.tsx
index c7b574a5..29f322f4 100644
--- a/packages/cli/src/ui/components/StatsDisplay.test.tsx
+++ b/packages/cli/src/ui/components/StatsDisplay.test.tsx
@@ -5,67 +5,259 @@
*/
import { render } from 'ink-testing-library';
-import { describe, it, expect } from 'vitest';
+import { describe, it, expect, vi } from 'vitest';
import { StatsDisplay } from './StatsDisplay.js';
-import { type CumulativeStats } from '../contexts/SessionContext.js';
+import * as SessionContext from '../contexts/SessionContext.js';
+import { SessionMetrics } from '../contexts/SessionContext.js';
-describe('<StatsDisplay />', () => {
- const mockStats: CumulativeStats = {
- turnCount: 10,
- promptTokenCount: 1000,
- candidatesTokenCount: 2000,
- totalTokenCount: 3500,
- cachedContentTokenCount: 500,
- toolUsePromptTokenCount: 200,
- thoughtsTokenCount: 300,
- apiTimeMs: 50234,
+// Mock the context to provide controlled data for testing
+vi.mock('../contexts/SessionContext.js', async (importOriginal) => {
+ const actual = await importOriginal<typeof SessionContext>();
+ return {
+ ...actual,
+ useSessionStats: vi.fn(),
};
+});
- const mockLastTurnStats: CumulativeStats = {
- turnCount: 1,
- promptTokenCount: 100,
- candidatesTokenCount: 200,
- totalTokenCount: 350,
- cachedContentTokenCount: 50,
- toolUsePromptTokenCount: 20,
- thoughtsTokenCount: 30,
- apiTimeMs: 1234,
- };
+const useSessionStatsMock = vi.mocked(SessionContext.useSessionStats);
+
+const renderWithMockedStats = (metrics: SessionMetrics) => {
+ useSessionStatsMock.mockReturnValue({
+ stats: {
+ sessionStartTime: new Date(),
+ metrics,
+ lastPromptTokenCount: 0,
+ },
+ });
+
+ return render(<StatsDisplay duration="1s" />);
+};
+
+describe('<StatsDisplay />', () => {
+ it('renders only the Performance section in its zero state', () => {
+ const zeroMetrics: SessionMetrics = {
+ models: {},
+ tools: {
+ totalCalls: 0,
+ totalSuccess: 0,
+ totalFail: 0,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
+
+ const { lastFrame } = renderWithMockedStats(zeroMetrics);
+ const output = lastFrame();
+
+ expect(output).toContain('Performance');
+ expect(output).not.toContain('Interaction Summary');
+ expect(output).not.toContain('Efficiency & Optimizations');
+ expect(output).not.toContain('Model'); // The table header
+ expect(output).toMatchSnapshot();
+ });
- const mockDuration = '1h 23m 45s';
+ it('renders a table with two models correctly', () => {
+ const metrics: SessionMetrics = {
+ models: {
+ 'gemini-2.5-pro': {
+ api: { totalRequests: 3, totalErrors: 0, totalLatencyMs: 15000 },
+ tokens: {
+ prompt: 1000,
+ candidates: 2000,
+ total: 43234,
+ cached: 500,
+ thoughts: 100,
+ tool: 50,
+ },
+ },
+ 'gemini-2.5-flash': {
+ api: { totalRequests: 5, totalErrors: 1, totalLatencyMs: 4500 },
+ tokens: {
+ prompt: 25000,
+ candidates: 15000,
+ total: 150000000,
+ cached: 10000,
+ thoughts: 2000,
+ tool: 1000,
+ },
+ },
+ },
+ tools: {
+ totalCalls: 0,
+ totalSuccess: 0,
+ totalFail: 0,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
- it('renders correctly with given stats and duration', () => {
- const { lastFrame } = render(
- <StatsDisplay
- stats={mockStats}
- lastTurnStats={mockLastTurnStats}
- duration={mockDuration}
- />,
- );
+ const { lastFrame } = renderWithMockedStats(metrics);
+ const output = lastFrame();
- expect(lastFrame()).toMatchSnapshot();
+ expect(output).toContain('gemini-2.5-pro');
+ expect(output).toContain('gemini-2.5-flash');
+ expect(output).toContain('1,000');
+ expect(output).toContain('25,000');
+ expect(output).toMatchSnapshot();
});
- it('renders zero state correctly', () => {
- const zeroStats: CumulativeStats = {
- turnCount: 0,
- promptTokenCount: 0,
- candidatesTokenCount: 0,
- totalTokenCount: 0,
- cachedContentTokenCount: 0,
- toolUsePromptTokenCount: 0,
- thoughtsTokenCount: 0,
- apiTimeMs: 0,
+ it('renders all sections when all data is present', () => {
+ const metrics: SessionMetrics = {
+ models: {
+ 'gemini-2.5-pro': {
+ api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
+ tokens: {
+ prompt: 100,
+ candidates: 100,
+ total: 250,
+ cached: 50,
+ thoughts: 0,
+ tool: 0,
+ },
+ },
+ },
+ tools: {
+ totalCalls: 2,
+ totalSuccess: 1,
+ totalFail: 1,
+ totalDurationMs: 123,
+ totalDecisions: { accept: 1, reject: 0, modify: 0 },
+ byName: {
+ 'test-tool': {
+ count: 2,
+ success: 1,
+ fail: 1,
+ durationMs: 123,
+ decisions: { accept: 1, reject: 0, modify: 0 },
+ },
+ },
+ },
};
- const { lastFrame } = render(
- <StatsDisplay
- stats={zeroStats}
- lastTurnStats={zeroStats}
- duration="0s"
- />,
- );
+ const { lastFrame } = renderWithMockedStats(metrics);
+ const output = lastFrame();
+
+ expect(output).toContain('Performance');
+ expect(output).toContain('Interaction Summary');
+ expect(output).toContain('User Agreement');
+ expect(output).toContain('Savings Highlight');
+ expect(output).toContain('gemini-2.5-pro');
+ expect(output).toMatchSnapshot();
+ });
+
+ describe('Conditional Rendering Tests', () => {
+ it('hides User Agreement when no decisions are made', () => {
+ const metrics: SessionMetrics = {
+ models: {},
+ tools: {
+ totalCalls: 2,
+ totalSuccess: 1,
+ totalFail: 1,
+ totalDurationMs: 123,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 }, // No decisions
+ byName: {
+ 'test-tool': {
+ count: 2,
+ success: 1,
+ fail: 1,
+ durationMs: 123,
+ decisions: { accept: 0, reject: 0, modify: 0 },
+ },
+ },
+ },
+ };
+
+ const { lastFrame } = renderWithMockedStats(metrics);
+ const output = lastFrame();
+
+ expect(output).toContain('Interaction Summary');
+ expect(output).toContain('Success Rate');
+ expect(output).not.toContain('User Agreement');
+ expect(output).toMatchSnapshot();
+ });
+
+ it('hides Efficiency section when cache is not used', () => {
+ const metrics: SessionMetrics = {
+ models: {
+ 'gemini-2.5-pro': {
+ api: { totalRequests: 1, totalErrors: 0, totalLatencyMs: 100 },
+ tokens: {
+ prompt: 100,
+ candidates: 100,
+ total: 200,
+ cached: 0,
+ thoughts: 0,
+ tool: 0,
+ },
+ },
+ },
+ tools: {
+ totalCalls: 0,
+ totalSuccess: 0,
+ totalFail: 0,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
+
+ const { lastFrame } = renderWithMockedStats(metrics);
+ const output = lastFrame();
+
+ expect(output).not.toContain('Efficiency & Optimizations');
+ expect(output).toMatchSnapshot();
+ });
+ });
+
+ describe('Conditional Color Tests', () => {
+ it('renders success rate in green for high values', () => {
+ const metrics: SessionMetrics = {
+ models: {},
+ tools: {
+ totalCalls: 10,
+ totalSuccess: 10,
+ totalFail: 0,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
+ const { lastFrame } = renderWithMockedStats(metrics);
+ expect(lastFrame()).toMatchSnapshot();
+ });
+
+ it('renders success rate in yellow for medium values', () => {
+ const metrics: SessionMetrics = {
+ models: {},
+ tools: {
+ totalCalls: 10,
+ totalSuccess: 9,
+ totalFail: 1,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
+ const { lastFrame } = renderWithMockedStats(metrics);
+ expect(lastFrame()).toMatchSnapshot();
+ });
- expect(lastFrame()).toMatchSnapshot();
+ it('renders success rate in red for low values', () => {
+ const metrics: SessionMetrics = {
+ models: {},
+ tools: {
+ totalCalls: 10,
+ totalSuccess: 5,
+ totalFail: 5,
+ totalDurationMs: 0,
+ totalDecisions: { accept: 0, reject: 0, modify: 0 },
+ byName: {},
+ },
+ };
+ const { lastFrame } = renderWithMockedStats(metrics);
+ expect(lastFrame()).toMatchSnapshot();
+ });
});
});