/** * @vitest-environment jsdom */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { cn, str, num, arr, obj, date, storage, debounce, throttle, } from '../src/utils/index'; describe('cn()', () => { it('concatena classes válidas', () => { expect(cn('foo', 'bar')).toBe('foo bar'); }); it('filtra falsy values', () => { expect(cn('foo', false, null, undefined, 'bar')).toBe('foo bar'); }); it('flatten nested arrays', () => { expect(cn('a', ['b', 'c'])).toBe('a b c'); }); it('normaliza espaços múltiplos', () => { expect(cn('a', ' b ', 'c')).toBe('a b c'); }); }); describe('str utils', () => { it('capitalize', () => { expect(str.capitalize('pULSE')).toBe('Pulse'); expect(str.capitalize('')).toBe(''); }); it('truncate com sufixo', () => { expect(str.truncate('abcdef', 4, '…')).toBe('abcd…'); }); it('truncate retorna original se menor', () => { expect(str.truncate('ab', 10)).toBe('ab'); }); it('camelCase e kebabCase', () => { expect(str.camelCase('hello-world')).toBe('helloWorld'); expect(str.kebabCase('helloWorld')).toBe('hello-world'); }); it('removeAccents', () => { expect(str.removeAccents('coração')).toBe('coracao'); }); it('maskEmail', () => { expect(str.maskEmail('john.doe@example.com')).toBe('j******e@example.com'); expect(str.maskEmail('ab@x.com')).toBe('a*@x.com'); }); it('slugify', () => { expect(str.slugify('São Paulo → Cidade!')).toBe('s-o-paulo-cidade'); expect(str.slugify('Hello World')).toBe('hello-world'); }); }); describe('num utils', () => { it('clamp — limita intervalo', () => { expect(num.clamp(15, 0, 10)).toBe(10); expect(num.clamp(-5, 0, 10)).toBe(0); expect(num.clamp(5, 0, 10)).toBe(5); }); it('rand — gera dentro do intervalo', () => { for (let i = 0; i < 10; i++) { const v = num.rand(1, 10); expect(v).toBeGreaterThanOrEqual(1); expect(v).toBeLessThanOrEqual(10); expect(Number.isInteger(v)).toBe(true); } }); it('format — locale BR', () => { expect(num.format(1000)).toContain('1'); }); it('percent', () => { expect(num.percent(5, 0)).toBe(0); expect(num.percent(50, 100, 0)).toBe(50); expect(num.percent(1, 3, 0)).toBe(33); }); }); describe('arr utils', () => { it('unique', () => { expect(arr.unique([1, 2, 2, 3])).toEqual([1, 2, 3]); }); it('unique com key', () => { const objs = [{ id: 1 }, { id: 2 }, { id: 1 }]; expect(arr.unique(objs, 'id')).toHaveLength(2); }); it('chunk', () => { expect(arr.chunk([1, 2, 3, 4, 5], 2)).toEqual([[1, 2], [3, 4], [5]]); expect(arr.chunk([1, 2, 3, 4], 2)).toEqual([[1, 2], [3, 4]]); }); it('shuffle mantém elementos', () => { const original = [1, 2, 3, 4, 5]; const shuffled = arr.shuffle(original); expect(shuffled.length).toBe(original.length); expect(shuffled.sort()).toEqual(original.sort()); }); }); describe('obj utils', () => { it('pick', () => { expect(obj.pick({ a: 1, b: 2, c: 3 }, ['a'])).toEqual({ a: 1 }); }); it('omit', () => { expect(obj.omit({ a: 1, b: 2 }, ['b'])).toEqual({ a: 1 }); }); it('isEmpty', () => { expect(obj.isEmpty({})).toBe(true); expect(obj.isEmpty({ a: 1 })).toBe(false); expect(obj.isEmpty(null)).toBe(true); expect(obj.isEmpty(undefined)).toBe(true); }); }); describe('date utils', () => { it('format', () => { const d = new Date('2024-01-15T10:30:00'); expect(date.format(d, 'YYYY-MM-DD')).toBe('2024-01-15'); expect(date.format(d, 'HH:mm')).toBe('10:30'); }); it('now retorna string ISO', () => { const result = date.now(); expect(typeof result).toBe('string'); expect(new Date(result).toISOString()).toBe(result); }); it('isToday', () => { expect(date.isToday(new Date())).toBe(true); expect(date.isToday(new Date('2000-01-01'))).toBe(false); }); it('daysBetween', () => { const a = new Date('2024-01-01'); const b = new Date('2024-01-10'); expect(date.daysBetween(a, b)).toBe(9); expect(date.daysBetween(b, a)).toBe(-9); }); }); describe('storage', () => { beforeEach(() => { localStorage.clear(); }); it('get retorna fallback quando vazio', () => { expect(storage.get('key', 'default')).toBe('default'); }); it('set e get', () => { storage.set('key', { a: 1 }); expect(storage.get('key', null)).toEqual({ a: 1 }); }); it('remove', () => { storage.set('key1', 1); storage.remove('key1'); expect(storage.get('key1', 'x')).toBe('x'); }); it('clear', () => { storage.set('a', 1); storage.set('b', 2); storage.clear(); expect(storage.get('a', null)).toBe(null); }); it('clear com prefixo', () => { storage.set('app_a', 1); storage.set('app_b', 2); storage.set('other', 3); storage.clear('app_'); expect(storage.get('app_a', null)).toBe(null); expect(storage.get('other', null)).toBe(3); }); }); describe('debounce', () => { it('atrasa execuçao — chama apenas ultima chamada', async () => { const fn = vi.fn(); const debounced = debounce(fn, 50); debounced('a'); debounced('b'); expect(fn).not.toHaveBeenCalled(); await new Promise(r => setTimeout(r, 100)); expect(fn).toHaveBeenCalledTimes(1); expect(fn).toHaveBeenCalledWith('b'); }); }); describe('throttle', () => { it('executa imediatamente na primeira chamada', () => { const fn = vi.fn(); const throttled = throttle(fn, 50); throttled('a'); expect(fn).toHaveBeenCalledWith('a'); expect(fn).toHaveBeenCalledTimes(1); }); });