test(01-01): add failing tests for palette module

- Tests cover all 7 CategoryType values with 3 shades each
- Tests for headerGradient returning valid CSSProperties with linear-gradient
- Tests for overviewHeaderGradient multi-stop gradient
- Tests for amountColorClass: income, available, and expense paths
This commit is contained in:
2026-03-11 20:52:06 +01:00
parent 3f97d07f4e
commit d5fc10de46

View File

@@ -0,0 +1,137 @@
import { describe, it, expect } from 'vitest'
import {
palette,
CategoryType,
headerGradient,
overviewHeaderGradient,
amountColorClass,
} from './palette'
describe('palette exports', () => {
it('exports all 7 CategoryType values', () => {
const expectedTypes: CategoryType[] = [
'income',
'bill',
'variable_expense',
'debt',
'saving',
'investment',
'carryover',
]
expectedTypes.forEach((type) => {
expect(palette[type]).toBeDefined()
})
})
it('has exactly 7 entries', () => {
expect(Object.keys(palette)).toHaveLength(7)
})
it('each category has light, medium, and base shades', () => {
Object.entries(palette).forEach(([, shades]) => {
expect(shades.light).toBeTruthy()
expect(shades.medium).toBeTruthy()
expect(shades.base).toBeTruthy()
})
})
it('all shade values are non-empty oklch strings', () => {
Object.entries(palette).forEach(([, shades]) => {
expect(shades.light).toMatch(/oklch/)
expect(shades.medium).toMatch(/oklch/)
expect(shades.base).toMatch(/oklch/)
})
})
})
describe('headerGradient', () => {
it('returns a CSSProperties object for a valid category type', () => {
const result = headerGradient('bill')
expect(result).toBeDefined()
expect(typeof result).toBe('object')
})
it('returns an object with a background property', () => {
const result = headerGradient('income')
expect(result).toHaveProperty('background')
})
it('background value is a linear-gradient', () => {
const result = headerGradient('bill')
expect(String(result.background)).toMatch(/linear-gradient/)
})
it('gradient uses the light and medium shades of the category', () => {
const result = headerGradient('saving')
expect(String(result.background)).toContain(palette.saving.light)
expect(String(result.background)).toContain(palette.saving.medium)
})
})
describe('overviewHeaderGradient', () => {
it('returns a CSSProperties object', () => {
const result = overviewHeaderGradient()
expect(result).toBeDefined()
expect(typeof result).toBe('object')
})
it('returns an object with a background property', () => {
const result = overviewHeaderGradient()
expect(result).toHaveProperty('background')
})
it('background value is a multi-stop linear-gradient', () => {
const result = overviewHeaderGradient()
const bg = String(result.background)
expect(bg).toMatch(/linear-gradient/)
// Should have multiple color stops (at least 3 commas after the direction)
const stops = bg.split('oklch').length - 1
expect(stops).toBeGreaterThanOrEqual(3)
})
})
describe('amountColorClass', () => {
it('returns text-success for positive income (isIncome=true, actual > 0)', () => {
expect(amountColorClass({ type: 'income', actual: 100, budgeted: 0, isIncome: true })).toBe(
'text-success'
)
})
it('returns empty string for zero income (isIncome=true, actual = 0)', () => {
expect(amountColorClass({ type: 'income', actual: 0, budgeted: 0, isIncome: true })).toBe('')
})
it('returns text-warning when actual > budgeted (over-budget expense)', () => {
expect(amountColorClass({ type: 'bill', actual: 200, budgeted: 100 })).toBe('text-warning')
})
it('returns empty string when actual equals budgeted (exactly on budget)', () => {
expect(amountColorClass({ type: 'bill', actual: 100, budgeted: 100 })).toBe('')
})
it('returns empty string when actual < budgeted (under budget)', () => {
expect(amountColorClass({ type: 'bill', actual: 50, budgeted: 100 })).toBe('')
})
it('returns empty string when isAvailable=true and actual is zero', () => {
expect(amountColorClass({ type: 'bill', actual: 0, budgeted: 0, isAvailable: true })).toBe('')
})
it('returns text-success when isAvailable=true and actual > 0', () => {
expect(
amountColorClass({ type: 'bill', actual: 500, budgeted: 0, isAvailable: true })
).toBe('text-success')
})
it('returns text-destructive when isAvailable=true and actual < 0', () => {
expect(
amountColorClass({ type: 'bill', actual: -100, budgeted: 0, isAvailable: true })
).toBe('text-destructive')
})
it('returns text-destructive for negative income (isIncome=true, actual < 0)', () => {
expect(
amountColorClass({ type: 'income', actual: -50, budgeted: 0, isIncome: true })
).toBe('text-destructive')
})
})