diff --git a/src/arrays.test.ts b/src/arrays.test.ts new file mode 100644 index 0000000..53bf689 --- /dev/null +++ b/src/arrays.test.ts @@ -0,0 +1,112 @@ +import { describe, it, expect } from 'vitest'; +import { + chunk, + compact, + uniq, + uniqBy, + flatten, + flattenDeep, + difference, + intersection, + groupBy, + partition, + sample, + shuffle, +} from '../src/arrays'; + +describe('chunk', () => { + it('splits array into chunks of given size', () => { + expect(chunk([1, 2, 3, 4, 5], 2)).toEqual([[1, 2], [3, 4], [5]]); + }); + it('handles size larger than array', () => { + expect(chunk([1, 2], 5)).toEqual([[1, 2]]); + }); + it('handles empty array', () => { + expect(chunk([], 3)).toEqual([]); + }); +}); + +describe('compact', () => { + it('removes falsy values', () => { + expect(compact([0, 1, false, 2, '', 3])).toEqual([1, 2, 3]); + }); + it('handles all falsy', () => { + expect(compact([false, null, undefined, 0, ''])).toEqual([]); + }); +}); + +describe('uniq', () => { + it('removes duplicates', () => { + expect(uniq([1, 2, 2, 3, 3, 3])).toEqual([1, 2, 3]); + }); + it('handles empty array', () => { + expect(uniq([])).toEqual([]); + }); +}); + +describe('uniqBy', () => { + it('removes duplicates by key', () => { + const arr = [{ id: 1 }, { id: 2 }, { id: 1 }]; + expect(uniqBy(arr, 'id')).toEqual([{ id: 1 }, { id: 2 }]); + }); +}); + +describe('flatten', () => { + it('flattens one level', () => { + expect(flatten([[1, 2], [3, 4]])).toEqual([1, 2, 3, 4]); + }); +}); + +describe('flattenDeep', () => { + it('flattens all levels', () => { + expect(flattenDeep([1, [2, [3, [4]]]])).toEqual([1, 2, 3, 4]); + }); +}); + +describe('difference', () => { + it('returns items not in second array', () => { + expect(difference([1, 2, 3, 4], [2, 4])).toEqual([1, 3]); + }); +}); + +describe('intersection', () => { + it('returns common items', () => { + expect(intersection([1, 2, 3], [2, 3, 4])).toEqual([2, 3]); + }); +}); + +describe('groupBy', () => { + it('groups by key', () => { + const arr = [{ type: 'a' }, { type: 'b' }, { type: 'a' }]; + const result = groupBy(arr, 'type'); + expect(result.a).toHaveLength(2); + expect(result.b).toHaveLength(1); + }); +}); + +describe('partition', () => { + it('splits by predicate', () => { + const [evens, odds] = partition([1, 2, 3, 4], n => n % 2 === 0); + expect(evens).toEqual([2, 4]); + expect(odds).toEqual([1, 3]); + }); +}); + +describe('sample', () => { + it('returns element from array', () => { + const arr = [1, 2, 3]; + const result = sample(arr); + expect(arr).toContain(result); + }); + it('handles empty array', () => { + expect(sample([])).toBeUndefined(); + }); +}); + +describe('shuffle', () => { + it('returns array with same elements', () => { + const arr = [1, 2, 3, 4, 5]; + const result = shuffle(arr); + expect(result.sort()).toEqual([1, 2, 3, 4, 5]); + }); +}); diff --git a/src/dates.test.ts b/src/dates.test.ts new file mode 100644 index 0000000..4ed3190 --- /dev/null +++ b/src/dates.test.ts @@ -0,0 +1,81 @@ +import { describe, it, expect } from 'vitest'; +import { + formatDate, + formatRelative, + isToday, + isYesterday, + daysBetween, + addDays, +} from '../src/dates'; + +describe('formatDate', () => { + it('formats a date string', () => { + const result = formatDate('2026-05-27T10:00:00Z'); + expect(result).toBeTruthy(); + expect(typeof result).toBe('string'); + }); + it('handles invalid date', () => { + expect(formatDate('invalid')).toBeFalsy(); + }); +}); + +describe('formatRelative', () => { + it('returns relative time string', () => { + const result = formatRelative(new Date().toISOString()); + expect(result).toBeTruthy(); + expect(typeof result).toBe('string'); + }); + it('handles past dates', () => { + const past = new Date(Date.now() - 86400000).toISOString(); + const result = formatRelative(past); + expect(result).toBeTruthy(); + }); + it('handles future dates', () => { + const future = new Date(Date.now() + 86400000).toISOString(); + const result = formatRelative(future); + expect(result).toBeTruthy(); + }); +}); + +describe('isToday', () => { + it('returns true for today', () => { + expect(isToday(new Date().toISOString())).toBe(true); + }); + it('returns false for yesterday', () => { + const yesterday = new Date(Date.now() - 86400000).toISOString(); + expect(isToday(yesterday)).toBe(false); + }); +}); + +describe('isYesterday', () => { + it('returns true for yesterday', () => { + const yesterday = new Date(Date.now() - 86400000).toISOString(); + expect(isYesterday(yesterday)).toBe(true); + }); + it('returns false for today', () => { + expect(isYesterday(new Date().toISOString())).toBe(false); + }); +}); + +describe('daysBetween', () => { + it('calculates days between dates', () => { + const start = '2026-05-01T00:00:00Z'; + const end = '2026-05-05T00:00:00Z'; + expect(daysBetween(start, end)).toBe(4); + }); + it('returns 0 for same date', () => { + const date = '2026-05-01T00:00:00Z'; + expect(daysBetween(date, date)).toBe(0); + }); +}); + +describe('addDays', () => { + it('adds days to date', () => { + const result = addDays('2026-05-01T00:00:00Z', 5); + expect(result.includes('2026-05-06')).toBe(true); + }); + it('subtracts days with negative', () => { + const result = addDays('2026-05-01T00:00:00Z', -5); + expect(result.includes('2026-04-26')).toBe(true); + }); +}); diff --git a/src/money.test.ts b/src/money.test.ts new file mode 100644 index 0000000..66bffe5 --- /dev/null +++ b/src/money.test.ts @@ -0,0 +1,80 @@ +import { describe, it, expect } from 'vitest'; +import { + formatMoney, + parseMoney, + toCents, + fromCents, + addMoney, + subtractMoney, + multiplyMoney, + divideMoney, +} from '../src/money'; + +describe('formatMoney', () => { + it('formats cents to dollars', () => { + expect(formatMoney(1234)).toBe('$12.34'); + }); + it('handles zero', () => { + expect(formatMoney(0)).toBe('$0.00'); + }); + it('handles negative', () => { + expect(formatMoney(-500)).toBe('-$5.00'); + }); +}); + +describe('parseMoney', () => { + it('parses dollar string to cents', () => { + expect(parseMoney('$12.34')).toBe(1234); + }); + it('parses without dollar sign', () => { + expect(parseMoney('12.34')).toBe(1234); + }); + it('handles invalid input', () => { + expect(parseMoney('abc')).toBe(0); + }); +}); + +describe('toCents', () => { + it('converts dollars to cents', () => { + expect(toCents(12.34)).toBe(1234); + }); + it('handles whole dollars', () => { + expect(toCents(100)).toBe(10000); + }); +}); + +describe('fromCents', () => { + it('converts cents to dollars', () => { + expect(fromCents(1234)).toBe(12.34); + }); + it('handles zero', () => { + expect(fromCents(0)).toBe(0); + }); +}); + +describe('addMoney', () => { + it('adds two amounts in cents', () => { + expect(addMoney(1000, 500)).toBe(1500); + }); +}); + +describe('subtractMoney', () => { + it('subtracts two amounts in cents', () => { + expect(subtractMoney(1000, 300)).toBe(700); + }); +}); + +describe('multiplyMoney', () => { + it('multiplies cents by factor', () => { + expect(multiplyMoney(1000, 3)).toBe(3000); + }); +}); + +describe('divideMoney', () => { + it('divides cents by factor', () => { + expect(divideMoney(1000, 4)).toBe(250); + }); + it('handles division by zero', () => { + expect(divideMoney(1000, 0)).toBe(0); + }); +});