opsdash-app/opsdash/test/BalanceIndexCard.test.ts

190 lines
6.2 KiB
TypeScript

import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import BalanceIndexCard from '../src/components/widgets/cards/BalanceIndexCard.vue'
const overview = {
index: 0.72,
trend: { badge: 'Balanced', history: [{ label: 'T-1', categories: [{ id: 'work', share: 0.6 }] }, { label: 'T-2', categories: [{ id: 'work', share: 0.5 }] }] },
relations: [{ label: 'Work:Life', value: '0.9' }],
categories: [{ id: 'work', label: 'Work', share: 60 }],
warnings: ['Unassigned accounts for 100% of tracked hours.'],
}
describe('BalanceIndexCard', () => {
it('renders trend, relations, categories, messages when enabled', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview,
showTrend: true,
showMessages: true,
showConfig: true,
showHeader: true,
indexBasis: 'category',
thresholds: { noticeAbove: 0.15, noticeBelow: 0.1, warnAbove: 0.3, warnBelow: 0.25, warnIndex: 0.6 },
title: 'My Balance',
cardBg: '#eee',
},
})
expect(wrapper.text()).toContain('My Balance')
expect(wrapper.text()).toContain('Unassigned')
expect(wrapper.find('.trend-block').exists()).toBe(true)
const style = wrapper.find('.balance-card').attributes('style') || ''
expect(style.includes('#eee') || style.toLowerCase().includes('rgb(238')).toBe(true)
expect(wrapper.text()).toContain('Basis')
expect(wrapper.text()).toContain('Warn index')
})
it('respects toggles to hide sections', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview,
showTrend: false,
showMessages: false,
},
})
expect(wrapper.find('.trend').exists()).toBe(false)
expect(wrapper.find('.messages').exists()).toBe(false)
})
it('hides the title when showHeader is false', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview,
showHeader: false,
},
})
expect(wrapper.find('.title-row').exists()).toBe(false)
})
it('renders trend index values using targets and lookback', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview: {
index: 0.9,
trend: {
history: [
{ label: 'Now', categories: [{ id: 'work', share: 60 }, { id: 'hobby', share: 40 }] },
{ label: 'Prev', categories: [{ id: 'work', share: 50 }, { id: 'hobby', share: 50 }] },
],
delta: [1, 2],
},
},
targetsCategories: [
{ id: 'work', targetHours: 10 },
{ id: 'hobby', targetHours: 10 },
],
showTrend: true,
lookbackWeeks: 2,
},
})
const trendValues = wrapper.findAll('.trend-block .trend-value').map((n) => n.text())
expect(trendValues.length).toBeGreaterThan(0)
})
it('falls back to overview.trendHistory and handles extra buckets', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview: {
index: 0.762,
trendHistory: [
{ label: 'Last week', categories: [
{ id: 'work', share: 59.1 },
{ id: 'sport', share: 40.9 },
{ id: '__uncategorized__', share: 0 },
]},
{ label: '-2 wk', categories: [
{ id: 'work', share: 33.3 },
{ id: 'sport', share: 66.7 },
]},
],
},
targetsCategories: [
{ id: 'work', targetHours: 32 },
{ id: 'sport', targetHours: 4 },
],
showTrend: true,
lookbackWeeks: 2,
},
})
const trendValues = wrapper.findAll('.trend-block .trend-value').map((n) => n.text())
expect(trendValues.length).toBeGreaterThan(0)
})
it('shows oldest-first by default and supports reverse-order toggle', () => {
const baseProps = {
overview: {
index: 0.75,
trendHistory: [
{ offset: 1, label: '-1 wk', categories: [{ id: 'work', share: 60 }] },
{ offset: 2, label: '-2 wk', categories: [{ id: 'work', share: 40 }] },
],
},
targetsCategories: [{ id: 'work', targetHours: 10 }],
showTrend: true,
showCurrent: true,
labelMode: 'offset' as const,
lookbackWeeks: 2,
}
const normal = mount(BalanceIndexCard, { props: baseProps })
expect(normal.findAll('.trend-offset').map((node) => node.text())).toEqual([
'-2',
'-1',
'Current',
])
const reversed = mount(BalanceIndexCard, {
props: { ...baseProps, reverseOrder: true },
})
expect(reversed.findAll('.trend-offset').map((node) => node.text())).toEqual([
'Current',
'-1',
'-2',
])
})
it('does not add a special inline box shadow to the first historical trend block', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview: {
index: 0.75,
trendHistory: [
{ offset: 1, label: '-1 wk', categories: [{ id: 'work', share: 60 }] },
{ offset: 2, label: '-2 wk', categories: [{ id: 'work', share: 40 }] },
],
},
targetsCategories: [{ id: 'work', targetHours: 10 }],
showTrend: true,
showCurrent: true,
lookbackWeeks: 2,
},
})
const blocks = wrapper.findAll('.trend-block')
expect(blocks[0].attributes('style') || '').not.toContain('box-shadow')
expect(blocks[0].classes()).not.toContain('current')
expect(blocks[blocks.length - 1].classes()).toContain('current')
})
it('uses precomputed history index values for calendar basis', () => {
const wrapper = mount(BalanceIndexCard, {
props: {
overview: {
index: 0.83,
trendHistory: [
{ offset: 2, label: '-2 wk', index: 0.41, categories: [{ id: 'work', share: 100 }] },
{ offset: 1, label: '-1 wk', index: 0.67, categories: [{ id: 'work', share: 100 }] },
],
},
targetsCategories: [{ id: 'work', targetHours: 10 }],
indexBasis: 'calendar',
showTrend: true,
showCurrent: true,
lookbackWeeks: 2,
},
})
expect(wrapper.findAll('.trend-value').map((node) => node.text())).toEqual(['0.41', '0.67', '0.83'])
})
})