| import { describe, expect, it, vi, beforeEach } from 'vitest' |
| import { mount } from '@vue/test-utils' |
| import { nextTick } from 'vue' |
|
|
| import UsageTable from '../UsageTable.vue' |
|
|
| const messages: Record<string, string> = { |
| 'usage.costDetails': 'Cost Breakdown', |
| 'admin.usage.inputCost': 'Input Cost', |
| 'admin.usage.outputCost': 'Output Cost', |
| 'admin.usage.cacheCreationCost': 'Cache Creation Cost', |
| 'admin.usage.cacheReadCost': 'Cache Read Cost', |
| 'usage.inputTokenPrice': 'Input price', |
| 'usage.outputTokenPrice': 'Output price', |
| 'usage.perMillionTokens': '/ 1M tokens', |
| 'usage.serviceTier': 'Service tier', |
| 'usage.serviceTierPriority': 'Fast', |
| 'usage.serviceTierFlex': 'Flex', |
| 'usage.serviceTierStandard': 'Standard', |
| 'usage.rate': 'Rate', |
| 'usage.accountMultiplier': 'Account rate', |
| 'usage.original': 'Original', |
| 'usage.userBilled': 'User billed', |
| 'usage.accountBilled': 'Account billed', |
| } |
|
|
| vi.mock('vue-i18n', async () => { |
| const actual = await vi.importActual<typeof import('vue-i18n')>('vue-i18n') |
| return { |
| ...actual, |
| useI18n: () => ({ |
| t: (key: string) => messages[key] ?? key, |
| }), |
| } |
| }) |
|
|
| const DataTableStub = { |
| props: ['data'], |
| template: ` |
| <div> |
| <div v-for="row in data" :key="row.request_id"> |
| <slot name="cell-cost" :row="row" /> |
| </div> |
| </div> |
| `, |
| } |
|
|
| describe('admin UsageTable tooltip', () => { |
| beforeEach(() => { |
| vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockReturnValue({ |
| x: 0, |
| y: 0, |
| top: 20, |
| left: 20, |
| right: 120, |
| bottom: 40, |
| width: 100, |
| height: 20, |
| toJSON: () => ({}), |
| } as DOMRect) |
| }) |
|
|
| it('shows service tier and billing breakdown in cost tooltip', async () => { |
| const row = { |
| request_id: 'req-admin-1', |
| actual_cost: 0.092883, |
| total_cost: 0.092883, |
| account_rate_multiplier: 1, |
| rate_multiplier: 1, |
| service_tier: 'priority', |
| input_cost: 0.020285, |
| output_cost: 0.00303, |
| cache_creation_cost: 0, |
| cache_read_cost: 0.069568, |
| input_tokens: 4057, |
| output_tokens: 101, |
| } |
|
|
| const wrapper = mount(UsageTable, { |
| props: { |
| data: [row], |
| loading: false, |
| columns: [], |
| }, |
| global: { |
| stubs: { |
| DataTable: DataTableStub, |
| EmptyState: true, |
| Icon: true, |
| Teleport: true, |
| }, |
| }, |
| }) |
|
|
| await wrapper.find('.group.relative').trigger('mouseenter') |
| await nextTick() |
|
|
| const text = wrapper.text() |
| expect(text).toContain('Service tier') |
| expect(text).toContain('Fast') |
| expect(text).toContain('Rate') |
| expect(text).toContain('1.00x') |
| expect(text).toContain('Account rate') |
| expect(text).toContain('User billed') |
| expect(text).toContain('Account billed') |
| expect(text).toContain('$0.092883') |
| expect(text).toContain('$5.0000 / 1M tokens') |
| expect(text).toContain('$30.0000 / 1M tokens') |
| expect(text).toContain('$0.069568') |
| }) |
| }) |
|
|