Files
Pulse Agent 0889ee9117 feat(lib): add useLiveStream WS hook + useLiveMetrics + LiveMetricChart
feat(hooks): add useLiveStream generic WebSocket hook
  - supports websocket/sse/polling transports
  - exponential backoff reconnect with jitter
  - circular buffer with configurable size
  - typed filter callback per use case
  - manual disconnect + reconnect + error state

feat(hooks): add useLiveMetrics derived hook
  - sliding time-window cut
  - moving average (configurable window)
  - current / avg / min / max / ratePerSecond
  - zero allocations per tick (memoized)

feat(charts): add LiveMetricChart molecule (Recharts)
  - line + area variants, grid + tooltip
  - moving-average overlay (dashed)
  - ConnectionStatus atom in header
  - status bar + compact mode
  - 100% responsive, GPU via SVG ViewBox

feat(atoms): add ConnectionStatus indicator
  - 5 states: disconnected/connecting/connected/reconnecting/error
  - animated pulse, JetBrains Mono, pill style
  - exported helpers: formatLatency / formatBytes

docs(pkg): bump v0.1.0 → v0.2.0, add recharts peerDep
2026-05-20 22:59:10 -03:00

157 lines
4.4 KiB
TypeScript
Executable File

import { describe, it, expect } from 'vitest';
import {
emailSchema,
passwordSchema,
passwordConfirmSchema,
uuidSchema,
urlSchema,
phoneSchema,
documentoSchema,
sanitizedStr,
required,
safeParse,
} from '../src/validators';
describe('emailSchema', () => {
it('aceita email valido e normaliza para lowercase', () => {
const r = safeParse(emailSchema, 'TESTE@EXAMPLE.COM');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('teste@example.com');
});
it('rejeita email invalido', () => {
expect(safeParse(emailSchema, 'not-an-email').success).toBe(false);
});
it('aceita email com dominio internacionalizado', () => {
expect(safeParse(emailSchema, 'user@mail.co.uk').success).toBe(true);
});
});
describe('passwordSchema', () => {
it('rejeita senha menor que 8 caracteres', () => {
expect(safeParse(passwordSchema, 'Abc1234').success).toBe(false);
});
it('rejeita senha sem numero', () => {
expect(safeParse(passwordSchema, 'Abcdefgh').success).toBe(false);
});
it('rejeita senha sem letra maiuscula', () => {
expect(safeParse(passwordSchema, 'abcdefgh123').success).toBe(false);
});
it('aceita senha valida', () => {
expect(safeParse(passwordSchema, 'Minha#Senh@1234').success).toBe(true);
});
});
describe('passwordConfirmSchema', () => {
it('retorna erro quando senhas nao coincidem', () => {
const r = safeParse(
passwordConfirmSchema,
{ password: 'Abc12345', confirm: 'Zxy98765' },
);
expect(r.success).toBe(false);
});
it('aceita quando senhas coincidem', () => {
const r = safeParse(
passwordConfirmSchema,
{ password: 'Abc12345', confirm: 'Abc12345' },
);
expect(r.success).toBe(true);
});
});
describe('uuidSchema', () => {
it('aceita UUID valido', () => {
expect(
safeParse(uuidSchema, '550e8400-e29b-41d4-a716-446655440000').success,
).toBe(true);
});
it('rejeita string que nao e UUID', () => {
expect(safeParse(uuidSchema, 'nao-e-uuid').success).toBe(false);
});
});
describe('urlSchema', () => {
it('aceita URL valida', () => {
const r = safeParse(urlSchema, 'https://exemplo.com');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('https://exemplo.com');
});
it('transforma string vazia em undefined', () => {
const r = safeParse(urlSchema, '');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBeUndefined();
});
});
describe('phoneSchema', () => {
it('aceita telefone formato (11) 98765-4321', () => {
expect(safeParse(phoneSchema, '(11) 98765-4321').success).toBe(true);
});
it('aceita telefone sem parentesis nem tracos', () => {
expect(safeParse(phoneSchema, '11987654321').success).toBe(true);
});
it('rejeita telefone com poucos digitos', () => {
expect(safeParse(phoneSchema, '123').success).toBe(false);
});
});
describe('documentoSchema', () => {
it('aceita CPF com 11 digitos', () => {
const r = safeParse(documentoSchema, '123.456.789-09');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('12345678909');
});
it('aceita CNPJ com 14 digitos', () => {
const r = safeParse(documentoSchema, '12.345.678/0001-95');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('12345678000195');
});
it('rejeita documento com tamanho invalido', () => {
expect(safeParse(documentoSchema, '12345').success).toBe(false);
});
});
describe('sanitizedStr', () => {
it('remove tags HTML e mantem texto corporizado', () => {
const r = safeParse(sanitizedStr, '<b>hello</b> world');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('hello world');
});
it('rejeita string que fica vazia apos sanitizar', () => {
expect(safeParse(sanitizedStr, '<p></p>').success).toBe(false);
expect(safeParse(sanitizedStr, ' ').success).toBe(false);
});
});
describe('required wrapper', () => {
it('transforma string vazia em erro', () => {
const schema = required(emailSchema);
expect(safeParse(schema, '').success).toBe(false);
});
});
describe('safeParse', () => {
it('retorna erro formatado quando falha', () => {
const r = safeParse(passwordSchema, 'curta');
expect(r.success).toBe(false);
});
it('retorna dados quando sucesso', () => {
const r = safeParse(emailSchema, 'teste@exemplo.com');
expect(r.success).toBe(true);
if (r.success) expect(r.data).toBe('teste@exemplo.com');
});
});