Files
hermes-web-ui/tests/client/usage-components-cache-visuals.test.ts
Zhicheng Han c2068302c3 feat: enhance usage analytics dashboard (#666)
- visualize input, output, and cache token segments in usage charts
- add usage period selector for 7d, 30d, 90d, and 365d
- guard usage stats against stale overlapping period requests
- normalize blank model usage into unknown buckets
- add client and server coverage for usage analytics behavior
2026-05-13 07:41:49 +08:00

74 lines
2.1 KiB
TypeScript

// @vitest-environment jsdom
import { describe, expect, it, vi } from 'vitest'
import { mount } from '@vue/test-utils'
const mockUsageStore = vi.hoisted(() => ({
dailyUsage: [
{
date: '2026-05-12',
input_tokens: 100,
output_tokens: 50,
cache_read_tokens: 75,
cache_write_tokens: 10,
sessions: 2,
errors: 0,
cost: 0.02,
visualTokens: 225,
inputPercent: 44.444,
outputPercent: 22.222,
cachePercent: 33.333,
},
],
modelUsage: [
{
model: 'gpt-5',
inputTokens: 100,
outputTokens: 50,
cacheTokens: 75,
cacheWriteTokens: 10,
totalTokens: 150,
visualTokens: 225,
sessions: 2,
color: '#4fd1c5',
inputPercent: 44.444,
outputPercent: 22.222,
cachePercent: 33.333,
},
],
}))
vi.mock('@/stores/hermes/usage', () => ({
useUsageStore: () => mockUsageStore,
}))
vi.mock('vue-i18n', () => ({
useI18n: () => ({
t: (key: string) => key,
}),
}))
import DailyTrend from '@/components/hermes/usage/DailyTrend.vue'
import ModelBreakdown from '@/components/hermes/usage/ModelBreakdown.vue'
describe('usage cache visualizations', () => {
it('renders cache-read as a visible segment in the daily usage bars', () => {
const wrapper = mount(DailyTrend)
const cacheSegment = wrapper.find('.bar-segment.cache')
expect(cacheSegment.exists()).toBe(true)
expect(cacheSegment.attributes('style')).toContain('height: 33.333%')
expect(wrapper.text()).toContain('usage.cacheRead')
})
it('renders model breakdown as input/output/cache stacked segments', () => {
const wrapper = mount(ModelBreakdown)
expect(wrapper.find('.model-swatch').attributes('style')).toContain('background: rgb(79, 209, 197)')
expect(wrapper.find('.model-bar-segment.input').exists()).toBe(true)
expect(wrapper.find('.model-bar-segment.output').exists()).toBe(true)
const cacheSegment = wrapper.find('.model-bar-segment.cache')
expect(cacheSegment.exists()).toBe(true)
expect(cacheSegment.attributes('style')).toContain('width: 33.333%')
})
})