feat: filter analytics by profile

This commit is contained in:
Tam Nhu Tran committed 2026-05-22 11:24:21 -04:00
1 parent 14cc787f18
commit f1d655e425
11 files changed
+416 -47

No files matched your search

@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { renderHook } from '@testing-library/react';
import { useAnalyticsPage } from '@/pages/analytics/hooks';
import { AllProviders } from '@tests/setup/test-utils';
@@ -14,8 +14,46 @@ const usageMocks = vi.hoisted(() => ({
}));
vi.mock('@/hooks/use-usage', () => usageMocks);
vi.mock('@/hooks/use-accounts', () => ({
useAccounts: vi.fn(() => ({
data: { accounts: [{ name: 'work' }], default: 'work' },
isLoading: false,
})),
}));
vi.mock('@/hooks/use-profiles', () => ({
useProfiles: vi.fn(() => ({ data: { profiles: [] }, isLoading: false })),
}));
describe('useAnalyticsPage', () => {
beforeEach(() => {
window.localStorage.clear();
Object.values(usageMocks).forEach((mock) => mock.mockClear());
});
afterEach(() => {
vi.restoreAllMocks();
});
it('restores the persisted selected profile and passes it to analytics queries', () => {
vi.spyOn(globalThis.localStorage, 'getItem').mockImplementation((key) =>
key === 'ccs.analytics.selectedProfile' ? 'work' : null
);
renderHook(() => useAnalyticsPage(), {
wrapper: AllProviders,
});
expect(usageMocks.useUsageSummary).toHaveBeenCalledWith(
expect.objectContaining({ profile: 'work' })
);
expect(usageMocks.useUsageTrends).toHaveBeenCalledWith(
expect.objectContaining({ profile: 'work' })
);
expect(usageMocks.useModelUsage).toHaveBeenCalledWith(
expect.objectContaining({ profile: 'work' })
);
});
it('requests a broader recent session sample instead of the old 3-session slice', () => {
renderHook(() => useAnalyticsPage(), {
wrapper: AllProviders,
@@ -37,4 +37,30 @@ describe('analytics usage API contract', () => {
expect(urls).toContain('/api/usage/monthly?since=20260401&until=20260430');
expect(urls.every((url) => !url.includes('months='))).toBe(true);
});
it('serializes the selected profile for every profile-scoped usage endpoint', async () => {
const startDate = new Date(2026, 3, 1);
const endDate = new Date(2026, 3, 30);
const options = { startDate, endDate, profile: 'work' };
await usageApi.summary(options);
await usageApi.trends(options);
await usageApi.hourly(options);
await usageApi.models(options);
await usageApi.sessions({ ...options, limit: 50 });
await usageApi.insights(options);
await usageApi.monthly(options);
const urls = vi.mocked(global.fetch).mock.calls.map(([url]) => String(url));
expect(urls).toContain('/api/usage/summary?since=20260401&until=20260430&profile=work');
expect(urls).toContain('/api/usage/daily?since=20260401&until=20260430&profile=work');
expect(urls).toContain('/api/usage/hourly?since=20260401&until=20260430&profile=work');
expect(urls).toContain('/api/usage/models?since=20260401&until=20260430&profile=work');
expect(urls).toContain(
'/api/usage/sessions?since=20260401&until=20260430&limit=50&profile=work'
);
expect(urls).toContain('/api/usage/insights?since=20260401&until=20260430&profile=work');
expect(urls).toContain('/api/usage/monthly?since=20260401&until=20260430&profile=work');
});
});