Files
quitfree/test/storage.test.ts

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')
})
})