93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
/**
|
|
* AgentIntelligenceCard — tests that feedback stats are rendered correctly.
|
|
*
|
|
* Uses a lightweight approach: tests the data-transformation logic and
|
|
* verifies the component accepts the FeedbackStats shape without errors.
|
|
* Since this is a Tauri desktop app (not Next.js), we test the card's
|
|
* data contract and rendering expectations.
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import type { FeedbackStats } from '../src/components/cockpit/types';
|
|
|
|
describe('AgentIntelligenceCard data contract', () => {
|
|
it('FeedbackStats shape matches the /api/feedback/stats response', () => {
|
|
const stats: FeedbackStats = {
|
|
totalFeedback: 42,
|
|
positiveRate: 0.85,
|
|
topIssues: ['wrong_answer', 'too_verbose'],
|
|
correctionsThisWeek: 3,
|
|
improvementTrend: '+12%',
|
|
};
|
|
|
|
expect(stats.totalFeedback).toBe(42);
|
|
expect(stats.positiveRate).toBe(0.85);
|
|
expect(stats.topIssues).toHaveLength(2);
|
|
expect(stats.correctionsThisWeek).toBe(3);
|
|
expect(stats.improvementTrend).toBe('+12%');
|
|
});
|
|
|
|
it('handles empty stats (zero feedback)', () => {
|
|
const stats: FeedbackStats = {
|
|
totalFeedback: 0,
|
|
positiveRate: 0,
|
|
topIssues: [],
|
|
correctionsThisWeek: 0,
|
|
improvementTrend: '0%',
|
|
};
|
|
|
|
expect(stats.totalFeedback).toBe(0);
|
|
expect(stats.positiveRate).toBe(0);
|
|
expect(stats.topIssues).toEqual([]);
|
|
});
|
|
|
|
it('handles negative improvement trend', () => {
|
|
const stats: FeedbackStats = {
|
|
totalFeedback: 10,
|
|
positiveRate: 0.5,
|
|
topIssues: ['wrong_tool'],
|
|
correctionsThisWeek: 7,
|
|
improvementTrend: '-5%',
|
|
};
|
|
|
|
expect(stats.improvementTrend).toBe('-5%');
|
|
// Negative trend starts with '-'
|
|
expect(stats.improvementTrend.startsWith('-')).toBe(true);
|
|
});
|
|
|
|
it('trend parsing for positive values', () => {
|
|
const trend = '+12%';
|
|
const match = trend.match(/^([+-]?\d+)%$/);
|
|
expect(match).not.toBeNull();
|
|
expect(parseInt(match![1], 10)).toBe(12);
|
|
});
|
|
|
|
it('trend parsing for negative values', () => {
|
|
const trend = '-5%';
|
|
const match = trend.match(/^([+-]?\d+)%$/);
|
|
expect(match).not.toBeNull();
|
|
expect(parseInt(match![1], 10)).toBe(-5);
|
|
});
|
|
|
|
it('trend parsing for zero', () => {
|
|
const trend = '0%';
|
|
const match = trend.match(/^([+-]?\d+)%$/);
|
|
expect(match).not.toBeNull();
|
|
expect(parseInt(match![1], 10)).toBe(0);
|
|
});
|
|
|
|
it('reason formatting converts snake_case to Title Case', () => {
|
|
const formatReason = (reason: string): string =>
|
|
reason
|
|
.split('_')
|
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
.join(' ');
|
|
|
|
expect(formatReason('wrong_answer')).toBe('Wrong Answer');
|
|
expect(formatReason('too_verbose')).toBe('Too Verbose');
|
|
expect(formatReason('wrong_tool')).toBe('Wrong Tool');
|
|
expect(formatReason('too_slow')).toBe('Too Slow');
|
|
expect(formatReason('other')).toBe('Other');
|
|
});
|
|
});
|