Skip to content

Commit 7ff523d

Browse files
authored
Merge pull request #95 from rajbos/main
Add total row to Requests per Model table (#22)
2 parents 9a40b11 + 619dbcc commit 7ff523d

2 files changed

Lines changed: 158 additions & 1 deletion

File tree

src/App.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Card } from "@/components/ui/card";
99
import { Button } from "@/components/ui/button";
1010
import { Separator } from "@/components/ui/separator";
1111
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart";
12-
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
12+
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table";
1313
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
1414
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
1515
import { Tooltip as UITooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
@@ -862,6 +862,23 @@ function App() {
862862
</TableRow>
863863
))}
864864
</TableBody>
865+
<TableFooter>
866+
<TableRow>
867+
<TableCell className="font-medium">Total</TableCell>
868+
<TableCell className="text-right font-medium">
869+
{modelSummary.reduce((sum, item) => sum + item.totalRequests, 0).toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 0})}
870+
</TableCell>
871+
<TableCell className="text-right font-medium">
872+
{modelSummary.reduce((sum, item) => sum + item.compliantRequests, 0).toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 0})}
873+
</TableCell>
874+
<TableCell className="text-right font-medium">
875+
{modelSummary.reduce((sum, item) => sum + item.exceedingRequests, 0).toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 0})}
876+
</TableCell>
877+
<TableCell className="text-right"></TableCell>
878+
<TableCell className="text-right"></TableCell>
879+
<TableCell className="text-right">${modelSummary.reduce((sum, item) => sum + item.excessCost, 0).toFixed(2)}</TableCell>
880+
</TableRow>
881+
</TableFooter>
865882
</Table>
866883
</div>
867884
</Card>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { render } from '@testing-library/react';
3+
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '../components/ui/table';
4+
5+
describe('Model Summary Total Row', () => {
6+
it('should calculate and display correct totals for model summary', () => {
7+
// Mock model summary data
8+
const mockModelSummary = [
9+
{
10+
model: 'GPT-4o',
11+
totalRequests: 1000,
12+
compliantRequests: 800,
13+
exceedingRequests: 200,
14+
multiplier: 1,
15+
excessCost: 50
16+
},
17+
{
18+
model: 'Claude-3',
19+
totalRequests: 500,
20+
compliantRequests: 400,
21+
exceedingRequests: 100,
22+
multiplier: 2,
23+
excessCost: 40
24+
}
25+
];
26+
27+
// Calculate expected totals
28+
const expectedTotalRequests = 1500; // 1000 + 500
29+
const expectedCompliantRequests = 1200; // 800 + 400
30+
const expectedExceedingRequests = 300; // 200 + 100
31+
32+
// Render the table structure with total row like it would appear in App.tsx
33+
const { container } = render(
34+
<Table>
35+
<TableHeader>
36+
<TableRow>
37+
<TableHead>Model</TableHead>
38+
<TableHead className="text-right">Total Requests</TableHead>
39+
<TableHead className="text-right">Compliant</TableHead>
40+
<TableHead className="text-right">Exceeding</TableHead>
41+
<TableHead className="text-right">Multiplier</TableHead>
42+
<TableHead className="text-right">Excess Cost</TableHead>
43+
</TableRow>
44+
</TableHeader>
45+
<TableBody>
46+
{mockModelSummary.map((item) => (
47+
<TableRow key={item.model}>
48+
<TableCell className="font-medium">{item.model}</TableCell>
49+
<TableCell className="text-right">{item.totalRequests.toLocaleString()}</TableCell>
50+
<TableCell className="text-right">{item.compliantRequests.toLocaleString()}</TableCell>
51+
<TableCell className="text-right">{item.exceedingRequests.toLocaleString()}</TableCell>
52+
<TableCell className="text-right">{item.multiplier}x</TableCell>
53+
<TableCell className="text-right">${item.excessCost.toFixed(2)}</TableCell>
54+
</TableRow>
55+
))}
56+
</TableBody>
57+
<TableFooter>
58+
<TableRow>
59+
<TableCell className="font-medium">Total</TableCell>
60+
<TableCell className="text-right font-medium">
61+
{expectedTotalRequests.toLocaleString()}
62+
</TableCell>
63+
<TableCell className="text-right font-medium">
64+
{expectedCompliantRequests.toLocaleString()}
65+
</TableCell>
66+
<TableCell className="text-right font-medium">
67+
{expectedExceedingRequests.toLocaleString()}
68+
</TableCell>
69+
<TableCell className="text-right"></TableCell>
70+
<TableCell className="text-right"></TableCell>
71+
</TableRow>
72+
</TableFooter>
73+
</Table>
74+
);
75+
76+
// Verify total row exists and contains correct values
77+
const totalRow = container.querySelector('tfoot tr');
78+
expect(totalRow).toBeTruthy();
79+
80+
const cells = totalRow?.querySelectorAll('td');
81+
expect(cells).toHaveLength(6);
82+
83+
// Check the total values in the cells
84+
expect(cells?.[0]?.textContent).toBe('Total');
85+
expect(cells?.[1]?.textContent).toBe('1,500');
86+
expect(cells?.[2]?.textContent).toBe('1,200');
87+
expect(cells?.[3]?.textContent).toBe('300');
88+
expect(cells?.[4]?.textContent).toBe('—');
89+
expect(cells?.[5]?.textContent).toBe('—');
90+
});
91+
92+
it('should handle empty model summary data', () => {
93+
const mockModelSummary: any[] = [];
94+
95+
const { container } = render(
96+
<Table>
97+
<TableHeader>
98+
<TableRow>
99+
<TableHead>Model</TableHead>
100+
<TableHead className="text-right">Total Requests</TableHead>
101+
<TableHead className="text-right">Compliant</TableHead>
102+
<TableHead className="text-right">Exceeding</TableHead>
103+
<TableHead className="text-right">Multiplier</TableHead>
104+
<TableHead className="text-right">Excess Cost</TableHead>
105+
</TableRow>
106+
</TableHeader>
107+
<TableBody>
108+
{mockModelSummary.map((item) => (
109+
<TableRow key={item.model}>
110+
<TableCell className="font-medium">{item.model}</TableCell>
111+
<TableCell className="text-right">{item.totalRequests.toLocaleString()}</TableCell>
112+
<TableCell className="text-right">{item.compliantRequests.toLocaleString()}</TableCell>
113+
<TableCell className="text-right">{item.exceedingRequests.toLocaleString()}</TableCell>
114+
<TableCell className="text-right">{item.multiplier}x</TableCell>
115+
<TableCell className="text-right">${item.excessCost.toFixed(2)}</TableCell>
116+
</TableRow>
117+
))}
118+
</TableBody>
119+
<TableFooter>
120+
<TableRow>
121+
<TableCell className="font-medium">Total</TableCell>
122+
<TableCell className="text-right font-medium">0</TableCell>
123+
<TableCell className="text-right font-medium">0</TableCell>
124+
<TableCell className="text-right font-medium">0</TableCell>
125+
<TableCell className="text-right"></TableCell>
126+
<TableCell className="text-right"></TableCell>
127+
</TableRow>
128+
</TableFooter>
129+
</Table>
130+
);
131+
132+
// Verify total row shows zeros for empty data
133+
const totalRow = container.querySelector('tfoot tr');
134+
const cells = totalRow?.querySelectorAll('td');
135+
136+
expect(cells?.[1]?.textContent).toBe('0');
137+
expect(cells?.[2]?.textContent).toBe('0');
138+
expect(cells?.[3]?.textContent).toBe('0');
139+
});
140+
});

0 commit comments

Comments
 (0)