110 lines
4.3 KiB
TypeScript
110 lines
4.3 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import {
|
|
monthlyCost, annualCost, totalMonthlyCost, totalAnnualCost, daysUntil,
|
|
subscriptionsExpiringSoon, subscriptionsToCSV, expensesToCSV, generateId, formatCurrency
|
|
} from '../src/shared/storage'
|
|
import type { Subscription, Expense } from '../src/shared/storage'
|
|
|
|
describe('monthlyCost', () => {
|
|
it('returns monthly cost for monthly interval', () => {
|
|
const s: Subscription = { id: '1', name: 'Test', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other' }
|
|
expect(monthlyCost(s)).toBe(10)
|
|
})
|
|
it('returns monthly cost for yearly interval', () => {
|
|
const s: Subscription = { id: '1', name: 'Test', cost: 120, interval: 'yearly', startedAt: '2024-01-01', category: 'Other' }
|
|
expect(monthlyCost(s)).toBe(10)
|
|
})
|
|
it('returns monthly cost for weekly interval', () => {
|
|
const s: Subscription = { id: '1', name: 'Test', cost: 10, interval: 'weekly', startedAt: '2024-01-01', category: 'Other' }
|
|
expect(monthlyCost(s)).toBeCloseTo(43.3, 1)
|
|
})
|
|
})
|
|
|
|
describe('annualCost', () => {
|
|
it('returns annual cost for monthly interval', () => {
|
|
const s: Subscription = { id: '1', name: 'Test', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other' }
|
|
expect(annualCost(s)).toBe(120)
|
|
})
|
|
it('returns annual cost for yearly interval', () => {
|
|
const s: Subscription = { id: '1', name: 'Test', cost: 120, interval: 'yearly', startedAt: '2024-01-01', category: 'Other' }
|
|
expect(annualCost(s)).toBe(120)
|
|
})
|
|
})
|
|
|
|
describe('totalMonthlyCost', () => {
|
|
it('sums only active subscriptions', () => {
|
|
const subs: Subscription[] = [
|
|
{ id: '1', name: 'A', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other' },
|
|
{ id: '2', name: 'B', cost: 20, interval: 'monthly', startedAt: '2024-01-01', category: 'Other', cancelled: true },
|
|
{ id: '3', name: 'C', cost: 120, interval: 'yearly', startedAt: '2024-01-01', category: 'Other' }
|
|
]
|
|
expect(totalMonthlyCost(subs)).toBe(20)
|
|
})
|
|
})
|
|
|
|
describe('daysUntil', () => {
|
|
it('returns days until a future date', () => {
|
|
const future = new Date(Date.now() + 3 * 86400000).toISOString().slice(0, 10)
|
|
expect(daysUntil(future)).toBe(3)
|
|
})
|
|
it('returns 0 for today', () => {
|
|
const today = new Date().toISOString().slice(0, 10)
|
|
expect(daysUntil(today)).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('subscriptionsExpiringSoon', () => {
|
|
it('returns trials expiring within given days', () => {
|
|
const today = new Date().toISOString().slice(0, 10)
|
|
const tomorrow = new Date(Date.now() + 86400000).toISOString().slice(0, 10)
|
|
const nextWeek = new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10)
|
|
const subs: Subscription[] = [
|
|
{ id: '1', name: 'A', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other', trialEndsAt: today },
|
|
{ id: '2', name: 'B', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other', trialEndsAt: tomorrow },
|
|
{ id: '3', name: 'C', cost: 10, interval: 'monthly', startedAt: '2024-01-01', category: 'Other', trialEndsAt: nextWeek }
|
|
]
|
|
expect(subscriptionsExpiringSoon(subs, 3).length).toBe(2)
|
|
})
|
|
})
|
|
|
|
describe('formatCurrency', () => {
|
|
it('formats dollars correctly', () => {
|
|
expect(formatCurrency(10)).toBe('$10.00')
|
|
expect(formatCurrency(10.5)).toBe('$10.50')
|
|
expect(formatCurrency(0)).toBe('$0.00')
|
|
})
|
|
})
|
|
|
|
describe('generateId', () => {
|
|
it('generates unique ids', () => {
|
|
const id1 = generateId()
|
|
const id2 = generateId()
|
|
expect(id1).not.toBe(id2)
|
|
expect(id1.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('subscriptionsToCSV', () => {
|
|
it('produces valid CSV', () => {
|
|
const subs: Subscription[] = [
|
|
{ id: '1', name: 'Netflix', cost: 15.99, interval: 'monthly', startedAt: '2024-01-01', category: 'Entertainment' }
|
|
]
|
|
const csv = subscriptionsToCSV(subs)
|
|
expect(csv).toContain('Name')
|
|
expect(csv).toContain('Netflix')
|
|
expect(csv).toContain('15.99')
|
|
})
|
|
})
|
|
|
|
describe('expensesToCSV', () => {
|
|
it('produces valid CSV', () => {
|
|
const expenses: Expense[] = [
|
|
{ id: '1', amount: 25.50, description: 'Lunch', category: 'Food', date: '2024-01-01' }
|
|
]
|
|
const csv = expensesToCSV(expenses)
|
|
expect(csv).toContain('Description')
|
|
expect(csv).toContain('Lunch')
|
|
expect(csv).toContain('25.50')
|
|
})
|
|
})
|